<commit_before>const express = require( 'express' );
const twitter = require( 'node-tweet-stream' );
const { exec } = require( 'child_process' );
const st = require( 'st' );
let fs = require( 'fs' );
let app = express();
const helmet = require( 'helmet' );
const bodyParser = require( 'body-parser' );
const compression = require( 'compression' );
const morgan = require( 'morgan' );
const moment = require( 'moment' );
const port = process.env.PORT || 80;
let io = null;
let lastTweet = new Date().getTime();

let server = require( 'http' ).createServer( app );
server.listen( port );
if ( process.env.sslEnabled === "true" ) {
	const options = {
		cert: fs.readFileSync( __dirname + '/sslcert/fullchain.pem' ),
		key: fs.readFileSync( __dirname + '/sslcert/privkey.pem' )
	};
	let sslServer = require( 'https' ).createServer( options, app );
	sslServer.listen( 443 );
	io = require( 'socket.io' ).listen( sslServer );
} else {
	io = require( 'socket.io' ).listen( server );
}

let twitterOptions = {
	consumer_key: process.env.consumer_key,
	consumer_secret: process.env.consumer_secret,
	token: process.env.access_token_key,
	token_secret: process.env.access_token_secret
};

let twitterBackupOptions = {
	consumer_key: process.env.backup_consumer_key || "",
	consumer_secret: process.env.backup_consumer_secret || "",
	token: process.env.backup_access_token_key || "",
	token_secret: process.env.backup_access_token_secret || ""
};
let usingTwitterBackup = false;
let twitterClient = null;

function TimedLogger( area, type, data ) {
	let csvString = moment().format( 'MM/DD/YYYY,HH:mm:ss' ) + "," + area + "," + type + "," + data;
	console.log( csvString );
}

let raidConfigs = require( './raids.json' );

app.set( 'json spaces', 0 );
app.use( helmet() );
app.use( morgan( 'combined' ) );
app.use( compression() );
app.use( bodyParser.json() );
app.use( bodyParser.urlencoded( {
	extended: true
} ) );

app.get( '/health-check', ( req, res ) => res.sendStatus( 200 ) );

app.get( '/getraids', function ( req, res ) {
	res.header( 'Cache-Control', 'public, max-age=432000000' );
	res.header( 'Access-Control-Allow-Origin', '*' );
	res.send( raidConfigs );
} );

app.get( '/serviceWorker.js', function ( req, res ) {
	res.header( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' );
	res.sendFile( __dirname + '/static/serviceWorker.js' );
} );

app.get( '/', function ( req, res ) {
	res.sendFile( __dirname + '/static/index.html' );
} );

app.use( st( {
	path: __dirname + '/static',
	url: '/',
	index: '/index.html',
	gzip: true,
	dot: true,
	cors: true,
	cache: {
		content: {
			max: 1024 * 1024 * 64, // how much memory to use on caching contents (bytes * kilo * mega)
			maxAge: 1000 * 60 * 60 * 24 * 7, // how long to cache contents for (milliseconds * seconds * minutes * hours * days)
		}
	},
	passthrough: true
} ) );

let keywords = "";

for ( let i = 0; i < raidConfigs.length; i++ ) {
	keywords += raidConfigs[ i ].english + "," + raidConfigs[ i ].japanese;
	if ( i != raidConfigs.length - 1 ) {
		keywords += ',';
	}
}

function searchTextForRaids( text ) {
	let result = null;
	for ( let i = 0; i < raidConfigs.length; i++ ) {
		if ( text.indexOf( raidConfigs[ i ].english ) != -1 || text.indexOf( raidConfigs[ i ].japanese ) != -1 ) {
			result = raidConfigs[ i ].room;
			break;
		}
	}
	return result;
}

function DoesTweetContainMessage( data ) {
	let result = false;
	if ( data.text.indexOf( "参加者募集" ) != -1 || data.text.indexOf( "I need backup" ) != -1 ) {
		result = true;
	}
	return result;
}

function GetTweetLanguage( data ) {
	if ( data.text.indexOf( '参戦ID' ) !== -1 ) {
		return "JP";
	} else if ( data.text.indexOf( 'Battle ID' ) !== -1 ) {
		return "EN";
	} else {
		return null;
	}
}

function GetTweetMessage( data ) {
	let result = {
		language: "JP",
		message: "No Twitter Message."
	};
	let splitString = data.text.split( '\n' );
	let tempMessage = splitString[ 1 ];
	if ( data.text.indexOf( ":" ) > 9 ) {
		result.message = data.text.substr( 0, data.text.indexOf( ":" ) - 10 );
	}
	if ( GetTweetLanguage( data ) === "JP" ) {
		result.language = "JP";
	} else if ( GetTweetLanguage( data ) === "EN" ) {
		result.language = "EN";
	}
	return result;
}

function GetRaidID( data ) {
	var result = null;
	try {
		result = data.text.substr( data.text.indexOf( ":" ) - 9, 8 );
	} catch ( error ) {
		TimedLogger( "Twitter", "Error", error );
	}
	return result;
}

function IsValidTweet( data ) {
	let result = false;
	if ( data.source !== 'グランブルー ファンタジー' ) {
		TimedLogger( "Twitter", "Invalid Tweet Source", data.source );
	} else {
		if ( searchTextForRaids( data.text ) === null ) {
			TimedLogger( "Twitter", "No Raid Name", data.text );
		} else {
			if ( DoesTweetContainMessage( data ) && searchTextForRaids( GetTweetMessage( data ).message ) !== null ) {
				TimedLogger( "Twitter", "Message Contains Name", data.text );
			} else {
				if ( GetRaidID( data ) === null ) {
					TimedLogger( "Twitter", "No Raid ID", data.text );
				} else {
					TimedLogger( "Twitter", "Valid Tweet", "" );
					result = true;
				}
			}
		}
	}
	return result;
}

function StartTwitterStream( options ) {
	TimedLogger( "System", "Starting Twitter Stream", "" );
	try {
		twitterClient = new twitter( options );

		client.on( 'tweet', function ( tweet ) {
			TimedLogger( "Twitter", "Tweet Found", "" );
			if ( IsValidTweet( tweet ) ) {
				let raidInfo = {
					id: GetRaidID( tweet ),
					user: "@" + tweet.user.screen_name,
					time: tweet.created_at,
					room: searchTextForRaids( tweet.text ),
					message: "No Twitter Message.",
					language: "JP",
					status: "unclicked",
					timer: 0
				};
				if ( DoesTweetContainMessage( tweet ) ) {
					let tweetMessage = GetTweetMessage( tweet );
					raidInfo.message = tweetMessage.message;
					raidInfo.language = tweetMessage.language;
				} else if ( GetTweetLanguage( tweet ) !== null ) {
					raidInfo.language = GetTweetLanguage( tweet );
				}
				TimedLogger( "Twitter", "Raid Info", JSON.stringify( raidInfo ) );
				lastTweet = new Date().getTime();
				io.to( raidInfo.room ).emit( 'tweet', raidInfo );
			}
		} );

		client.on( 'error', function ( error ) {
			TimedLogger( "Twitter", "Error", JSON.stringify( error ) );
			twitterClient.abort();
		} );

		client.on( 'reconnect', function ( reconnect ) {
			TimedLogger( "Twitter", "Reconnect", JSON.stringify( reconnect ) );
			twitterClient.reconnect();
		} );

		client.track( keywords );
	} catch ( error ) {
		TimedLogger( "Twitter", "Error", JSON.stringify( error ) );
		twitterClient.abort();
	}
}

setInterval( function () {
	if ( new Date().getTime() - 600000 > lastTweet ) {
		TimedLogger( "Twitter", "No Tweet Warning", "Sending Email..." );
		io.emit( 'warning', { type: "twitter" } );
		try {
			exec( 'echo "There hasn\'t been a tweet in 10 minutes! You should check up on things." | mail -s "Tweet Warning!" gene@pinskiy.us' );
			lastTweet = new Date().getTime();
			setTimeout( function () {
				TimedLogger( "Twitter", "No Tweet Warning", "Restarting Twitter Client..." );
				twitterClient.abort();
				if ( !usingTwitterBackup ) {
					if ( twitterBackupOptions.consumer_key != "" ) {
						StartTwitterStream( twitterBackupOptions );
					}
				} else {
					StartTwitterStream( twitterOptions );
				}
				usingTwitterBackup = !usingTwitterBackup;
			}, 500 );
		} catch ( error ) {
			TimedLogger( "Twitter", "No Tweet Error", JSON.stringify( error ) );
		}
	}
}, 60000 )

io.sockets.on( 'connection', function ( socket ) {
	TimedLogger( "Socket", "New Connection", "" );
	socket.on( 'subscribe',
		function ( data ) {
			TimedLogger( "Socket", "Room Subscribed", data.room );
			socket.join( data.room );
		} );
	socket.on( 'raid-over',
		function ( data ) {
			io.to( data.room ).emit( 'raid-over', data );
		} );
	socket.on( 'unsubscribe',
		function ( data ) {
			TimedLogger( "Socket", "Room Unsubscribed", data.room );
			socket.leave( data.room );
		} );
} );

TimedLogger( "System", "Starting GBF Raiders", "Port " + port );
StartTwitterStream( twitterOptions );
<commit_msg>Added error array + page<commit_after>const express = require( 'express' );
const twitter = require( 'node-tweet-stream' );
const { exec } = require( 'child_process' );
const st = require( 'st' );
let fs = require( 'fs' );
let app = express();
const helmet = require( 'helmet' );
const bodyParser = require( 'body-parser' );
const compression = require( 'compression' );
const morgan = require( 'morgan' );
const moment = require( 'moment' );
const port = process.env.PORT || 80;
let io = null;
let lastTweet = new Date().getTime();

let server = require( 'http' ).createServer( app );
server.listen( port );
if ( process.env.sslEnabled === "true" ) {
	const options = {
		cert: fs.readFileSync( __dirname + '/sslcert/fullchain.pem' ),
		key: fs.readFileSync( __dirname + '/sslcert/privkey.pem' )
	};
	let sslServer = require( 'https' ).createServer( options, app );
	sslServer.listen( 443 );
	io = require( 'socket.io' ).listen( sslServer );
} else {
	io = require( 'socket.io' ).listen( server );
}

let twitterOptions = {
	consumer_key: process.env.consumer_key,
	consumer_secret: process.env.consumer_secret,
	token: process.env.access_token_key,
	token_secret: process.env.access_token_secret
};

let twitterBackupOptions = {
	consumer_key: process.env.backup_consumer_key || "",
	consumer_secret: process.env.backup_consumer_secret || "",
	token: process.env.backup_access_token_key || "",
	token_secret: process.env.backup_access_token_secret || ""
};
let usingTwitterBackup = false;
let twitterClient = null;
let errors = [];

function TimedLogger( area, type, data ) {
	let csvString = moment().format( 'MM/DD/YYYY,HH:mm:ss' ) + "," + area + "," + type + "," + data;
	console.log( csvString );
	return csvString;
}

let raidConfigs = require( './raids.json' );

app.set( 'json spaces', 0 );
app.use( helmet() );
app.use( morgan( 'combined' ) );
app.use( compression() );
app.use( bodyParser.json() );
app.use( bodyParser.urlencoded( {
	extended: true
} ) );

app.get( '/health-check', ( req, res ) => res.sendStatus( 200 ) );

app.get( '/getraids', function ( req, res ) {
	res.header( 'Cache-Control', 'public, max-age=432000000' );
	res.header( 'Access-Control-Allow-Origin', '*' );
	res.send( raidConfigs );
} );

app.get( '/serviceWorker.js', function ( req, res ) {
	res.header( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' );
	res.sendFile( __dirname + '/static/serviceWorker.js' );
} );

app.get( '/errors', function ( req, res ) {
	res.header( 'Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate' );
	res.send( errors );
} );

app.get( '/', function ( req, res ) {
	res.sendFile( __dirname + '/static/index.html' );
} );

app.use( st( {
	path: __dirname + '/static',
	url: '/',
	index: '/index.html',
	gzip: true,
	dot: true,
	cors: true,
	cache: {
		content: {
			max: 1024 * 1024 * 64, // how much memory to use on caching contents (bytes * kilo * mega)
			maxAge: 1000 * 60 * 60 * 24 * 7, // how long to cache contents for (milliseconds * seconds * minutes * hours * days)
		}
	},
	passthrough: true
} ) );

let keywords = "";

for ( let i = 0; i < raidConfigs.length; i++ ) {
	keywords += raidConfigs[ i ].english + "," + raidConfigs[ i ].japanese;
	if ( i != raidConfigs.length - 1 ) {
		keywords += ',';
	}
}

function searchTextForRaids( text ) {
	let result = null;
	for ( let i = 0; i < raidConfigs.length; i++ ) {
		if ( text.indexOf( raidConfigs[ i ].english ) != -1 || text.indexOf( raidConfigs[ i ].japanese ) != -1 ) {
			result = raidConfigs[ i ].room;
			break;
		}
	}
	return result;
}

function DoesTweetContainMessage( data ) {
	let result = false;
	if ( data.text.indexOf( "参加者募集" ) != -1 || data.text.indexOf( "I need backup" ) != -1 ) {
		result = true;
	}
	return result;
}

function GetTweetLanguage( data ) {
	if ( data.text.indexOf( '参戦ID' ) !== -1 ) {
		return "JP";
	} else if ( data.text.indexOf( 'Battle ID' ) !== -1 ) {
		return "EN";
	} else {
		return null;
	}
}

function GetTweetMessage( data ) {
	let result = {
		language: "JP",
		message: "No Twitter Message."
	};
	let splitString = data.text.split( '\n' );
	let tempMessage = splitString[ 1 ];
	if ( data.text.indexOf( ":" ) > 9 ) {
		result.message = data.text.substr( 0, data.text.indexOf( ":" ) - 10 );
	}
	if ( GetTweetLanguage( data ) === "JP" ) {
		result.language = "JP";
	} else if ( GetTweetLanguage( data ) === "EN" ) {
		result.language = "EN";
	}
	return result;
}

function GetRaidID( data ) {
	var result = null;
	try {
		result = data.text.substr( data.text.indexOf( ":" ) - 9, 8 );
	} catch ( error ) {
		TimedLogger( "Twitter", "Error", error );
	}
	return result;
}

function IsValidTweet( data ) {
	let result = false;
	if ( data.source !== 'グランブルー ファンタジー' ) {
		TimedLogger( "Twitter", "Invalid Tweet Source", data.source );
	} else {
		if ( searchTextForRaids( data.text ) === null ) {
			TimedLogger( "Twitter", "No Raid Name", data.text );
		} else {
			if ( DoesTweetContainMessage( data ) && searchTextForRaids( GetTweetMessage( data ).message ) !== null ) {
				TimedLogger( "Twitter", "Message Contains Name", data.text );
			} else {
				if ( GetRaidID( data ) === null ) {
					TimedLogger( "Twitter", "No Raid ID", data.text );
				} else {
					TimedLogger( "Twitter", "Valid Tweet", "" );
					result = true;
				}
			}
		}
	}
	return result;
}

function StartTwitterStream( options ) {
	TimedLogger( "System", "Starting Twitter Stream", "" );
	try {
		twitterClient = new twitter( options );

		client.on( 'tweet', function ( tweet ) {
			TimedLogger( "Twitter", "Tweet Found", "" );
			if ( IsValidTweet( tweet ) ) {
				let raidInfo = {
					id: GetRaidID( tweet ),
					user: "@" + tweet.user.screen_name,
					time: tweet.created_at,
					room: searchTextForRaids( tweet.text ),
					message: "No Twitter Message.",
					language: "JP",
					status: "unclicked",
					timer: 0
				};
				if ( DoesTweetContainMessage( tweet ) ) {
					let tweetMessage = GetTweetMessage( tweet );
					raidInfo.message = tweetMessage.message;
					raidInfo.language = tweetMessage.language;
				} else if ( GetTweetLanguage( tweet ) !== null ) {
					raidInfo.language = GetTweetLanguage( tweet );
				}
				TimedLogger( "Twitter", "Raid Info", JSON.stringify( raidInfo ) );
				lastTweet = new Date().getTime();
				io.to( raidInfo.room ).emit( 'tweet', raidInfo );
			}
		} );

		client.on( 'error', function ( error ) {
			errors.push( TimedLogger( "Twitter", "Error", JSON.stringify( error ) ) );
			twitterClient.abort();
		} );

		client.on( 'reconnect', function ( reconnect ) {
			errors.push( TimedLogger( "Twitter", "Reconnect", JSON.stringify( reconnect ) ) );
			twitterClient.reconnect();
		} );

		client.track( keywords );
	} catch ( error ) {
		errors.push( TimedLogger( "Twitter", "Error", JSON.stringify( error ) ) );
		twitterClient.abort();
	}
}

setInterval( function () {
	if ( new Date().getTime() - 600000 > lastTweet ) {
		errors.push( TimedLogger( "Twitter", "No Tweet Warning", "Sending Email..." ) );
		io.emit( 'warning', { type: "twitter" } );
		try {
			exec( 'echo "There hasn\'t been a tweet in 10 minutes! You should check up on things." | mail -s "Tweet Warning!" gene@pinskiy.us' );
			lastTweet = new Date().getTime();
			setTimeout( function () {
				TimedLogger( "Twitter", "No Tweet Warning", "Restarting Twitter Client..." );
				twitterClient.abort();
				if ( !usingTwitterBackup ) {
					if ( twitterBackupOptions.consumer_key != "" ) {
						StartTwitterStream( twitterBackupOptions );
					}
				} else {
					StartTwitterStream( twitterOptions );
				}
				usingTwitterBackup = !usingTwitterBackup;
			}, 500 );
		} catch ( error ) {
			errors.push( TimedLogger( "Twitter", "No Tweet Error", JSON.stringify( error ) ) );
		}
	}
}, 60000 )

io.sockets.on( 'connection', function ( socket ) {
	TimedLogger( "Socket", "New Connection", "" );
	socket.on( 'subscribe',
		function ( data ) {
			TimedLogger( "Socket", "Room Subscribed", data.room );
			socket.join( data.room );
		} );
	socket.on( 'raid-over',
		function ( data ) {
			io.to( data.room ).emit( 'raid-over', data );
		} );
	socket.on( 'unsubscribe',
		function ( data ) {
			TimedLogger( "Socket", "Room Unsubscribed", data.room );
			socket.leave( data.room );
		} );
} );

TimedLogger( "System", "Starting GBF Raiders", "Port " + port );
StartTwitterStream( twitterOptions );
<|endoftext|>


<commit_before>var Istanbul = require('istanbul');
var through = require('through2');
var minimatch = require("minimatch");
var _ = require('lodash');

function instrument(options) {
  var excludePattern = options.exclude ? [].concat(options.exclude) : [''];
  var instrumenter = new Istanbul.Instrumenter();

  function transform(file) {
    // If if doesnt match the pattern dont instrument it
    var matchResult = _.compact(_.map(excludePattern, function (pattern) {
      return minimatch(file, pattern);
    }));

    if (matchResult.length)
      return through();

    var data = '';
    return through(function(buf, enc, next) {
      data += buf;
      next();
    }, function(next) {
      var self = this;
      instrumenter.instrument(data, file, function(err, code) {
        if (!err) {
          // Inject __converage__ var
          self.push(code);
          self.push('after(function(){console.log("__coverage__=\'" + JSON.stringify(__coverage__) + "\';");});');
        } else {
          self.emit('error', err);
        }
        next();
      });
    });
  }

  return transform;
}

function writeReports(options) {
  var collector = new Istanbul.Collector();
  var report = options.report || [];
  delete(options.report);

  var data = '';
  return through(function(buf, enc, next) {
    data += buf;
    next();
  }, function(next) {
    var re = /__coverage__='([^;]*)';\n/gi,
        match = re.exec(data),
        coverage;

    // Clean up the stream
    this.push(data.replace(re,''));

    // match[1] contains JSON.stringify(__coverage__)
    coverage = match ? JSON.parse(match[1]) || {} : {};

    collector.add(coverage);

    // Add report
    [].concat(report).forEach(function (reportType) {
      Istanbul.Report
        .create(reportType, _.clone(options))
        .writeReport(collector, true);
    });

    next();
  });
}

module.exports = function (b, opts) {
  var reporterOptions = _.omit(opts, 'exclude');

  b.transform(instrument(opts));
  b.pipeline.get('wrap').push(writeReports(reporterOptions));
};
<commit_msg>Apply reporter on any reset. Retain reports array<commit_after>var Istanbul = require('istanbul');
var through = require('through2');
var minimatch = require("minimatch");
var _ = require('lodash');

function instrument(options) {
  var excludePattern = options.exclude ? [].concat(options.exclude) : [''];
  var instrumenter = new Istanbul.Instrumenter();

  function transform(file) {
    // If if doesnt match the pattern dont instrument it
    var matchResult = _.compact(_.map(excludePattern, function (pattern) {
      return minimatch(file, pattern);
    }));

    if (matchResult.length)
      return through();

    var data = '';
    return through(function(buf, enc, next) {
      data += buf;
      next();
    }, function(next) {
      var self = this;
      instrumenter.instrument(data, file, function(err, code) {
        if (!err) {
          // Inject __converage__ var
          self.push(code);
          self.push('after(function(){console.log("__coverage__=\'" + JSON.stringify(__coverage__) + "\';");});');
        } else {
          self.emit('error', err);
        }
        next();
      });
    });
  }

  return transform;
}

var report = [];

function writeReports(options) {
  var collector = new Istanbul.Collector();

  if (options.report) {
    report = options.report;
    delete(options.report);
  }

  var data = '';
  return through(function(buf, enc, next) {
    data += buf;
    next();
  }, function(next) {
    var re = /__coverage__='([^;]*)';\n/gi,
        match = re.exec(data),
        coverage;

    // Clean up the stream
    this.push(data.replace(re,''));

    // match[1] contains JSON.stringify(__coverage__)
    coverage = match ? JSON.parse(match[1]) || {} : {};

    collector.add(coverage);

    // Add report
    [].concat(report).forEach(function (reportType) {
      Istanbul.Report
        .create(reportType, _.clone(options))
        .writeReport(collector, true);
    });

    next();
  });
}

module.exports = function (b, opts) {
  var reporterOptions = _.omit(opts, 'exclude');

  function apply() {
    b.pipeline.get('wrap').push(writeReports(reporterOptions));
  }

  b.transform(instrument(opts));
  apply();
  b.on('reset', apply);
};
<|endoftext|>


<commit_before>'use strict';

var levelup = require('levelup');
var leveldown = require('leveldown');
var request = require('request');

var KEY = 'meatspace:';

var openDb = function (callback) {
  if (!self.db || self.db.isClosed()) {
    levelup(self.dbPath, {
      createIfMissing: true,
      keyEncoding: 'binary',
      valueEncoding: 'json'
    }, function (err, lp) {
      if (lp) {
        self.db = lp;
        callback();
      } else {
        openDb(callback);
      }
    });
  } else {
    callback();
  }
};

var Meatspace = function (options) {
  if (!options.fullName || !options.postUrl || !options.username) {
    throw new Error('fullName, username, db and postUrl are mandatory');
  }

  var self = this;

  this.fullName = options.fullName;
  this.username = options.username;
  this.postUrl = options.postUrl;
  this.dbPath = options.db;
  this.limit = options.limit - 1 || 10;
  this.keyId = '';

  var openDb = function (callback) {
    if (!self.db || self.db.isClosed()) {
      levelup(self.dbPath, {
        createIfMissing: true,
        keyEncoding: 'binary',
        valueEncoding: 'json'
      }, function (err, lp) {
        if (lp) {
          self.db = lp;
          callback();
        } else {
          openDb(callback);
        }
      });
    } else {
      callback();
    }
  };

  var addToArray = function (i, callback) {
    self.get(self.ids[i], function (err, m) {
      if (err) {
        callback(err);
      } else {
        self.messageArray.push(m);
      }

      if (self.messageArray.length === self.ids.length) {
        callback(null, self.messageArray);
      }
    });
  };

  var setAll = function (opts, message, id, callback) {
    self.db.get(KEY + 'all:ids' + self.keyId, function (err, ids) {
      if (err) {
        // Not created, so create a new array
        ids = [id];
      } else {
        if (ids.indexOf(id) === -1) {
          ids.unshift(id);
        }
      }

      opts.push({
        type: 'put',
        key: KEY + 'all:ids' + self.keyId,
        value: ids
      });

      opts.push({
        type: 'put',
        key: KEY + id,
        value: message
      });

      self.db.batch(opts, function (err) {
        if (err) {
          callback(err);
        } else {
          callback(null, message);
        }
      });
    });
  };

  var setPublic = function (opts, message, id, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (err) {
        publicIds = [];
      }

      if (!message.meta.isPrivate && publicIds.indexOf(id) === -1) {
        publicIds.unshift(id);

        opts.push({
          type: 'put',
          key: KEY + 'public:ids' + self.keyId,
          value: publicIds
        });
      }

      setAll(opts, message, id, callback);
    });
  };

  var setPrivate = function (opts, message, id, callback) {
    self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
      if (err) {
        privIds = [];
      }

      if (message.meta.isPrivate && privIds.indexOf(id) === -1) {
        privIds.unshift(id);

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });
      }

      setPublic(opts, message, id, callback);
    });
  };

  this.create = function (message, callback) {
    if (!message || !this.fullName || !this.postUrl) {
      callback(new Error('Message invalid'));
    } else {
      var opts = [];

      openDb(function () {
        self.db.get(KEY + 'ids', function (err, id) {
          if (err) {
            id = 1;
          } else {
            id ++;
          }

          opts.push({
            type: 'put',
            key: KEY + 'ids',
            value: id
          });

          message.id = id;
          message.fullName = self.fullName;
          message.username = self.username;
          if (!message.postUrl) {
            message.postUrl = self.postUrl;
          }
          message.content.created = message.content.updated = Math.round(new Date() / 1000);

          setPrivate(opts, message, id, callback);
        });
      });
    }
  };

  this.get = function (id, callback) {
    openDb(function () {
      self.db.get(KEY + id, function (err, message) {
        if (err || !message) {
          callback(new Error('Not found ', err));
        } else {
          if (typeof message === 'object') {
            callback(null, message);
          } else {
            callback(new Error('Invalid JSON'));
          }
        }
      });
    });
  };

  this.share = function (message, url, callback) {
    if (message.shares.indexOf(this.postUrl) < 0) {
      message.meta.isShared = true;
      message.postUrl = url;
      message.shares.push(url);

      self.create(message, callback);
    } else {
      callback(new Error('Already shared'));
    }
  };

  this.subscribe = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          subs = {};
        }

        url = url.toLowerCase().trim();
        subs[url] = true;

        self.db.put(KEY + 'subscriptions' + self.keyId, subs, function (err) {
          if (err) {
            callback(err);
          } else {
            callback(null, url);
          }
        });
      });
    });
  };

  var loadSubscriptions = function (subs, callback) {
    var subscriptions = [];
    var subsLength = Object.keys(subs).length;

    if (subsLength > 0) {
      for (var s in subs) {
        subscriptions.push(s);

        if (subscriptions.length === subsLength) {
          callback(null, subscriptions);
        }
      }
    } else {
      callback(null, subscriptions);
    }
  };

  this.unsubscribe = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          subs = {};
        }

        delete subs[url.toLowerCase().trim()];

        self.db.put(KEY + 'subscriptions' + self.keyId, subs, function (err) {
          if (err) {
            callback(err);
          } else {
            loadSubscriptions(subs, callback);
          }
        });
      });
    });
  };

  this.getSubscriptions = function (callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          callback(null, []);
        } else {
          loadSubscriptions(subs, callback);
        }
      });
    });
  };

  this.getSubscriptionRecent = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        url = url.toLowerCase().trim();

        if (err || !subs[url]) {
          callback(new Error('Subscription messages not found or you did not subscribe to this url'));
        } else {
          request(url, function (err, resp, body) {
            if (err) {
              callback(err);
            } else {
              if (typeof body !== 'object') {
                try {
                  body = JSON.parse(body);
                } catch (e) {
                  return callback(new Error('Could not parse JSON'));
                }
              }

              var recentArr = [];

              for (var i = 0; i < body.posts.length; i ++) {
                recentArr.push(body.posts[i]);

                if (recentArr.length === body.posts.length) {
                  callback(null, recentArr);
                }
              }
            }
          });
        }
      });
    });
  };

  var loadAll = function (ids, callback) {
    self.messageArray = [];
    self.ids = ids;

    if (self.ids.length > 0) {
      for (var i = 0; i < self.ids.length; i ++) {
        addToArray(i, callback);
      }
    } else {
      callback(null, self.messageArray);
    }
  };

  var resetPublic = function (opts, message, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (!publicIds) {
        publicIds = [];
      }

      if (message.meta.isPrivate) {
        publicIds.splice(publicIds.indexOf(message.id), 1);
      } else if (publicIds.indexOf(message.id) === -1) {
        publicIds.unshift(message.id);
      }

      opts.push({
        type: 'put',
        key: KEY + 'public:ids' + self.keyId,
        value: publicIds
      });

      self.db.get(KEY + message.id, function (err, msg) {
        if (err) {
          callback(err);
        } else {
          message.content.updated = Math.round(new Date() / 1000);

          opts.push({
            type: 'put',
            key: KEY + message.id,
            value: message
          });

          self.db.batch(opts, function (err) {
            if (err) {
              callback(err);
            } else {
              callback(null, message);
            }
          });
        }
      });
    });
  };

  this.update = function (message, callback) {
    openDb(function () {
      self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
        var opts = [];

        if (!privIds) {
          privIds = [];
        }

        if (message.meta.isPrivate) {
          privIds.unshift(message.id);
        } else if (privIds.indexOf(message.id) === -1) {
          privIds.splice(privIds.indexOf(message.id), 1);
        }

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });

        resetPublic(opts, message, callback);
      });
    });
  };

  var delPublic = function (opts, id, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (err) {
        callback(err);
      } else {
        publicIds.splice(publicIds.indexOf(id), 1);

        opts.push({
          type: 'put',
          key: KEY + 'public:ids' + self.keyId,
          value: publicIds
        });

        self.ids.splice(self.ids.indexOf(id), 1);

        self.db.batch(opts, function (err) {
          if (err) {
            callback(err);
          } else {
            callback(null, true);
          }
        });
      }
    });
  };

  var delPrivate = function (opts, id, callback) {
    self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
      if (err) {
        callback(err);
      } else {
        privIds.splice(privIds.indexOf(id), 1);

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });

        delPublic(opts, id, callback);
      }
    });
  };

  this.del = function (id, callback) {
    openDb(function () {
      id = parseInt(id, 10);
      var opts = [];

      opts.push({
        type: 'del',
        key: KEY + id
      });

      self.db.get(KEY + 'all:ids' + self.keyId, function (err, ids) {
        if (err) {
          callback(err);
        } else {
          ids.splice(ids.indexOf(id), 1);

          opts.push({
            type: 'put',
            key: KEY + 'all:ids' + self.keyId,
            value: ids
          });

          delPrivate(opts, id, callback);
        }
      });
    });
  };

  this.getAll = function (start, callback) {
    openDb(function () {
      start = parseInt(start, 10);

      if (isNaN(start)) {
        start = 0;
      }

      self.db.get(KEY + 'all:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          self.totalAll = cids.length;
          loadAll(cids.slice(start, self.limit + start + 1), callback);
        }
      });
    });
  };

  this.getAllIds = function (callback) {
    openDb(function () {
      self.db.get(KEY + 'all:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          callback(null, cids);
        }
      });
    });
  };

  this.shareRecent = function (start, callback) {
    openDb(function () {
      start = parseInt(start, 10);

      if (isNaN(parseInt(start, 10))) {
        start = 0;
      }

      self.db.get(KEY + 'public:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          self.totalPublic = cids.length;
          loadAll(cids.slice(start, self.limit + start + 1), callback);
        }
      });
    });
  };

  this.shareOne = function (id, callback) {
    openDb(function () {
      self.get(id, function (err, message) {
        if (err) {
          callback(err);
        } else {
          if (message.meta.isPrivate) {
            callback(new Error('This is private'));
          } else {
            callback(null, message);
          }
        }
      });
    });
  };

  this.flush = function (dbPath) {
    leveldown.destroy(dbPath || self.dbPath, function (err) {
      console.log('Deleted database');
    });
  };
};

module.exports = Meatspace;
<commit_msg>fixed error callback; removed unused function<commit_after>'use strict';

var levelup = require('levelup');
var leveldown = require('leveldown');
var request = require('request');

var KEY = 'meatspace:';

var Meatspace = function (options) {
  if (!options.fullName || !options.postUrl || !options.username) {
    throw new Error('fullName, username, db and postUrl are mandatory');
  }

  var self = this;

  this.fullName = options.fullName;
  this.username = options.username;
  this.postUrl = options.postUrl;
  this.dbPath = options.db;
  this.limit = options.limit - 1 || 10;
  this.keyId = '';

  var openDb = function (callback) {
    if (!self.db || self.db.isClosed()) {
      levelup(self.dbPath, {
        createIfMissing: true,
        keyEncoding: 'binary',
        valueEncoding: 'json'
      }, function (err, lp) {
        if (err) {
          throw new Error('Could not open database: ', err);
        } else {
          self.db = lp;
          callback();
        }
      });
    } else {
      callback();
    }
  };

  var addToArray = function (i, callback) {
    self.get(self.ids[i], function (err, m) {
      if (err) {
        callback(err);
      } else {
        self.messageArray.push(m);
      }

      if (self.messageArray.length === self.ids.length) {
        callback(null, self.messageArray);
      }
    });
  };

  var setAll = function (opts, message, id, callback) {
    self.db.get(KEY + 'all:ids' + self.keyId, function (err, ids) {
      if (err) {
        // Not created, so create a new array
        ids = [id];
      } else {
        if (ids.indexOf(id) === -1) {
          ids.unshift(id);
        }
      }

      opts.push({
        type: 'put',
        key: KEY + 'all:ids' + self.keyId,
        value: ids
      });

      opts.push({
        type: 'put',
        key: KEY + id,
        value: message
      });

      self.db.batch(opts, function (err) {
        if (err) {
          callback(err);
        } else {
          callback(null, message);
        }
      });
    });
  };

  var setPublic = function (opts, message, id, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (err) {
        publicIds = [];
      }

      if (!message.meta.isPrivate && publicIds.indexOf(id) === -1) {
        publicIds.unshift(id);

        opts.push({
          type: 'put',
          key: KEY + 'public:ids' + self.keyId,
          value: publicIds
        });
      }

      setAll(opts, message, id, callback);
    });
  };

  var setPrivate = function (opts, message, id, callback) {
    self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
      if (err) {
        privIds = [];
      }

      if (message.meta.isPrivate && privIds.indexOf(id) === -1) {
        privIds.unshift(id);

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });
      }

      setPublic(opts, message, id, callback);
    });
  };

  this.create = function (message, callback) {
    if (!message || !this.fullName || !this.postUrl) {
      callback(new Error('Message invalid'));
    } else {
      var opts = [];

      openDb(function () {
        self.db.get(KEY + 'ids', function (err, id) {
          if (err) {
            id = 1;
          } else {
            id ++;
          }

          opts.push({
            type: 'put',
            key: KEY + 'ids',
            value: id
          });

          message.id = id;
          message.fullName = self.fullName;
          message.username = self.username;
          if (!message.postUrl) {
            message.postUrl = self.postUrl;
          }
          message.content.created = message.content.updated = Math.round(new Date() / 1000);

          setPrivate(opts, message, id, callback);
        });
      });
    }
  };

  this.get = function (id, callback) {
    openDb(function () {
      self.db.get(KEY + id, function (err, message) {
        if (err || !message) {
          callback(new Error('Not found ', err));
        } else {
          if (typeof message === 'object') {
            callback(null, message);
          } else {
            callback(new Error('Invalid JSON'));
          }
        }
      });
    });
  };

  this.share = function (message, url, callback) {
    if (message.shares.indexOf(this.postUrl) < 0) {
      message.meta.isShared = true;
      message.postUrl = url;
      message.shares.push(url);

      self.create(message, callback);
    } else {
      callback(new Error('Already shared'));
    }
  };

  this.subscribe = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          subs = {};
        }

        url = url.toLowerCase().trim();
        subs[url] = true;

        self.db.put(KEY + 'subscriptions' + self.keyId, subs, function (err) {
          if (err) {
            callback(err);
          } else {
            callback(null, url);
          }
        });
      });
    });
  };

  var loadSubscriptions = function (subs, callback) {
    var subscriptions = [];
    var subsLength = Object.keys(subs).length;

    if (subsLength > 0) {
      for (var s in subs) {
        subscriptions.push(s);

        if (subscriptions.length === subsLength) {
          callback(null, subscriptions);
        }
      }
    } else {
      callback(null, subscriptions);
    }
  };

  this.unsubscribe = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          subs = {};
        }

        delete subs[url.toLowerCase().trim()];

        self.db.put(KEY + 'subscriptions' + self.keyId, subs, function (err) {
          if (err) {
            callback(err);
          } else {
            loadSubscriptions(subs, callback);
          }
        });
      });
    });
  };

  this.getSubscriptions = function (callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        if (err) {
          callback(null, []);
        } else {
          loadSubscriptions(subs, callback);
        }
      });
    });
  };

  this.getSubscriptionRecent = function (url, callback) {
    openDb(function () {
      self.db.get(KEY + 'subscriptions' + self.keyId, function (err, subs) {
        url = url.toLowerCase().trim();

        if (err || !subs[url]) {
          callback(new Error('Subscription messages not found or you did not subscribe to this url'));
        } else {
          request(url, function (err, resp, body) {
            if (err) {
              callback(err);
            } else {
              if (typeof body !== 'object') {
                try {
                  body = JSON.parse(body);
                } catch (e) {
                  return callback(new Error('Could not parse JSON'));
                }
              }

              var recentArr = [];

              for (var i = 0; i < body.posts.length; i ++) {
                recentArr.push(body.posts[i]);

                if (recentArr.length === body.posts.length) {
                  callback(null, recentArr);
                }
              }
            }
          });
        }
      });
    });
  };

  var loadAll = function (ids, callback) {
    self.messageArray = [];
    self.ids = ids;

    if (self.ids.length > 0) {
      for (var i = 0; i < self.ids.length; i ++) {
        addToArray(i, callback);
      }
    } else {
      callback(null, self.messageArray);
    }
  };

  var resetPublic = function (opts, message, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (!publicIds) {
        publicIds = [];
      }

      if (message.meta.isPrivate) {
        publicIds.splice(publicIds.indexOf(message.id), 1);
      } else if (publicIds.indexOf(message.id) === -1) {
        publicIds.unshift(message.id);
      }

      opts.push({
        type: 'put',
        key: KEY + 'public:ids' + self.keyId,
        value: publicIds
      });

      self.db.get(KEY + message.id, function (err, msg) {
        if (err) {
          callback(err);
        } else {
          message.content.updated = Math.round(new Date() / 1000);

          opts.push({
            type: 'put',
            key: KEY + message.id,
            value: message
          });

          self.db.batch(opts, function (err) {
            if (err) {
              callback(err);
            } else {
              callback(null, message);
            }
          });
        }
      });
    });
  };

  this.update = function (message, callback) {
    openDb(function () {
      self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
        var opts = [];

        if (!privIds) {
          privIds = [];
        }

        if (message.meta.isPrivate) {
          privIds.unshift(message.id);
        } else if (privIds.indexOf(message.id) === -1) {
          privIds.splice(privIds.indexOf(message.id), 1);
        }

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });

        resetPublic(opts, message, callback);
      });
    });
  };

  var delPublic = function (opts, id, callback) {
    self.db.get(KEY + 'public:ids' + self.keyId, function (err, publicIds) {
      if (err) {
        callback(err);
      } else {
        publicIds.splice(publicIds.indexOf(id), 1);

        opts.push({
          type: 'put',
          key: KEY + 'public:ids' + self.keyId,
          value: publicIds
        });

        self.ids.splice(self.ids.indexOf(id), 1);

        self.db.batch(opts, function (err) {
          if (err) {
            callback(err);
          } else {
            callback(null, true);
          }
        });
      }
    });
  };

  var delPrivate = function (opts, id, callback) {
    self.db.get(KEY + 'priv:ids' + self.keyId, function (err, privIds) {
      if (err) {
        callback(err);
      } else {
        privIds.splice(privIds.indexOf(id), 1);

        opts.push({
          type: 'put',
          key: KEY + 'priv:ids' + self.keyId,
          value: privIds
        });

        delPublic(opts, id, callback);
      }
    });
  };

  this.del = function (id, callback) {
    openDb(function () {
      id = parseInt(id, 10);
      var opts = [];

      opts.push({
        type: 'del',
        key: KEY + id
      });

      self.db.get(KEY + 'all:ids' + self.keyId, function (err, ids) {
        if (err) {
          callback(err);
        } else {
          ids.splice(ids.indexOf(id), 1);

          opts.push({
            type: 'put',
            key: KEY + 'all:ids' + self.keyId,
            value: ids
          });

          delPrivate(opts, id, callback);
        }
      });
    });
  };

  this.getAll = function (start, callback) {
    openDb(function () {
      start = parseInt(start, 10);

      if (isNaN(start)) {
        start = 0;
      }

      self.db.get(KEY + 'all:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          self.totalAll = cids.length;
          loadAll(cids.slice(start, self.limit + start + 1), callback);
        }
      });
    });
  };

  this.getAllIds = function (callback) {
    openDb(function () {
      self.db.get(KEY + 'all:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          callback(null, cids);
        }
      });
    });
  };

  this.shareRecent = function (start, callback) {
    openDb(function () {
      start = parseInt(start, 10);

      if (isNaN(parseInt(start, 10))) {
        start = 0;
      }

      self.db.get(KEY + 'public:ids' + self.keyId, function (err, cids) {
        if (err) {
          callback(err);
        } else {
          self.totalPublic = cids.length;
          loadAll(cids.slice(start, self.limit + start + 1), callback);
        }
      });
    });
  };

  this.shareOne = function (id, callback) {
    openDb(function () {
      self.get(id, function (err, message) {
        if (err) {
          callback(err);
        } else {
          if (message.meta.isPrivate) {
            callback(new Error('This is private'));
          } else {
            callback(null, message);
          }
        }
      });
    });
  };

  this.flush = function (dbPath) {
    leveldown.destroy(dbPath || self.dbPath, function (err) {
      console.log('Deleted database');
    });
  };
};

module.exports = Meatspace;
<|endoftext|>


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

const APP_ID = '59f807307ebf813df0c1dd3647242945';
const BASE_URL = 'http://api.openweathermap.org/data/2.5/weather?q=';

const getRequestOptions = city => ({
  url: `${BASE_URL}${city}&APPID=${APP_ID}`,
  headers: {
    'User-Agent': 'agentWeatherrApi'
  }
})

const getWordWithoutSomething = (str, find, replace) =>
  str.replace(new RegExp(find, 'g'), replace);

// Get maximum temperature
exports.getMaximumTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(parseInt(data['main']['temp_max'] - 273));
    }
  });
};

// Get minimum temperature
exports.getMinimumTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
       return callback('City not found');
    } else {
      return callback(parseInt(data['main']['temp_min'] - 273));
    }
  });
};

// Get actual temperature
exports.getActualTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(parseInt(data['main']['temp'] - 273));
    }
  });
};

// Get climate description
exports.getClimateDescription = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(data['weather'][0]['description']);
    }
  });
};

// Get wind speed
exports.getWindSpeed = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(data['wind']['speed']);
    }
  });
};
<commit_msg>callbacks: fix response when theres no error<commit_after>const request = require('request');

const APP_ID = '59f807307ebf813df0c1dd3647242945';
const BASE_URL = 'http://api.openweathermap.org/data/2.5/weather?q=';

const getRequestOptions = city => ({
  url: `${BASE_URL}${city}&APPID=${APP_ID}`,
  headers: {
    'User-Agent': 'agentWeatherrApi'
  }
})

const getWordWithoutSomething = (str, find, replace) =>
  str.replace(new RegExp(find, 'g'), replace);

// Get maximum temperature
exports.getMaximumTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(null, parseInt(data['main']['temp_max'] - 273));
    }
  });
};

// Get minimum temperature
exports.getMinimumTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
       return callback('City not found');
    } else {
      return callback(null, parseInt(data['main']['temp_min'] - 273));
    }
  });
};

// Get actual temperature
exports.getActualTemp = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(null, parseInt(data['main']['temp'] - 273));
    }
  });
};

// Get climate description
exports.getClimateDescription = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(null, data['weather'][0]['description']);
    }
  });
};

// Get wind speed
exports.getWindSpeed = (city, callback) => {
  city = getWordWithoutSomething(city.trim(), ' ', '-');

  const options = getRequestOptions(city)

  request(options, (error, response, body) => {
    let data = JSON.parse(body);

    if(data['message'] != undefined) {
      return callback('City not found');
    } else {
      return callback(null, data['wind']['speed']);
    }
  });
};
<|endoftext|>


<commit_before>module.exports = {
  extends: [
    'eslint-config-defaults'
  ].map(require.resolve),
  env: {
    node: true
  },
  rules: {
    'eol-last': 2,
    indent: ['error', 2],
    quotes: [2, 'single'],
    semi: 2
  }
};
<commit_msg>rules: disallow trailing whitespace<commit_after>module.exports = {
  extends: [
    'eslint-config-defaults'
  ].map(require.resolve),
  env: {
    node: true
  },
  rules: {
    'eol-last': 2,
    indent: ['error', 2],
    'no-trailing-spaces': 2,
    quotes: [2, 'single'],
    semi: 2
  }
};
<|endoftext|>


<commit_before>'use strict'
const ethUtil = require('ethereumjs-util')
const fees = require('ethereum-common/params')
const BN = ethUtil.BN

// secp256k1n/2
const N_DIV_2 = new BN('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16)

/**
 * Creates a new transaction object
 * @class {Buffer|Array} data a transaction can be initiailized with either a buffer containing the RLP serialized transaction or an array of buffers relating to each of the tx Properties, listed in order below in the exmple. Or lastly an Object containing the Properties of the transaction like in the Usage example
 *
 * For Object and Arrays each of the elements can either be a Buffer, a hex-prefixed (0x) String , Number, or an object with a toBuffer method such as Bignum
 * @example
 * var rawTx = {
 *   nonce: '00',
 *   gasPrice: '09184e72a000',
 *   gasLimit: '2710',
 *   to: '0000000000000000000000000000000000000000',
 *   value: '00',
 *   data: '7f7465737432000000000000000000000000000000000000000000000000000000600057',
 *   v: '1c',
 *   r: '5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab',
 *   s '5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13'
 * };
 * var tx = new Transaction(rawTx);
 * @prop {Buffer} raw The raw rlp decoded transaction
 * @prop {Buffer} nonce
 * @prop {Buffer} to the to address
 * @prop {Buffer} value the amount of ether sent
 * @prop {Buffer} data this will contain the data of the message or the init of a contract
 * @prop {Buffer} v EC signature parameter
 * @prop {Buffer} r EC signature parameter
 * @prop {Buffer} s EC recovery ID
 */
module.exports = class Transaction {
  constructor (data={}) {
    // Define Properties
    const fields = [{
      name: 'nonce',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'gasPrice',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'gasLimit',
      alias: 'gas',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'to',
      allowZero: true,
      length: 20,
      default: new Buffer([])
    }, {
      name: 'value',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'data',
      alias: 'input',
      allowZero: true,
      default: new Buffer([])
    }, {
      name: 'v',
      length: 1,
      default: new Buffer([0x1c])
    }, {
      name: 'r',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 's',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }]

    /**
     * Returns the rlp encoding of the transaction
     * @method serialize
     * @return {Buffer}
     */
    // attached serialize
    ethUtil.defineProperties(this, fields, data)

    /**
     * @prop {Buffer} from (read only) sender address of this transaction, mathematically derived from other parameters.
     */
    Object.defineProperty(this, 'from', {
      enumerable: true,
      configurable: true,
      get: this.getSenderAddress.bind(this)
    })

    // calculate chainId from signature
    let sigV = ethUtil.bufferToInt(this.v)
    let chainId = (sigV - 35) / 2
    if (chainId < 0) chainId = 0

    // set chainId
    this._chainId = chainId || data.chainId || 0
    this._homestead = true
  }

  /**
   * If the tx's `to` is to the creation address
   * @return {Boolean}
   */
  toCreationAddress () {
    return this.to.toString('hex') === ''
  }

  /**
   * Computes a sha3-256 hash of the serialized tx
   * @param {Boolean} [includeSignature=true] whether or not to inculde the signature
   * @return {Buffer}
   */
  hash (includeSignature=true) {
    // backup original signature
    const rawCopy = this.raw.slice(0)

    // modify raw for signature generation only
    if (this._chainId > 0) {
      includeSignature = true
      this.v = this._chainId
      this.r = 0
      this.s = 0
    }

    // generate rlp params for hash
    let txRawForHash = includeSignature ? this.raw : this.raw.slice(0, 6)

    // restore original signature
    this.raw = rawCopy.slice()

    // create hash
    return ethUtil.rlphash(txRawForHash)
  }

  /**
   * returns the public key of the sender
   * @return {Buffer}
   */
  getChainId () {
    return this._chainId
  }

  /**
   * returns the sender's address
   * @return {Buffer}
   */
  getSenderAddress () {
    if (this._from) {
      return this._from
    }
    const pubkey = this.getSenderPublicKey()
    this._from = ethUtil.publicToAddress(pubkey)
    return this._from
  }

  /**
   * returns the public key of the sender
   * @return {Buffer}
   */
  getSenderPublicKey () {
    if (!this._senderPubKey || !this._senderPubKey.length) {
      if (!this.verifySignature()) throw new Error('Invalid Signature')
    }
    return this._senderPubKey
  }

  /**
   * Determines if the signature is valid
   * @return {Boolean}
   */
  verifySignature () {
    const msgHash = this.hash(false)
    // All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid.
    if (this._homestead && new BN(this.s).cmp(N_DIV_2) === 1) {
      return false
    }

    try {
      let v = ethUtil.bufferToInt(this.v)
      if (this._chainId > 0) {
        v -= this._chainId * 2 + 8
      }
      this._senderPubKey = ethUtil.ecrecover(msgHash, v, this.r, this.s)
    } catch (e) {
      return false
    }

    return !!this._senderPubKey
  }

  /**
   * sign a transaction with a given a private key
   * @param {Buffer} privateKey
   */
  sign (privateKey) {
    const msgHash = this.hash(false)
    const sig = ethUtil.ecsign(msgHash, privateKey)
    if (this._chainId > 0) {
      sig.v += this._chainId * 2 + 8
    }
    Object.assign(this, sig)
  }

  /**
   * The amount of gas paid for the data in this tx
   * @return {BN}
   */
  getDataFee () {
    const data = this.raw[5]
    const cost = new BN(0)
    for (let i = 0; i < data.length; i++) {
      data[i] === 0 ? cost.iaddn(fees.txDataZeroGas.v) : cost.iaddn(fees.txDataNonZeroGas.v)
    }
    return cost
  }

  /**
   * the minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee)
   * @return {BN}
   */
  getBaseFee () {
    const fee = this.getDataFee().iaddn(fees.txGas.v)
    if (this._homestead && this.toCreationAddress()) {
      fee.iaddn(fees.txCreation.v)
    }
    return fee
  }

  /**
   * the up front amount that an account must have for this transaction to be valid
   * @return {BN}
   */
  getUpfrontCost () {
    return new BN(this.gasLimit)
      .imul(new BN(this.gasPrice))
      .iadd(new BN(this.value))
  }

  /**
   * validates the signature and checks to see if it has enough gas
   * @param {Boolean} [stringError=false] whether to return a string with a dscription of why the validation failed or return a Bloolean
   * @return {Boolean|String}
   */
  validate (stringError) {
    const errors = []
    if (!this.verifySignature()) {
      errors.push('Invalid Signature')
    }

    if (this.getBaseFee().cmp(new BN(this.gasLimit)) > 0) {
      errors.push([`gas limit is to low. Need at least ${this.getBaseFee()}`])
    }

    if (stringError === undefined || stringError === false) {
      return errors.length === 0
    } else {
      return errors.join(' ')
    }
  }
}
<commit_msg>es6 - remove fancy fn argument default values<commit_after>'use strict'
const ethUtil = require('ethereumjs-util')
const fees = require('ethereum-common/params')
const BN = ethUtil.BN

// secp256k1n/2
const N_DIV_2 = new BN('7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0', 16)

/**
 * Creates a new transaction object
 * @class {Buffer|Array} data a transaction can be initiailized with either a buffer containing the RLP serialized transaction or an array of buffers relating to each of the tx Properties, listed in order below in the exmple. Or lastly an Object containing the Properties of the transaction like in the Usage example
 *
 * For Object and Arrays each of the elements can either be a Buffer, a hex-prefixed (0x) String , Number, or an object with a toBuffer method such as Bignum
 * @example
 * var rawTx = {
 *   nonce: '00',
 *   gasPrice: '09184e72a000',
 *   gasLimit: '2710',
 *   to: '0000000000000000000000000000000000000000',
 *   value: '00',
 *   data: '7f7465737432000000000000000000000000000000000000000000000000000000600057',
 *   v: '1c',
 *   r: '5e1d3a76fbf824220eafc8c79ad578ad2b67d01b0c2425eb1f1347e8f50882ab',
 *   s '5bd428537f05f9830e93792f90ea6a3e2d1ee84952dd96edbae9f658f831ab13'
 * };
 * var tx = new Transaction(rawTx);
 * @prop {Buffer} raw The raw rlp decoded transaction
 * @prop {Buffer} nonce
 * @prop {Buffer} to the to address
 * @prop {Buffer} value the amount of ether sent
 * @prop {Buffer} data this will contain the data of the message or the init of a contract
 * @prop {Buffer} v EC signature parameter
 * @prop {Buffer} r EC signature parameter
 * @prop {Buffer} s EC recovery ID
 */
module.exports = class Transaction {
  constructor (data) {
    data = data || {}
    // Define Properties
    const fields = [{
      name: 'nonce',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'gasPrice',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'gasLimit',
      alias: 'gas',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'to',
      allowZero: true,
      length: 20,
      default: new Buffer([])
    }, {
      name: 'value',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 'data',
      alias: 'input',
      allowZero: true,
      default: new Buffer([])
    }, {
      name: 'v',
      length: 1,
      default: new Buffer([0x1c])
    }, {
      name: 'r',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }, {
      name: 's',
      length: 32,
      allowLess: true,
      default: new Buffer([])
    }]

    /**
     * Returns the rlp encoding of the transaction
     * @method serialize
     * @return {Buffer}
     */
    // attached serialize
    ethUtil.defineProperties(this, fields, data)

    /**
     * @prop {Buffer} from (read only) sender address of this transaction, mathematically derived from other parameters.
     */
    Object.defineProperty(this, 'from', {
      enumerable: true,
      configurable: true,
      get: this.getSenderAddress.bind(this)
    })

    // calculate chainId from signature
    let sigV = ethUtil.bufferToInt(this.v)
    let chainId = (sigV - 35) / 2
    if (chainId < 0) chainId = 0

    // set chainId
    this._chainId = chainId || data.chainId || 0
    this._homestead = true
  }

  /**
   * If the tx's `to` is to the creation address
   * @return {Boolean}
   */
  toCreationAddress () {
    return this.to.toString('hex') === ''
  }

  /**
   * Computes a sha3-256 hash of the serialized tx
   * @param {Boolean} [includeSignature=true] whether or not to inculde the signature
   * @return {Buffer}
   */
  hash (includeSignature) {
    if (includeSignature === undefined) includeSignature = true
    // backup original signature
    const rawCopy = this.raw.slice(0)

    // modify raw for signature generation only
    if (this._chainId > 0) {
      includeSignature = true
      this.v = this._chainId
      this.r = 0
      this.s = 0
    }

    // generate rlp params for hash
    let txRawForHash = includeSignature ? this.raw : this.raw.slice(0, 6)

    // restore original signature
    this.raw = rawCopy.slice()

    // create hash
    return ethUtil.rlphash(txRawForHash)
  }

  /**
   * returns the public key of the sender
   * @return {Buffer}
   */
  getChainId () {
    return this._chainId
  }

  /**
   * returns the sender's address
   * @return {Buffer}
   */
  getSenderAddress () {
    if (this._from) {
      return this._from
    }
    const pubkey = this.getSenderPublicKey()
    this._from = ethUtil.publicToAddress(pubkey)
    return this._from
  }

  /**
   * returns the public key of the sender
   * @return {Buffer}
   */
  getSenderPublicKey () {
    if (!this._senderPubKey || !this._senderPubKey.length) {
      if (!this.verifySignature()) throw new Error('Invalid Signature')
    }
    return this._senderPubKey
  }

  /**
   * Determines if the signature is valid
   * @return {Boolean}
   */
  verifySignature () {
    const msgHash = this.hash(false)
    // All transaction signatures whose s-value is greater than secp256k1n/2 are considered invalid.
    if (this._homestead && new BN(this.s).cmp(N_DIV_2) === 1) {
      return false
    }

    try {
      let v = ethUtil.bufferToInt(this.v)
      if (this._chainId > 0) {
        v -= this._chainId * 2 + 8
      }
      this._senderPubKey = ethUtil.ecrecover(msgHash, v, this.r, this.s)
    } catch (e) {
      return false
    }

    return !!this._senderPubKey
  }

  /**
   * sign a transaction with a given a private key
   * @param {Buffer} privateKey
   */
  sign (privateKey) {
    const msgHash = this.hash(false)
    const sig = ethUtil.ecsign(msgHash, privateKey)
    if (this._chainId > 0) {
      sig.v += this._chainId * 2 + 8
    }
    Object.assign(this, sig)
  }

  /**
   * The amount of gas paid for the data in this tx
   * @return {BN}
   */
  getDataFee () {
    const data = this.raw[5]
    const cost = new BN(0)
    for (let i = 0; i < data.length; i++) {
      data[i] === 0 ? cost.iaddn(fees.txDataZeroGas.v) : cost.iaddn(fees.txDataNonZeroGas.v)
    }
    return cost
  }

  /**
   * the minimum amount of gas the tx must have (DataFee + TxFee + Creation Fee)
   * @return {BN}
   */
  getBaseFee () {
    const fee = this.getDataFee().iaddn(fees.txGas.v)
    if (this._homestead && this.toCreationAddress()) {
      fee.iaddn(fees.txCreation.v)
    }
    return fee
  }

  /**
   * the up front amount that an account must have for this transaction to be valid
   * @return {BN}
   */
  getUpfrontCost () {
    return new BN(this.gasLimit)
      .imul(new BN(this.gasPrice))
      .iadd(new BN(this.value))
  }

  /**
   * validates the signature and checks to see if it has enough gas
   * @param {Boolean} [stringError=false] whether to return a string with a dscription of why the validation failed or return a Bloolean
   * @return {Boolean|String}
   */
  validate (stringError) {
    const errors = []
    if (!this.verifySignature()) {
      errors.push('Invalid Signature')
    }

    if (this.getBaseFee().cmp(new BN(this.gasLimit)) > 0) {
      errors.push([`gas limit is to low. Need at least ${this.getBaseFee()}`])
    }

    if (stringError === undefined || stringError === false) {
      return errors.length === 0
    } else {
      return errors.join(' ')
    }
  }
}
<|endoftext|>


<commit_before>#! /usr/bin/env node

var h           = require('highland')
  , _           = require('lodash')
  , program     = require('commander')
  , XLSX        = require('xlsx')
  , request     = require('superagent')
  , through2    = require('through2')
  , mappedColumns;

var exceltoJSONStream = function(file){
  var workbook = XLSX.readFile(file);
  var ws = workbook.Sheets[workbook.SheetNames[0]];
  var json = XLSX.utils.sheet_to_json(ws);
  return h(json);
};

var lowerCasedKeys = function(row){
  const result = {};
  _.keys(row).forEach(key => result[key.toLowerCase()] = row[key]);
  return result;
};

var mapColumns = function(row){
  const result = _.assign({}, row);
  const inverted = _.invert(mappedColumns);

  _.values(mappedColumns).forEach( val => {
    result[inverted[val]] = row[val];
    delete result[val]
  });

  return result;
};

function parseMapCols(val){
  var result = {};
  var val = val.replace(/\s|\"|\{|\}|\[|\]/g, '');
  val.split(',').forEach(function(e){
    var parts = e.split(':');
    result[parts[0]] = parts[1] === 'null' ? null : parts[1];
  });
  return result;
}

program
.usage('[options] <file>')
.arguments('<file>')
.option('-u, --url <http request target>', 'URL to work with.')
.option('-c, --mapcols [override1:original1, ...]', 'Optional column headers to override originals in xls/csv.', parseMapCols)
.action(function(file) {
  mappedColumns = program.mapcols;

  exceltoJSONStream(file)
  .map(lowerCasedKeys)
  .map(mapColumns)
  .map(JSON.stringify)
  .pipe(through2.obj(function(payload, h, next){
    request
    .post(program.url)
    .send(payload)
    .set('Accept', 'application/json')
    .set('Content-Type', 'application/json')
    .end(function(err, res){
      next(err, JSON.stringify(res));
    });
  }))
  .pipe(process.stdout);
})
.parse(process.argv);<commit_msg>Index -> is now the library API.<commit_after>'use strict';

const h           = require('highland')
    , _           = require('lodash')
    , XLSX        = require('xlsx')
    , request     = require('superagent')
    , through2    = require('through2');

const workbookToStream = (workbook, opts) => {
  const ws = workbook.Sheets[workbook.SheetNames[0]];
  const json = XLSX.utils.sheet_to_json(ws);
  return h(json);
};

const lowerCasedKeys = (row) => {
  const result = {};
  _.keys(row).forEach(key => result[key.toLowerCase()] = row[key]);
  return result;
};

const override = (overriden, row) => {
  const result = _.assign({}, row);
  const inverted = _.invert(overriden);

  _.values(overriden).forEach( val => {
    result[inverted[val]] = row[val];
    delete result[val]
  });

  return result;
};

const ignore = (ignored, row) => {
  const result = _.assign({}, row);
  ignored.forEach( i => { delete result[i] });
  return result;
};

function Slingg(opts) {
  if (!(this instanceof Slingg)) return new Slingg(opts);

  opts || (opts = {});
  if(!opts.url){ throw new Error('Destination url is missing!'); }

  this.url = opts.url;
  this.headers = opts.headers;
}

Slingg.prototype.hasOverrideHeaders = function () {
  return this.headers && this.headers.override;
};

Slingg.prototype.hasIgnoreHeaders = function () {
  return this.headers && this.headers.ignore;
};

Slingg.prototype.extractWorkbookFromPath = function (filePath) {
  this.workbook = XLSX.readFile(filePath);
  return this;
};

Slingg.prototype.extractWorkbookFromBuffer = function (buffer) {
  this.workbook = XLSX.read(buffer);
  return this;
};

Slingg.prototype.createBaseStream = function () {
  const ws = this.workbook.Sheets[this.workbook.SheetNames[0]];
  this.baseStream = h(XLSX.utils.sheet_to_json(ws));
  return this;
};

Slingg.prototype.start = function () {
  return this.baseStream
    .map(lowerCasedKeys)
    .map((row) => { return this.hasOverrideHeaders() ? override(this.headers.override, row) : row; })
    .map((row) => { return this.hasIgnoreHeaders() ? ignore(this.headers.ignore, row) : row; })
    .doto(console.log)
    .map(JSON.stringify)
    .pipe(through2.obj((payload, _, next) => {
      request
      .post(this.url)
      .send(payload)
      .set('Accept', 'application/json')
      .set('Content-Type', 'application/json')
      .end(function(err, res){
        next(err, JSON.stringify(res));
      });
    }));
};

Slingg.fromPath = (filePath, opts) => {
  const obj = new Slingg(opts);
  return obj
  .extractWorkbookFromPath(filePath)
  .createBaseStream();
};

Slingg.fromBuffer = (buffer, opts) => {
  const obj = new Slingg(opts);
  return obj
  .extractWorkbookFromBuffer(buffer)
  .createBaseStream();
};

module.exports = Slingg;<|endoftext|>


<commit_before>'use strict';

var transpiler = require('6to5-core');
var Filter     = require('broccoli-filter');

function SixToFive(inputTree, options) {
  if (!(this instanceof SixToFive)) {
    return new SixToFive(inputTree, options);
  }

  this.inputTree = inputTree;
  this.options = options || {};
}

SixToFive.prototype = Object.create(Filter.prototype);
SixToFive.prototype.constructor = SixToFive;

SixToFive.prototype.extensions = ['js'];
SixToFive.prototype.targetExtension = 'js';

SixToFive.prototype.processString = function (string, relativePath) {
  var opts = this.copyOptions();

  opts.filename = opts.sourceMapName = opts.sourceFileName = relativePath;

  return transpiler.transform(string, opts).code;
};

SixToFive.prototype.copyOptions = function() {
  return JSON.parse(JSON.stringify(this.options));
};

module.exports = SixToFive;
<commit_msg>quick hack<commit_after>'use strict';

var transpiler = require('6to5-core');
var Filter     = require('broccoli-filter');

function SixToFive(inputTree, options) {
  if (!(this instanceof SixToFive)) {
    return new SixToFive(inputTree, options);
  }

  this.inputTree = inputTree;
  this.options = options || {};
}

SixToFive.prototype = Object.create(Filter.prototype);
SixToFive.prototype.constructor = SixToFive;

SixToFive.prototype.extensions = ['js'];
SixToFive.prototype.targetExtension = 'js';

SixToFive.prototype.processString = function (string, relativePath) {
  var opts = this.copyOptions();

  opts.filename = opts.sourceMapName = opts.sourceFileName = relativePath;

  return transpiler.transform(string, opts).code;
};

SixToFive.prototype.copyOptions = function() {
  return {};//
  //return JSON.parse(JSON.stringify(this.options));
};

module.exports = SixToFive;
<|endoftext|>


<commit_before>module.exports = function parsePrefix(prefix) {
	var result = {}
	result.input = prefix

	var hasExclamation = prefix.indexOf('!') !== -1
	var hasAt = prefix.indexOf('@') !== -1
	var hasPeriod = prefix.indexOf('.') !== -1

	if (hasPeriod && !hasExclamation && !hasAt) {
		result.type = 'server'
		return result
	}

	result.type = 'user'

	result.nickname = null
	result.username = null
	result.hostname = null

	var userStart = 0
	var userEnd = 0

	while (prefix[userStart] !== '!') userStart++

	if (userStart < prefix.length) {
		result.nickname = prefix.slice(0, userStart)
		userEnd = userStart
	}

	while (prefix[userEnd] !== '@') userEnd++

	if (userEnd < prefix.length) {
		result.username = prefix.slice(userStart + 1, userEnd )
		result.hostname = prefix.slice(userEnd + 1)
	}

	return result
}<commit_msg>Spaces instead of tabs<commit_after>module.exports = function parsePrefix(prefix) {
    var result = {}
    result.input = prefix

    var hasExclamation = prefix.indexOf('!') !== -1
    var hasAt = prefix.indexOf('@') !== -1
    var hasPeriod = prefix.indexOf('.') !== -1

    if (hasPeriod && !hasExclamation && !hasAt) {
        result.type = 'server'
        return result
    }

    result.type = 'user'

    result.nickname = null
    result.username = null
    result.hostname = null

    var userStart = 0
    var userEnd = 0

    while (prefix[userStart] !== '!') userStart++

    if (userStart < prefix.length) {
        result.nickname = prefix.slice(0, userStart)
        userEnd = userStart
    }

    while (prefix[userEnd] !== '@') userEnd++

    if (userEnd < prefix.length) {
        result.username = prefix.slice(userStart + 1, userEnd )
        result.hostname = prefix.slice(userEnd + 1)
    }

    return result
}<|endoftext|>


<commit_before>module.exports = [
  '2015',
  '2016',
  '2017',
  '2018',
  '2019',
  '2020',
  'abuse',
  'accessibility',
  'account',
  'accounting',
  'accountmanagers',
  'accounts',
  'accountspayable',
  'acquisition',
  'admin',
  'administracion',
  'administration',
  'administrativo',
  'administrator',
  'administrators',
  'admins',
  'adminteam',
  'admissions',
  'adops',
  'ads',
  'adventure',
  'advertise',
  'advertising',
  'advertisingsales',
  'advisor',
  'advisors',
  'adwords',
  'affiliate',
  'affiliates',
  'agency',
  'agents',
  'alarm',
  'alarms',
  'alert',
  'alerts',
  'alexa',
  'all',
  'all-employees',
  'all-pms',
  'all-staff',
  'all-team',
  'all-users',
  'all.employees',
  'all.staff',
  'all.users',
  'all_staff',
  'alla',
  'alle',
  'allemployees',
  'allhands',
  'allsales',
  'allstaff',
  'allstudents',
  'allteachers',
  'allteam',
  'allusers',
  'alpha',
  'alphas',
  'alumni',
  'ambassadors',
  'amministrazione',
  'analysts',
  'analytics',
  'android',
  'angels',
  'announce',
  'announcements',
  'ap',
  'api',
  'app',
  'apple',
  'application',
  'applications',
  'apply',
  'apps',
  'asset',
  'associates',
  'associates-all',
  'ateam',
  'atendimento',
  'auctions',
  'available',
  'backend',
  'backend-dev',
  'backup',
  'bd',
  'benefits',
  'berlin',
  'beta',
  'billing',
  'bills',
  'biz',
  'bizdev',
  'blog',
  'board',
  'bod',
  'bookclub',
  'booking',
  'bookings',
  'boston',
  'brand',
  'branding',
  'brands',
  'brandsolutions',
  'broadcast',
  'bugs',
  'build',
  'bursar',
  'busdev',
  'business',
  'business_team',
  'businessdevelopment',
  'ca',
  'caltrain',
  'campaign',
  'campaigns',
  'campusteam',
  'captain',
  'captains',
  'care',
  'career',
  'careers',
  'ceo',
  'ceos',
  'channel-sales',
  'chat',
  'chatter',
  'chicago',
  'china',
  'citymanagers',
  'classof2016',
  'classof2017',
  'classof2018',
  'classof2019',
  'classroom_teachers',
  'client',
  'clientes',
  'clients',
  'clientservices',
  'cloud',
  'cm',
  'co-op',
  'coach',
  'coaches',
  'code',
  'colaboradores',
  'comercial',
  'commercial',
  'commissions',
  'committee',
  'comms',
  'communication',
  'communications',
  'community',
  'community',
  'company',
  'company.wide',
  'compete',
  'competition',
  'compliance',
  'compras',
  'concierge',
  'conference',
  'connect',
  'consultant',
  'consulting',
  'contact',
  'contacto',
  'contactus',
  'contato',
  'content',
  'contractor',
  'contractors',
  'contracts',
  'copyright',
  'core',
  'coreteam',
  'corp',
  'corporate',
  'corporatesales',
  'council',
  'creative',
  'crew',
  'crm',
  'cs',
  'csm',
  'csteam',
  'culture',
  'customer',
  'customercare',
  'customerfeedback',
  'customers',
  'customerservice',
  'customersuccess',
  'data',
  'database',
  'deals',
  'dean',
  'delivery',
  'demo',
  'denver',
  'departures',
  'deploy',
  'design',
  'designers',
  'dev',
  'developer',
  'developers',
  'development',
  'devnull',
  'devops',
  'devs',
  'devteam',
  'digital',
  'digsitesvalue',
  'director',
  'directors',
  'directory',
  'diretoria',
  'discuss',
  'dispatch',
  'diversity',
  'dns',
  'docs',
  'domain',
  'domainmanagement',
  'domains',
  'download',
  'dreamteam',
  'ecommerce',
  'editor',
  'editorial',
  'editors',
  'education',
  'email',
  'emergency',
  'employee',
  'employees',
  'employment',
  'eng',
  'eng-all',
  'engagement',
  'engineering',
  'engineers',
  'enq',
  'enquire',
  'enquiries',
  'enquiry',
  'enterprise',
  'equipe',
  'equipo',
  'error',
  'errors',
  'europe',
  'event',
  'events',
  'everybody',
  'everyone',
  'exec',
  'execs',
  'execteam',
  'executive',
  'executives',
  'expenses',
  'expert',
  'experts',
  'export',
  'facilities',
  'faculty',
  'family',
  'fax',
  'fbl',
  'feedback',
  'fellows',
  'finance',
  'financeiro',
  'food',
  'football',
  'founders',
  'france',
  'friends',
  'frontend',
  'fte',
  'ftp',
  'fulltime',
  'fun',
  'fundraising',
  'geeks',
  'general',
  'geral',
  'global',
  'graphics',
  'group',
  'growth',
  'hackathon',
  'hackers',
  'head',
  'head.office',
  'headoffice',
  'heads',
  'headteacher',
  'hello',
  'help',
  'helpdesk',
  'hi',
  'highschool',
  'hiring',
  'hola',
  'home',
  'homes',
  'hosting',
  'hostmaster',
  'house',
  'hq',
  'hr',
  'hsstaff',
  'hsteachers',
  'ideas',
  'implementation',
  'inbound',
  'india',
  'info',
  'information',
  'informativo',
  'infra',
  'infrastructure',
  'innovation',
  'inoc',
  'inquiries',
  'inquiry',
  'insidesales',
  'insights',
  'instagram',
  'integration',
  'integrations',
  'intern',
  'internal',
  'international',
  'interns',
  'internship',
  'invest',
  'investment',
  'investor',
  'investorrelations',
  'investors',
  'invoice',
  'invoices',
  'invoicing',
  'ios',
  'iphone',
  'ir',
  'ispfeedback',
  'ispsupport',
  'it',
  'ithelp',
  'itsupport',
  'itunes',
  'jira',
  'job',
  'jobs',
  'join',
  'la',
  'lab',
  'labs',
  'ladies',
  'latam',
  'launch',
  'lead',
  'leaders',
  'leadership',
  'leadership-team',
  'leadershipteam',
  'leads',
  'legal',
  'list',
  'list-request',
  'login',
  'logistics',
  'lt',
  'lunch',
  'mail',
  'maildaemon',
  'mailerdaemon',
  'mailing',
  'maintenance',
  'management',
  'management-group',
  'management.team',
  'management_team',
  'manager',
  'managers',
  'marketing',
  'marketing-ops',
  'marketing-team',
  'marketingteam',
  'marketplace',
  'master',
  'md',
  'media',
  'meetup',
  'member',
  'members',
  'membership',
  'mentors',
  'metrics',
  'mgmt',
  'middleschool',
  'misc',
  'mkt',
  'mktg',
  'mobile',
  'monitor',
  'monitoring',
  'montreal',
  'msstaff',
  'msteachers',
  'mt',
  'music',
  'network',
  'newbiz',
  'newbusiness',
  'news',
  'newsletter',
  'newyork',
  'nntp',
  'no-reply',
  'no.replay',
  'no.reply',
  'noc',
  'noreply',
  'noresponse',
  'northamerica',
  'notes',
  'notifications',
  'notify',
  'nps',
  'null',
  'ny',
  'nyc',
  'nyoffice',
  'offboarding',
  'offers',
  'office',
  'officeadmin',
  'officers',
  'officestaff',
  'offtopic',
  'onboarding',
  'online',
  'onsite',
  'ooo',
  'operations',
  'ops',
  'order',
  'orders',
  'outage',
  'outreach',
  'owners',
  'parents',
  'paris',
  'partner',
  'partners',
  'partnerships',
  'pay',
  'payment',
  'payments',
  'paypal',
  'payroll',
  'pd',
  'people',
  'peoplemanagers',
  'peopleops',
  'performance',
  'phish',
  'phishing',
  'photos',
  'platform',
  'pm',
  'portfolio',
  'post',
  'postbox',
  'postfix',
  'postmaster',
  'ppc',
  'pr',
  'presales',
  'press',
  'presse',
  'prime',
  'principal',
  'principals',
  'privacy',
  'prod',
  'product',
  'product-team',
  'product.growth',
  'product.management',
  'product.managers',
  'product.team',
  'production',
  'productmanagers',
  'products',
  'productteam',
  'produto',
  'program',
  'programs',
  'projectmanagers',
  'projects',
  'promo',
  'publishers',
  'purchasing',
  'qa',
  'questions',
  'random',
  'realestate',
  'receipts',
  'reception',
  'recruit',
  'recruiters',
  'recruiting',
  'recruitment',
  'recrutement',
  'referrals',
  'registrar',
  'release',
  'releases',
  'remote',
  'remove',
  'report',
  'reporting',
  'reports',
  'request',
  'requests',
  'research',
  'residents',
  'retail',
  'revenue',
  'rfp',
  'rnd',
  'rockstars',
  'root',
  'rrhh',
  'rsvp',
  'sales',
  'sales-team',
  'sales.team',
  'salesengineers',
  'salesforce',
  'salesops',
  'salesteam',
  'sanfrancisco',
  'school',
  'schooloffice',
  'science',
  'sdr',
  'se',
  'search',
  'seattle',
  'secretary',
  'security',
  'sem',
  'seniors',
  'seo',
  'server',
  'service',
  'services',
  'sf',
  'sf-office',
  'sfo',
  'sfoffice',
  'sfteam',
  'shareholders',
  'shipping',
  'shop',
  'shopify',
  'shopping',
  'signup',
  'signups',
  'singapore',
  'sistemas',
  'site',
  'smtp',
  'social',
  'socialclub',
  'socialmedia',
  'socios',
  'software',
  'solutions',
  'sos',
  'spam',
  'squad',
  'staff',
  'startups',
  'stats',
  'stockholm',
  'store',
  'stories',
  'strategy',
  'stripe',
  'student',
  'students',
  'studio',
  'submissions',
  'subscribe',
  'subscriptions',
  'success',
  'suggestions',
  'supervisors',
  'suporte',
  'supply',
  'support',
  'support-team',
  'supportteam',
  'sydney',
  'sysadmin',
  'system',
  'systems',
  'ta',
  'talent',
  'teachers',
  'team',
  'teamleaders',
  'teamleads',
  'tech',
  'technical',
  'technology',
  'techops',
  'techsupport',
  'techteam',
  'tecnologia',
  'test',
  'testgroup',
  'testing',
  'theoffice',
  'theteam',
  'time',
  'timesheets',
  'todos',
  'tools',
  'trade',
  'trainers',
  'training',
  'travel',
  'tribe',
  'trustees',
  'twitter',
  'uk',
  'undisclosed-recipients',
  'unsubscribe',
  'update',
  'updates',
  'us',
  'usa',
  'usenet',
  'users',
  'usteam',
  'uucp',
  'ux',
  'vendor',
  'vendors',
  'ventas',
  'video',
  'vip',
  'voicemail',
  'volunteer',
  'volunteers',
  'warehouse',
  'watercooler',
  'web',
  'webadmin',
  'webdev',
  'webinars',
  'webmaster',
  'website',
  'webteam',
  'welcome',
  'whois',
  'women',
  'wordpress',
  'work',
  'writers',
  'www'
];

<commit_msg>Added new entries<commit_after>module.exports = [
  '2015',
  '2016',
  '2017',
  '2018',
  '2019',
  '2020',
  'abuse',
  'academy',
  'accessibility',
  'account',
  'accountant',
  'accounting',
  'accountmanagers',
  'accounts',
  'accountspayable',
  'acquisition',
  'admin',
  'admin1',
  'administracao',
  'administracion',
  'administrador',
  'administratie',
  'administratif',
  'administration',
  'administrativo',
  'administrator',
  'administrators',
  'admins',
  'adminteam',
  'admissions',
  'adops',
  'ads',
  'adventure',
  'advertise',
  'advertising',
  'advertisingsales',
  'advice',
  'advisor',
  'advisors',
  'adwords',
  'affiliate',
  'affiliates',
  'agence',
  'agencia',
  'agency',
  'agents',
  'alarm',
  'alarms',
  'alert',
  'alerts',
  'alexa',
  'all',
  'all-employees',
  'all-pms',
  'all-staff',
  'all-team',
  'all-users',
  'all.employees',
  'all.staff',
  'all.users',
  'all_staff',
  'alla',
  'alle',
  'allemployees',
  'allhands',
  'allsales',
  'allstaff',
  'allstudents',
  'allteachers',
  'allteam',
  'allusers',
  'alpha',
  'alphas',
  'alumni',
  'ambassadors',
  'amministrazione',
  'analysts',
  'analytics',
  'android',
  'angels',
  'animation',
  'announce',
  'announcements',
  'ap',
  'api',
  'app',
  'apple',
  'application',
  'applications',
  'apply',
  'appointments',
  'apps',
  'archives',
  'asistente',
  'asset',
  'assistanthead',
  'assistencia',
  'assistenza',
  'associates',
  'associates-all',
  'ateam',
  'atencionalcliente',
  'atendimento',
  'auctions',
  'available',
  'backend',
  'backend-dev',
  'backup',
  'bd',
  'benefits',
  'berlin',
  'bestellung',
  'beta',
  'biblioteca',
  'bibliotheque',
  'billing',
  'bills',
  'biuro',
  'biz',
  'bizdev',
  'blog',
  'board',
  'bod',
  'bookclub',
  'booking',
  'bookings',
  'boston',
  'boxoffice',
  'brand',
  'branding',
  'brands',
  'brandsolutions',
  'broadcast',
  'buchhaltung',
  'bugs',
  'build',
  'bursar',
  'busdev',
  'business',
  'business_team',
  'businessdevelopment',
  'ca',
  'caltrain',
  'campaign',
  'campaigns',
  'campusteam',
  'capacitacion',
  'captain',
  'captains',
  'care',
  'career',
  'careers',
  'catering',
  'central',
  'centro',
  'ceo',
  'ceos',
  'channel-sales',
  'chat',
  'chatter',
  'chef',
  'chicago',
  'china',
  'citymanagers',
  'classof2016',
  'classof2017',
  'classof2018',
  'classof2019',
  'classroom_teachers',
  'client',
  'clientes',
  'clients',
  'clientservices',
  'clinic',
  'cloud',
  'cm',
  'co-op',
  'coach',
  'coaches',
  'coaching',
  'code',
  'colaboradores',
  'colegio',
  'com',
  'comenzi',
  'comercial',
  'comercial1',
  'comercial2',
  'comments',
  'commercial',
  'commerciale',
  'commissions',
  'committee',
  'comms',
  'communication',
  'communications',
  'community',
  'community',
  'company',
  'company.wide',
  'compete',
  'competition',
  'compliance',
  'compras',
  'compta',
  'comptabilite',
  'comunicacao',
  'comunicacion',
  'comunicaciones',
  'comunicazione',
  'concierge',
  'conference',
  'connect',
  'consultant',
  'consultas',
  'consulting',
  'consultoria',
  'contabil',
  'contabilidad',
  'contabilidade',
  'contabilita',
  'contact',
  'contactenos',
  'contacto',
  'contactus',
  'contador',
  'contato',
  'content',
  'contractor',
  'contractors',
  'contracts',
  'controller',
  'coordinator',
  'copyright',
  'core',
  'coreteam',
  'corp',
  'corporate',
  'corporatesales',
  'council',
  'courrier',
  'creative',
  'crew',
  'crm',
  'cs',
  'csm',
  'csteam',
  'cultura',
  'culture',
  'customer',
  'customer.service',
  'customercare',
  'customerfeedback',
  'customers',
  'customerservice',
  'customerservicecenter',
  'customerservices',
  'customersuccess',
  'customersupport',
  'custserv',
  'daemon',
  'data',
  'database',
  'deals',
  'dean',
  'delivery',
  'demo',
  'denver',
  'departures',
  'deploy',
  'deputy',
  'deputyhead',
  'design',
  'designer',
  'designers',
  'dev',
  'developer',
  'developers',
  'development',
  'devnull',
  'devops',
  'devs',
  'devteam',
  'digital',
  'digsitesvalue',
  'direccion',
  'direction',
  'director',
  'directors',
  'directory',
  'diretoria',
  'direzione',
  'discuss',
  'dispatch',
  'diversity',
  'dns',
  'docs',
  'domain',
  'domainmanagement',
  'domains',
  'download',
  'dreamteam',
  'ecommerce',
  'editor',
  'editorial',
  'editors',
  'education',
  'einkauf',
  'email',
  'emergency',
  'employee',
  'employees',
  'employment',
  'eng',
  'eng-all',
  'engagement',
  'engineering',
  'engineers',
  'english',
  'enq',
  'enquire',
  'enquires',
  'enquiries',
  'enquiry',
  'enterprise',
  'equipe',
  'equipo',
  'error',
  'errors',
  'escritorio',
  'europe',
  'event',
  'events',
  'everybody',
  'everyone',
  'exec',
  'execs',
  'execteam',
  'executive',
  'executives',
  'expenses',
  'expert',
  'experts',
  'export',
  'facilities',
  'facturacion',
  'faculty',
  'family',
  'farmacia',
  'faturamento',
  'fax',
  'fbl',
  'feedback',
  'fellows',
  'finance',
  'financeiro',
  'financeiro2',
  'finanzas',
  'firmapost',
  'fiscal',
  'food',
  'football',
  'founders',
  'france',
  'franchise',
  'friends',
  'frontdesk',
  'frontend',
  'frontoffice',
  'fte',
  'ftp',
  'fulltime',
  'fun',
  'fundraising',
  'gardner',
  'geeks',
  'general',
  'geral',
  'global',
  'grants',
  'graphics',
  'group',
  'growth',
  'hackathon',
  'hackers',
  'head',
  'head.office',
  'headoffice',
  'heads',
  'headteacher',
  'hello',
  'help',
  'helpdesk',
  'hi',
  'highschool',
  'hiring',
  'hola',
  'home',
  'homes',
  'hosting',
  'hostmaster',
  'hotel',
  'house',
  'hq',
  'hr',
  'hrdept',
  'hsstaff',
  'hsteachers',
  'humanresources',
  'ideas',
  'implementation',
  'import',
  'inbound',
  'inbox',
  'india',
  'info',
  'infor',
  'informacion',
  'informatica',
  'information',
  'informatique',
  'informativo',
  'infra',
  'infrastructure',
  'ingenieria',
  'innovation',
  'inoc',
  'inquiries',
  'inquiry',
  'insidesales',
  'insights',
  'instagram',
  'insurance',
  'integration',
  'integrations',
  'intern',
  'internal',
  'international',
  'internet',
  'interns',
  'internship',
  'invest',
  'investment',
  'investor',
  'investorrelations',
  'investors',
  'invoice',
  'invoices',
  'invoicing',
  'ios',
  'iphone',
  'ir',
  'ispfeedback',
  'ispsupport',
  'it',
  'ithelp',
  'itsupport',
  'itunes',
  'jira',
  'job',
  'jobs',
  'join',
  'jornalismo',
  'junk',
  'kontakt',
  'kundeservice',
  'la',
  'lab',
  'laboratorio',
  'labs',
  'ladies',
  'latam',
  'launch',
  'lead',
  'leaders',
  'leadership',
  'leadership-team',
  'leadershipteam',
  'leads',
  'leasing',
  'legal',
  'letters',
  'library',
  'licensing',
  'links',
  'list',
  'list-request',
  'login',
  'logistica',
  'logistics',
  'logistiek',
  'lt',
  'lunch',
  'mail',
  'mailbox',
  'maildaemon',
  'mailer-daemon',
  'mailerdaemon',
  'mailing',
  'maintenance',
  'management',
  'management-group',
  'management.team',
  'management_team',
  'manager',
  'managers',
  'marketing',
  'marketing-ops',
  'marketing-team',
  'marketingteam',
  'marketplace',
  'master',
  'mayor',
  'md',
  'media',
  'meetup',
  'member',
  'members',
  'membership',
  'mentors',
  'metrics',
  'mgmt',
  'middleschool',
  'misc',
  'mkt',
  'mktg',
  'mobile',
  'monitor',
  'monitoring',
  'montreal',
  'msstaff',
  'msteachers',
  'mt',
  'music',
  'network',
  'newbiz',
  'newbusiness',
  'news',
  'newsletter',
  'newyork',
  'nntp',
  'no-reply',
  'no.replay',
  'no.reply',
  'nobody',
  'noc',
  'none',
  'noreply',
  'noresponse',
  'northamerica',
  'nospam',
  'notes',
  'notifications',
  'notify',
  'nps',
  'null',
  'ny',
  'nyc',
  'nyoffice',
  'offboarding',
  'offers',
  'office',
  'officeadmin',
  'officemanager',
  'officers',
  'officestaff',
  'offtopic',
  'oficina',
  'onboarding',
  'online',
  'onsite',
  'ooo',
  'operaciones',
  'operations',
  'ops',
  'order',
  'orders',
  'ordini',
  'outage',
  'outreach',
  'owners',
  'parents',
  'paris',
  'partner',
  'partners',
  'partnerships',
  'parts',
  'pay',
  'payment',
  'payments',
  'paypal',
  'payroll',
  'pd',
  'people',
  'peoplemanagers',
  'peopleops',
  'performance',
  'personnel',
  'phish',
  'phishing',
  'photos',
  'planning',
  'platform',
  'pm',
  'portfolio',
  'post',
  'postbox',
  'postfix',
  'postmaster',
  'ppc',
  'pr',
  'prefeitura',
  'presales',
  'presidencia',
  'president',
  'presidente',
  'press',
  'presse',
  'prime',
  'principal',
  'principals',
  'privacy',
  'procurement',
  'prod',
  'produccion',
  'product',
  'product-team',
  'product.growth',
  'product.management',
  'product.managers',
  'product.team',
  'production',
  'productmanagers',
  'products',
  'productteam',
  'produto',
  'program',
  'programs',
  'project',
  'projectmanagers',
  'projects',
  'promo',
  'promotions',
  'protocollo',
  'proveedores',
  'publicidade',
  'publisher',
  'publishers',
  'purchase',
  'purchases',
  'purchasing',
  'qa',
  'qualidade',
  'questions',
  'quotes',
  'random',
  'realestate',
  'receipts',
  'recepcion',
  'reception',
  'receptionist',
  'recruit',
  'recruiter',
  'recruiters',
  'recruiting',
  'recruitment',
  'recrutement',
  'recursoshumanos',
  'redacao',
  'redaccion',
  'redaction',
  'redazione',
  'referrals',
  'register',
  'registrar',
  'registration',
  'relacionamento',
  'release',
  'releases',
  'remote',
  'remove',
  'rentals',
  'report',
  'reporting',
  'reports',
  'request',
  'requests',
  'research',
  'reservaciones',
  'reservas',
  'reservation',
  'reservations',
  'residents',
  'response',
  'restaurant',
  'resume',
  'resumes',
  'retail',
  'returns',
  'revenue',
  'rezervari',
  'rfp',
  'rnd',
  'rockstars',
  'root',
  'rrhh',
  'rsvp',
  'sales',
  'sales-team',
  'sales.team',
  'sales1',
  'sales2',
  'salesengineers',
  'salesforce',
  'salesops',
  'salesteam',
  'sanfrancisco',
  'school',
  'schooloffice',
  'science',
  'sdr',
  'se',
  'search',
  'seattle',
  'secretaria',
  'secretariaat',
  'secretaris',
  'secretary',
  'security',
  'sekretariat',
  'sem',
  'seniors',
  'seo',
  'server',
  'service',
  'serviceclient',
  'servicedesk',
  'services',
  'servicioalcliente',
  'sf',
  'sf-office',
  'sfo',
  'sfoffice',
  'sfteam',
  'shareholders',
  'shipping',
  'shop',
  'shopify',
  'shopping',
  'signup',
  'signups',
  'singapore',
  'sistemas',
  'site',
  'smtp',
  'social',
  'socialclub',
  'socialmedia',
  'socios',
  'software',
  'solutions',
  'soporte',
  'sos',
  'spam',
  'sponsorship',
  'sport',
  'squad',
  'staff',
  'startups',
  'stats',
  'stockholm',
  'store',
  'stories',
  'strategy',
  'stripe',
  'student',
  'students',
  'studio',
  'submissions',
  'submit',
  'subscribe',
  'subscriptions',
  'success',
  'suggestions',
  'supervisor',
  'supervisors',
  'suporte',
  'supply',
  'support',
  'support-team',
  'supportteam',
  'suprimentos',
  'sydney',
  'sysadmin',
  'system',
  'systems',
  'ta',
  'talent',
  'tax',
  'teachers',
  'team',
  'teamleaders',
  'teamleads',
  'tech',
  'technical',
  'technik',
  'technology',
  'techops',
  'techsupport',
  'techteam',
  'tecnologia',
  'tesoreria',
  'test',
  'testgroup',
  'testing',
  'the.principal',
  'theoffice',
  'theteam',
  'tickets',
  'time',
  'timesheets',
  'todos',
  'tools',
  'tour',
  'trade',
  'trainers',
  'training',
  'transport',
  'travel',
  'treasurer',
  'tribe',
  'trustees',
  'turismo',
  'twitter',
  'uk',
  'undisclosed-recipients',
  'unsubscribe',
  'update',
  'updates',
  'us',
  'usa',
  'usenet',
  'user',
  'users',
  'usteam',
  'uucp',
  'ux',
  'vendas',
  'vendas1',
  'vendas2',
  'vendor',
  'vendors',
  'ventas',
  'ventas1',
  'ventas2',
  'verkauf',
  'verwaltung',
  'video',
  'vip',
  'voicemail',
  'volunteer',
  'volunteers',
  'vorstand',
  'warehouse',
  'watercooler',
  'web',
  'webadmin',
  'webdesign',
  'webdev',
  'webinars',
  'webmaster',
  'website',
  'webteam',
  'welcome',
  'whois',
  'wholesale',
  'women',
  'wordpress',
  'work',
  'workshop',
  'writers',
  'www',
  'zentrale'
];

<|endoftext|>