<commit_before>var express = require('express');
var app     = express();
var pak     = require('./package.json');
var Client  = require('node-rest-client').Client;
var client  = new Client();
var year    = new Date().getFullYear();
var envic   = require('envic')

var shortIt = {
	company:    process.env.COMPANY       || process.env.NAME || process.env.APPNAME || pak.name,
	domain:     process.env.DOMAIN        || process.env.NAME || process.env.APPNAME || pak.name,
	name:       process.env.APPNAME       || pak.name,
	version:    process.env.APPVERSION    || pak.version,
	url:        process.env.URL           || 'https://github.com/yieme/shortit',
	year:       process.env.YEAR          || (year > 2015) ? '2015-' + year : year,
	logoUrl:    process.env.LOGO_URL      || 'logo.png',
	faviconUrl: process.env.FAVICON_URL   || 'favicon.png',
	nopowered:  process.env.NO_POWERED_BY || false,
	headCode:   process.env.HEADCODE      || '',
	bodyCode:   process.env.BODYCODE      || '',
	header1:    process.env.HEADERNAM     || false,
	value1:     process.env.HEADERVAL     || false,
	header2:    process.env.HEADERNAM2    || false,
	value2:     process.env.HEADERVAL2    || false,
	server:     process.env.SERVER        || false
};

shortIt.nameVersion = shortIt.name + '/' + shortIt.version
var conPassThru    = process.env.CONSOLE_PASSTHRU // console pass-thru
var logPassThru    = process.env.LOG_PASSTHRU
var passThruReturn = process.env.PASSTHRU_MESSAGE || '{ok:1}'
var passThruMaxLen = (process.env.PASSTHRU_MAXLEN) ? parseInt(process.env.PASSTHRU_MAXLEN) : 0 // maximum length of pass-thru string
var footerLinks = '';
var buttonLinks = '';
var shorts  = require('./shorts.json');
var fs      = require('fs')
var gaTxt   = fs.readFileSync('./templates/ga.js')
var gaid    = envic('GA Id')
if (gaid) {
	gaTxt = gaTxt.replace('$GAID', gaid)
}
console.log('gaid:', gaid,'-',process.env.GA_ID)
var shortsDataUrl = process.env.DATA_URL;
app.set('port', (process.env.PORT || 5000));
var template      = '

$msg';
var home          = '$company uses the $domain domain as part of a service to protect users from harmful activity, to provide value for the developer ecosystem, and as a quality signal for surfacing interesting events.';
var msg404        = 'Sorry, page not found';
var lastUpdate    = 0;
var started       = +new Date();
var refreshWait   = 5000; // 5 seconds between refresh requests
var reloadFrequency = process.env.RELOAD || 24*60*60*1000; /// daily default
var stats         = {};
//var Logger        = require('le_node');
var winston    = require('winston')
var logentriesConfig = {
	token:      process.env.LOGENTRIES,
	bufferSize: process.env.LOGENTRIES_BUFFER || 100,
	secure:     1,
	'console':  1
};
var logger      = new winston.Logger()
logger.add(winston.transports.Console)
if (logentriesConfig.token) {
	console.log('Log transport: LogEntries')
	var Logentries = require('winston-logentries')
	logger.add(new winston.transports.Logentries(logentriesConfig))
}
var logUrl = envic('LOG_URL')
if (logUrl) {
	console.log('Log transport: Http', logUrl.host)
	logger.add( winston.transports.Http, logUrl )
}
var log = {
	info:    (logentriesConfig.token) ? function(m) { logger.log('info',    m)} : console.log,
	warning: (logentriesConfig.token) ? function(m) { logger.log('warning', m)} : console.warn,
	error:   (logentriesConfig.token) ? function(m) { logger.log('error',   m)} : console.error
}

var logFirebase = envic('LOG_FIREBASE')
var firelogRef
if (logFirebase) {
	console.log('Log transport: Http', logFirebase.url)
	var Firebase = require('firebase');
	var firelogRef = new Firebase(logFirebase.url);
	firelogRef.auth(logFirebase.token, function(error, result) {
	  if (error) {
	    console.log("Firebase Authentication Failed!", error);
			firelogRef = undefined
	  } else {
	    console.log("Firebase Authenticated successfully with payload:", result.auth);
	    console.log("Firebase Auth expires at:", new Date(result.expires * 1000));
	  }
	})
}

var favicon_png   = '';
var logo_png      = '';

app.use(function customHeaders( req, res, next ){
  // Switch off the default 'X-Powered-By: Express' header
	if (shortIt.nopowered) {
		app.disable( 'x-powered-by' );
	} else {
  	res.setHeader( 'X-Powered-By', shortIt.nameVersion);
	}
	if (shortIt.server)  res.setHeader('Server', shortIt.server)
	if (shortIt.header1) res.setHeader(shortIt.header1, shortIt.value1)
	if (shortIt.header2) res.setHeader(shortIt.header2, shortIt.value2)
  next()
})

function bump(area) {
	var now   = new Date();
	var year  = now.getFullYear();
	var month = now.getMonth() + 1;
	month     = (month<=9) ? '0' + month : ''+ month;
	var day   = now.getDate();
	day       = (day <= 9) ? '0' + day : '' + day;
	var stat  = stats[area] || {};
	stat.tdd = stat.tdd || 0;
	stat.tdd++;
	stat[year]     = stat[year]     || {};
	stat[year].ytd = stat[year].ytd || 0;
	stat[year].ytd++;
	stat[year][month]      = stat[year][month]      || {};
	stat[year][month].mtd  = stat[year][month].mtd  || 0;
	stat[year][month].mtd++;
	stat[year][month][day] = stat[year][month][day] || 0;
	stat[year][month][day]++;
	stats[area] = stat;
}

function duration(val) {
	val = Math.round(val / 1000);
	if (val <= 59) return val + 's';
	val = Math.round(val / 60);
	if (val <= 59) return val + 'm';
	val = Math.round(val / 60);
	if (val <= 23) return val + 'h';
	val = Math.round(val / 24);
	return val + 'd';
}

function getShorts() {
	var now       = +new Date();
	var timeDelta = now - lastUpdate;
	if (timeDelta > refreshWait) {
		lastUpdate  = now;
		if (shortsDataUrl) {
			client.get(shortsDataUrl, function(data, response){
				log.info(shortsDataUrl +   ' loaded at: ' + new Date().toString());
				var parsed = JSON.parse(data);
				shorts     = parsed;
			});
		} else {
			log.error('DATA_URL not defined');
		}
	}
}

function sendJson(res, obj) {
	res.type('json');
	obj = obj || {};
	var json = JSON.stringify(obj, null, 2);
	res.send(json);
}

function notFound(res, short) {
	bump('_404');
	log.warning('/' + short + ' Not Found');
	if (shorts._404) return doShort('_404', res);
	render(res, '_404', msg404.replace('$short', short));
	res.status(404);
}

function doShort(short, res) {
	var url   = shorts[short];
	if (url) {
		url = url.url || url; // support firebase short: { id: short, url: url } formatted data
		res.redirect(302, url);
		log.info(short + ': ' + url);
		bump(short);
	} else {
		notFound(res, short);
	}
}

function render(res, name, $msg) {
	var result = template.replace('$msg', $msg);
	for(var max=10; max>0 && result.indexOf('$') >= 0; max--) {
		result = result
			.replace('$company',     shortIt.company)
			.replace('$url',         shortIt.url)
			.replace('$domain',      shortIt.domain)
			.replace('$year',        shortIt.year)
			.replace('$logoUrl',     shortIt.logoUrl)
			.replace('$faviconUrl',  shortIt.faviconUrl)
			.replace('$packageName', shortIt.name)
			.replace('$packageVer',  shortIt.version)
			.replace('$headCode',    shortIt.headCode)
			.replace('$bodyCode',    shortIt.bodyCode)
			.replace('$buttonLinks', buttonLinks)
			.replace('$footerLinks', footerLinks)
		;
	}
	res.send(result);
	bump(name);
	log.info('/' + name);
}

function renderPng(res, name, img) {
	res.type('png');
	res.send(img);
	name = name + '.png';
	bump(name);
	log.info('/' + name);
}

app.get('/favicon.png', function (req, res) {
	renderPng(res, 'favicon', favicon);
});

app.get('/logo.png', function (req, res) {
	renderPng(res, 'logo', logo);
});

app.get('/', function (req, res) {
	if (shorts._home) return doShort('_home', res);
	render(res, '_home', process.env.MESSAGE || home);
});

app.get('/_reload', function (req, res) {
	render(res, '_reload', 'Reload done.');
	getShorts();
});

app.get('/_stats', function (req, res) {
	bump('_stats');
	stats._running = duration(+new Date() - started);
	stats._updated = duration(+new Date() - lastUpdate);
	sendJson(res, stats);
	log.info('/_stats ' + JSON.stringify(stats));
});

app.get('/_stats/:short', function (req, res) {
	bump('_stats/*');
	sendJson(res, stats[req.params.short]);
	log.info('/_stats/' + req.params.short);
});

String.prototype.replaceIgnoreCase = function(strReplace, strWith) {
    var reg = new RegExp(strReplace, 'i'); // i=ignore case, g=global (ie all)
    return this.replace(reg, strWith);
};

if (conPassThru) { // console pass-thru
	app.get(conPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(conPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		console.log('data', data);
		res.send(passThruReturn)
	});
}

if (logPassThru) {
	app.get(logPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(logPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		log.info(data);
		if (firelogRef) {
			firelogRef.push(data)
		}
		res.send(passThruReturn)
	});
}

app.get('/:short', function (req, res) {
	doShort(req.params.short, res);
});

var server = app.listen(app.get('port'), function () {
  var host = server.address().address;
  var port = server.address().port;
  log.info(pak.name + ' ' + pak.version + ' listening on: ' + host + ' port: ' + port + ' at: ' + new Date().toString());
	if (!process.env.COMPANY) {
		log.warning('COMPANY not defined');
	}
	if (!process.env.DOMAIN) {
		log.warning('DOMAIN not defined');
	}
	if (!process.env.URL) {
		log.warning('URL not defined');
	}
});

function loadFile(path, cb) {
	fs.readFile('./' + path, 'utf8', function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		data = data.replace('$analytics', (gaid) ? gaTxt : '')
		cb(data);
	});
}

function loadTemplate(name, cb) {
	loadFile('./templates/' + name + '.html', cb);
}

function loadPng(path, cb) {
	fs.readFile('./' + path, function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		cb(data);
	});
}

loadTemplate('index', function(data) {
	template = data || '';
});
loadTemplate('home', function(data) {
	home = data || '';
});
loadTemplate('404', function(data) {
	msg404 = data || '';
});
loadTemplate('footerLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['FOOTER'+i]) {
			footerLinks += data
				.replace('$url',  process.env[ 'FOOTER_URL' + i ])
				.replace('$text', process.env[ 'FOOTER'     + i ])
			;
		}
	}
});
loadTemplate('buttonLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['BUTTON'+i]) {
			buttonLinks += data
				.replace('$url',  process.env[ 'BUTTON_URL' + i ])
				.replace('$text', process.env[ 'BUTTON'     + i ])
			;
		}
	}
});
loadPng('favicon.png', function(data) {
	favicon = data || null;
});
loadPng('logo.png', function(data) {
	logo = data || null;
});

getShorts();
setInterval(getShorts, reloadFrequency);
<commit_msg>security fix, default PASSTHRU_MAX 255<commit_after>var express = require('express');
var app     = express();
var pak     = require('./package.json');
var Client  = require('node-rest-client').Client;
var client  = new Client();
var year    = new Date().getFullYear();
var envic   = require('envic')

var shortIt = {
	company:    process.env.COMPANY       || process.env.NAME || process.env.APPNAME || pak.name,
	domain:     process.env.DOMAIN        || process.env.NAME || process.env.APPNAME || pak.name,
	name:       process.env.APPNAME       || pak.name,
	version:    process.env.APPVERSION    || pak.version,
	url:        process.env.URL           || 'https://github.com/yieme/shortit',
	year:       process.env.YEAR          || (year > 2015) ? '2015-' + year : year,
	logoUrl:    process.env.LOGO_URL      || 'logo.png',
	faviconUrl: process.env.FAVICON_URL   || 'favicon.png',
	nopowered:  process.env.NO_POWERED_BY || false,
	headCode:   process.env.HEADCODE      || '',
	bodyCode:   process.env.BODYCODE      || '',
	header1:    process.env.HEADERNAM     || false,
	value1:     process.env.HEADERVAL     || false,
	header2:    process.env.HEADERNAM2    || false,
	value2:     process.env.HEADERVAL2    || false,
	server:     process.env.SERVER        || false
};

shortIt.nameVersion = shortIt.name + '/' + shortIt.version
var conPassThru    = process.env.CONSOLE_PASSTHRU // console pass-thru
var logPassThru    = process.env.LOG_PASSTHRU
var passThruReturn = process.env.PASSTHRU_MESSAGE || '{ok:1}'
var passThruMaxLen = (process.env.PASSTHRU_MAXLEN) ? parseInt(process.env.PASSTHRU_MAXLEN) : 255 // maximum length of pass-thru string
var footerLinks = '';
var buttonLinks = '';
var shorts  = require('./shorts.json');
var fs      = require('fs')
var gaTxt   = fs.readFileSync('./templates/ga.js')
var gaid    = envic('GA Id')
if (gaid) {
	gaTxt = gaTxt.replace('$GAID', gaid)
}
console.log('gaid:', gaid,'-',process.env.GA_ID)
var shortsDataUrl = process.env.DATA_URL;
app.set('port', (process.env.PORT || 5000));
var template      = '

$msg';
var home          = '$company uses the $domain domain as part of a service to protect users from harmful activity, to provide value for the developer ecosystem, and as a quality signal for surfacing interesting events.';
var msg404        = 'Sorry, page not found';
var lastUpdate    = 0;
var started       = +new Date();
var refreshWait   = 5000; // 5 seconds between refresh requests
var reloadFrequency = process.env.RELOAD || 24*60*60*1000; /// daily default
var stats         = {};
//var Logger        = require('le_node');
var winston    = require('winston')
var logentriesConfig = {
	token:      process.env.LOGENTRIES,
	bufferSize: process.env.LOGENTRIES_BUFFER || 100,
	secure:     1,
	'console':  1
};
var logger      = new winston.Logger()
logger.add(winston.transports.Console)
if (logentriesConfig.token) {
	console.log('Log transport: LogEntries')
	var Logentries = require('winston-logentries')
	logger.add(new winston.transports.Logentries(logentriesConfig))
}
var logUrl = envic('LOG_URL')
if (logUrl) {
	console.log('Log transport: Http', logUrl.host)
	logger.add( winston.transports.Http, logUrl )
}
var log = {
	info:    (logentriesConfig.token) ? function(m) { logger.log('info',    m)} : console.log,
	warning: (logentriesConfig.token) ? function(m) { logger.log('warning', m)} : console.warn,
	error:   (logentriesConfig.token) ? function(m) { logger.log('error',   m)} : console.error
}

var logFirebase = envic('LOG_FIREBASE')
var firelogRef
if (logFirebase) {
	console.log('Log transport: Http', logFirebase.url)
	var Firebase = require('firebase');
	var firelogRef = new Firebase(logFirebase.url);
	firelogRef.auth(logFirebase.token, function(error, result) {
	  if (error) {
	    console.log("Firebase Authentication Failed!", error);
			firelogRef = undefined
	  } else {
	    console.log("Firebase Authenticated successfully with payload:", result.auth);
	    console.log("Firebase Auth expires at:", new Date(result.expires * 1000));
	  }
	})
}

var favicon_png   = '';
var logo_png      = '';

app.use(function customHeaders( req, res, next ){
  // Switch off the default 'X-Powered-By: Express' header
	if (shortIt.nopowered) {
		app.disable( 'x-powered-by' );
	} else {
  	res.setHeader( 'X-Powered-By', shortIt.nameVersion);
	}
	if (shortIt.server)  res.setHeader('Server', shortIt.server)
	if (shortIt.header1) res.setHeader(shortIt.header1, shortIt.value1)
	if (shortIt.header2) res.setHeader(shortIt.header2, shortIt.value2)
  next()
})

function bump(area) {
	var now   = new Date();
	var year  = now.getFullYear();
	var month = now.getMonth() + 1;
	month     = (month<=9) ? '0' + month : ''+ month;
	var day   = now.getDate();
	day       = (day <= 9) ? '0' + day : '' + day;
	var stat  = stats[area] || {};
	stat.tdd = stat.tdd || 0;
	stat.tdd++;
	stat[year]     = stat[year]     || {};
	stat[year].ytd = stat[year].ytd || 0;
	stat[year].ytd++;
	stat[year][month]      = stat[year][month]      || {};
	stat[year][month].mtd  = stat[year][month].mtd  || 0;
	stat[year][month].mtd++;
	stat[year][month][day] = stat[year][month][day] || 0;
	stat[year][month][day]++;
	stats[area] = stat;
}

function duration(val) {
	val = Math.round(val / 1000);
	if (val <= 59) return val + 's';
	val = Math.round(val / 60);
	if (val <= 59) return val + 'm';
	val = Math.round(val / 60);
	if (val <= 23) return val + 'h';
	val = Math.round(val / 24);
	return val + 'd';
}

function getShorts() {
	var now       = +new Date();
	var timeDelta = now - lastUpdate;
	if (timeDelta > refreshWait) {
		lastUpdate  = now;
		if (shortsDataUrl) {
			client.get(shortsDataUrl, function(data, response){
				log.info(shortsDataUrl +   ' loaded at: ' + new Date().toString());
				var parsed = JSON.parse(data);
				shorts     = parsed;
			});
		} else {
			log.error('DATA_URL not defined');
		}
	}
}

function sendJson(res, obj) {
	res.type('json');
	obj = obj || {};
	var json = JSON.stringify(obj, null, 2);
	res.send(json);
}

function notFound(res, short) {
	bump('_404');
	log.warning('/' + short + ' Not Found');
	if (shorts._404) return doShort('_404', res);
	render(res, '_404', msg404.replace('$short', short));
	res.status(404);
}

function doShort(short, res) {
	var url   = shorts[short];
	if (url) {
		url = url.url || url; // support firebase short: { id: short, url: url } formatted data
		res.redirect(302, url);
		log.info(short + ': ' + url);
		bump(short);
	} else {
		notFound(res, short);
	}
}

function render(res, name, $msg) {
	var result = template.replace('$msg', $msg);
	for(var max=10; max>0 && result.indexOf('$') >= 0; max--) {
		result = result
			.replace('$company',     shortIt.company)
			.replace('$url',         shortIt.url)
			.replace('$domain',      shortIt.domain)
			.replace('$year',        shortIt.year)
			.replace('$logoUrl',     shortIt.logoUrl)
			.replace('$faviconUrl',  shortIt.faviconUrl)
			.replace('$packageName', shortIt.name)
			.replace('$packageVer',  shortIt.version)
			.replace('$headCode',    shortIt.headCode)
			.replace('$bodyCode',    shortIt.bodyCode)
			.replace('$buttonLinks', buttonLinks)
			.replace('$footerLinks', footerLinks)
		;
	}
	res.send(result);
	bump(name);
	log.info('/' + name);
}

function renderPng(res, name, img) {
	res.type('png');
	res.send(img);
	name = name + '.png';
	bump(name);
	log.info('/' + name);
}

app.get('/favicon.png', function (req, res) {
	renderPng(res, 'favicon', favicon);
});

app.get('/logo.png', function (req, res) {
	renderPng(res, 'logo', logo);
});

app.get('/', function (req, res) {
	if (shorts._home) return doShort('_home', res);
	render(res, '_home', process.env.MESSAGE || home);
});

app.get('/_reload', function (req, res) {
	render(res, '_reload', 'Reload done.');
	getShorts();
});

app.get('/_stats', function (req, res) {
	bump('_stats');
	stats._running = duration(+new Date() - started);
	stats._updated = duration(+new Date() - lastUpdate);
	sendJson(res, stats);
	log.info('/_stats ' + JSON.stringify(stats));
});

app.get('/_stats/:short', function (req, res) {
	bump('_stats/*');
	sendJson(res, stats[req.params.short]);
	log.info('/_stats/' + req.params.short);
});

String.prototype.replaceIgnoreCase = function(strReplace, strWith) {
    var reg = new RegExp(strReplace, 'i'); // i=ignore case, g=global (ie all)
    return this.replace(reg, strWith);
};

if (conPassThru) { // console pass-thru
	app.get(conPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(conPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		console.log('data', data);
		res.send(passThruReturn)
	});
}

if (logPassThru) {
	app.get(logPassThru, function (req, res) {
		data = req.originalUrl.replaceIgnoreCase(logPassThru, '')
		if (data.substr(0,1) == '/') data = data.replace('/', '')
		if (data.substr(0,1) == '?') data = data.replace('?', '')
		if (passThruMaxLen && data.length > passThruMaxLen) {
			data = data.substr(0, passThruMaxLen)
		}
		log.info(data);
		if (firelogRef) {
			firelogRef.push(data)
		}
		res.send(passThruReturn)
	});
}

app.get('/:short', function (req, res) {
	doShort(req.params.short, res);
});

var server = app.listen(app.get('port'), function () {
  var host = server.address().address;
  var port = server.address().port;
  log.info(pak.name + ' ' + pak.version + ' listening on: ' + host + ' port: ' + port + ' at: ' + new Date().toString());
	if (!process.env.COMPANY) {
		log.warning('COMPANY not defined');
	}
	if (!process.env.DOMAIN) {
		log.warning('DOMAIN not defined');
	}
	if (!process.env.URL) {
		log.warning('URL not defined');
	}
});

function loadFile(path, cb) {
	fs.readFile('./' + path, 'utf8', function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		data = data.replace('$analytics', (gaid) ? gaTxt : '')
		cb(data);
	});
}

function loadTemplate(name, cb) {
	loadFile('./templates/' + name + '.html', cb);
}

function loadPng(path, cb) {
	fs.readFile('./' + path, function (err, data) {
	  if (data && !err) {
			log.info('Loaded ' + path);
		} else {
			log.warning('Unable to load ' + path);
		}
		cb(data);
	});
}

loadTemplate('index', function(data) {
	template = data || '';
});
loadTemplate('home', function(data) {
	home = data || '';
});
loadTemplate('404', function(data) {
	msg404 = data || '';
});
loadTemplate('footerLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['FOOTER'+i]) {
			footerLinks += data
				.replace('$url',  process.env[ 'FOOTER_URL' + i ])
				.replace('$text', process.env[ 'FOOTER'     + i ])
			;
		}
	}
});
loadTemplate('buttonLink', function(data) {
	data = data || '';
	for (var i=1; i<=9; i++) {
		if (process.env['BUTTON'+i]) {
			buttonLinks += data
				.replace('$url',  process.env[ 'BUTTON_URL' + i ])
				.replace('$text', process.env[ 'BUTTON'     + i ])
			;
		}
	}
});
loadPng('favicon.png', function(data) {
	favicon = data || null;
});
loadPng('logo.png', function(data) {
	logo = data || null;
});

getShorts();
setInterval(getShorts, reloadFrequency);
<|endoftext|>


<commit_before>

//add two buffers,
//putting least significant at left will be simplest.
//iterate over buffers from lsb to msb
//and add each byte & 0xff, carrying overflow.

exports.add = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l);
  c.fill()
  var carry = 0
  for(var i = 0; i < l; i++) {
    var v = (a[i] || 0) + (b[i] || 0) + carry
    c[i] = v & 0xff
    carry = v >> 8
  }
  if(carry) {//check if last item is a carry.
//    var _c = c
//    if(c.length === l) {
//      c = new Buffer(l + 1)
//      _c.copy(c)
//    }
    c[l] = carry
  }
  return c
}

//there are no negatives, so make sure A is larger.
//basically the reverse of add.
exports.sub =
exports.subtract = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l)
  c.fill()
  console.log(a, b, c)
  var carry = 0
  for(var i = 0; i < l; i++) {
    var A = (a[i] || 0), B = (b[i] || 0) + carry
    if(A < B) {
      A += 256
      carry = 1
    } else
      carry = 0
    c[i] = A - B
  }
  return c
}

//mulitply,
//multiplying each pair of places
//and accumulate results in a new buffer.
exports.mul =
exports.multiply = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l)
  c.fill()
  //for each place in A, multiply each place in B,
  //and add it to the running total.
  for(var i = 0; i < b.length; i++) {
    for(var j = 0; j < a.length; j++) {
      var value = b[i] * a[j]
      var current = (c[i + j]||0) + ((c[i + j + 1]<<8) || 0)
      var v = current + value
      c[i + j]     = v & 0xff
      c[1 + i + j] = v >> 8
    }
  }
  return c
}

function readInt(b, n) {
  return b[n] | (b[n + 1]||0)<<8 | (b[n + 2]||0)<<16 | (b[n + 2]||0)<<24
}

// a % n (where n is < 2^31)
// this uses Buffer#readInt32LE
// so, buffers length must be multiple of 4.
exports.modInt = function (a, n, c) {
  var l = a.length
  if(!c) c = new Buffer(l)
  a.copy(c)
  l = l - 4
  do {
    c.writeInt32LE(c.readInt32LE(l) % n, l)
  } while(l--)
  return c
}

//return -1, 0, or 1 if a < b, a == b, a > b
exports.compare = function (a, b) {
  var l = Math.max(a.length, b.length)
  while(l--) {
    if((a[l] || 0) !== (b[l] || 0))
      return a[l] < b[l] ? -1 : 1
  }
  return 0
}
<commit_msg>bitwise shift<commit_after>

//add two buffers,
//putting least significant at left will be simplest.
//iterate over buffers from lsb to msb
//and add each byte & 0xff, carrying overflow.

exports.add = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l);
  c.fill()
  var carry = 0
  for(var i = 0; i < l; i++) {
    var v = (a[i] || 0) + (b[i] || 0) + carry
    c[i] = v & 0xff
    carry = v >> 8
  }
  if(carry) {//check if last item is a carry.
//    var _c = c
//    if(c.length === l) {
//      c = new Buffer(l + 1)
//      _c.copy(c)
//    }
    c[l] = carry
  }
  return c
}

//there are no negatives, so make sure A is larger.
//basically the reverse of add.
exports.sub =
exports.subtract = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l)
  c.fill()
  console.log(a, b, c)
  var carry = 0
  for(var i = 0; i < l; i++) {
    var A = (a[i] || 0), B = (b[i] || 0) + carry
    if(A < B) {
      A += 256
      carry = 1
    } else
      carry = 0
    c[i] = A - B
  }
  return c
}

//mulitply,
//multiplying each pair of places
//and accumulate results in a new buffer.
exports.mul =
exports.multiply = function (a, b, c) {
  var l = Math.max(a.length, b.length)
  if(!c) c = new Buffer(l)
  c.fill()
  //for each place in A, multiply each place in B,
  //and add it to the running total.
  for(var i = 0; i < b.length; i++) {
    for(var j = 0; j < a.length; j++) {
      var value = b[i] * a[j]
      var current = (c[i + j]||0) + ((c[i + j + 1]<<8) || 0)
      var v = current + value
      c[i + j]     = v & 0xff
      c[1 + i + j] = v >> 8
    }
  }
  return c
}

function readInt(b, n) {
  return b[n] | (b[n + 1]||0)<<8 | (b[n + 2]||0)<<16 | (b[n + 2]||0)<<24
}

// a % n (where n is < 2^31)
// this uses Buffer#readInt32LE
// so, buffers length must be multiple of 4.
exports.modInt = function (a, n, c) {
  var l = a.length
  if(!c) c = new Buffer(l)
  a.copy(c)
  l = l - 4
  do {
    c.writeInt32LE(c.readInt32LE(l) % n, l)
  } while(l--)
  return c
}

//return -1, 0, or 1 if a < b, a == b, a > b
exports.compare = function (a, b) {
  var l = Math.max(a.length, b.length)
  while(l--) {
    if((a[l] || 0) !== (b[l] || 0))
      return a[l] < b[l] ? -1 : 1
  }
  return 0
}

exports.shift = function (a, n, c) {
  //if the shift is larger than a byte, iterate.
  if(!c) c = new Buffer(a.length)
  if(Math.abs(n) > 8) throw new Error('not implemented yet')
  var carry = 0
  if(n > 0) {
    for(var i = 0; i < a.length; i++) {
      var v = a[i] << n
      c[i] = v & 0xff | carry
      carry = v >> 8
    }
    c[a.length] = carry
  } else {
    var m = -1*n
    for(var i = a.length; i >= 0; i--) {
      // shift into the second byte,
      // so that we have a chance to grab the carry.
      var v = (a[i] << 8) >> m
      c[i] = v>>8 & 0xff | carry
      carry = v & 0xff
    }
    c[a.length] = carry
  }
  return c
}
<|endoftext|>


<commit_before>// Dependencies
var Request = require("request")
  , Mandrill = require("mandrill-api/mandrill")
  , Config = require("./config")
  , MandrillClient = new Mandrill.Mandrill(Config.mandrillKey)
  , Http = require("http")
  , Url = require("url")
  ;

// The request url where the results are supposed to be posted
const REQ_URL = Config.reqUrl || "http://static.bacalaureat.edu.ro/2014/rapoarte/BH/index.html"

// This becomes `true` once the email is submitted.
var sent = false;

var oldHtml = null
  , newHtml = null
  ;

/**
 * sendEmail
 * Sends the notification email
 *
 * @name sendEmail
 * @function
 * @return
 */
function sendEmail() {
    sent = true;
    MandrillClient.messages.send({
        message: {
            from_email: Config.from.email
          , from_name: Config.from.name
          , to: [
                {
                    email: Config.to.email
                  , name: Config.to.name
                }
            ]
          , subject: Config.subject
          , text: Config.text + "\n\n" + REQ_URL
        }
    }, function(result) {
        console.log(result);
    }, function (error) {
        console.log(error);
    });
}

function checkUrl() {
    Request(REQ_URL, function (error, response, body) {
        debugger;
        if (!oldHtml) {
            oldHtml = newHtml = body;
            setTimeout(checkUrl, Config.timeout || 1000);
            return;
        }
        oldHtml = newHtml;
        newHtml = body;
        if (newHtml !== oldHtml) {
            return sendEmail();
        }
        setTimeout(checkUrl, Config.timeout || 1000);
    });
}

checkUrl();
<commit_msg>Use cheerio to parse HTML<commit_after>// Dependencies
var Request = require("request")
  , Mandrill = require("mandrill-api/mandrill")
  , Config = require("./config")
  , MandrillClient = new Mandrill.Mandrill(Config.mandrillKey)
  , Http = require("http")
  , Url = require("url")
  , Cheerio = require("cheerio")
  ;

// The request url where the results are supposed to be posted
const REQ_URL = Config.reqUrl || "http://static.bacalaureat.edu.ro/2014/rapoarte/BH/index.html"

// This becomes `true` once the email is submitted.
var sent = false;

var oldHtml = null
  , newHtml = null
  ;

/**
 * sendEmail
 * Sends the notification email
 *
 * @name sendEmail
 * @function
 * @return
 */
function sendEmail() {
    sent = true;
    MandrillClient.messages.send({
        message: {
            from_email: Config.from.email
          , from_name: Config.from.name
          , to: [
                {
                    email: Config.to.email
                  , name: Config.to.name
                }
            ]
          , subject: Config.subject
          , text: Config.text + "\n\n" + REQ_URL
        }
    }, function(result) {
        console.log(result);
    }, function (error) {
        console.log(error);
    });
}

function checkUrl() {
    Request(REQ_URL, function (error, response, body) {
        if (!oldHtml) {
            oldHtml = newHtml = body;
            setTimeout(checkUrl, Config.timeout || 1000);
            return;
        }
        oldHtml = newHtml;
        newHtml = body;
        $1 = Cheerio.load(newHtml);
        $2 = Cheerio.load(newHtml);

        console.log($1("#ContentPlaceHolderBody_LabelTitle").text())

        if (newHtml !== oldHtml) {
            if ($1("#ContentPlaceHolderBody_LabelTitle").text() !== $2("#ContentPlaceHolderBody_LabelTitle")) {
                return sendEmail();
            }
        }
        setTimeout(checkUrl, Config.timeout || 1000);
    });
}

checkUrl();
<|endoftext|>


<commit_before>'use strict';

var postcss = require('postcss');

module.exports = postcss.plugin('postcss-prefixer', prefixer);

/**
 * Prefix all css classes and IDs
 *
 * @param  {String} prefix
 * @param  {Object} options
 */
function prefixer(prefix, opts) {
    opts = opts || {};
    var regex = /(\s*?[#\.][-\w\d\s,\>\~\+\:\&\(\)]+\s*?)/g;

    return function(css) {
        css.walkRules(function(rule) {
            var selectors = rule.selector.split(regex);

            if (selectors) {
                selectors = selectors.map(function(selector) {
                    if (!isValidSelector(selector) ||
                        matchIgnore(selector, opts.ignore)
                    ) {
                        return selector;
                    }

                    return selector.substr(0, 1) + prefix + selector.substr(1);
                });

                rule.selector = selectors.join('');
            }
        });
    }
}

/**
 * Check if given selector matchs ingore list
 *
 * @param  {String} selector [ selector to matched against the ignore]
 * @param  {Array} ignore [ ignore list ]
 * @return {Boolean}
 */
function matchIgnore(selector, ignore) {
    if (!ignore || ignore.constructor !== Array) {
        return false;
    }

    return ignore.some(function(test) {
        if (test.constructor === RegExp) {
            return test.exec(selector.replace(/[\,\)]/, ''));
        } else if (test.constructor === String) {
            test = new RegExp(test);
            return test.exec(selector.replace(/[\,\)]/, ''));
        }
    });
}

/**
 * Check if given selector is a class or ID
 *
 * @param  {String}  selector [ given selector to be valided ]
 * @return {Boolean}
 */
function isValidSelector(selector) {
    return selector.indexOf('.') === 0 || selector.indexOf('#') === 0;
}
<commit_msg>rewrite plugin to use css-selector-tokenizer to parse the css selector instead of a regex<commit_after>'use strict';

var postcss = require('postcss'),
    Tokenizer = require('css-selector-tokenizer');

module.exports = postcss.plugin('postcss-prefixer', function(prefix, opts) {
    opts = opts || {};

    return function(css) {
        css.walkRules(function(rule) {
            var selector = Tokenizer.parse(rule.selector);
            rule.selector = Tokenizer.stringify(prefixer(selector));
        });
    };

    function prefixer(selector) {
        var validTypes = /^class|^id/;

        selector.nodes.map(function(node) {
            return node.nodes.map(function(n) {
                if(n.type === 'selector') { return prefixer(n); }

                if (validTypes.test(n.type) && !matchIgnore(n)) {
                    n.name = prefix + n.name;
                } else if (n.type === 'nested-pseudo-class') {
                    return prefixer(n);
                }

                return node;
            });
        });

        return selector;
    }

    function matchIgnore(node) {
        if (!opts.ignore || opts.ignore.constructor !== Array) {
            return false;
        }

        var selector = node.name;

        switch (node.type) {
            case 'class':
                selector = '.' + selector;
                break;
            case 'id':
                selector = '#' + selector;
                break;
            default:
                break;
        }

        return opts.ignore.some(function(test) {
            if (test.constructor === RegExp) {
                return test.exec(selector);
            } else if (test.constructor === String) {
                return test === selector;
            }
        });
    }
});
<|endoftext|>


<commit_before>var fs = require('fs');
var ps = require('path');
var cs = require('crypto');
var rm = require('rimraf');

var IS_WINDOWS = process.platform === 'win32';
var SYS_DIR_MODE = 0700;
var SYS_FILE_MODE = 0600;
var SYS_FILE_FLAGS = 'wx+';
var TEMPLATE_RE = /X+/g;
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

var tracking = false;
var trackedDirs = {};
var trackedFiles = {};
var manuallyTrackedDirs = {};
var manuallyTrackedFiles = {};

process.addListener('exit', function (exitcode) {
  if (tracking) {
    clearSync();
  } else {
    clearManuallyTracked();
  }
});

var onUncaughtException = function (err) {
  process.removeListener('uncaughtException', onUncaughtException);
  clearSync();
  throw err;
};
process.addListener('uncaughtException', onUncaughtException);

/* History:
 * https://github.com/joyent/node/blob/a11bf99ce0dae4d8f4de8a9c0c32159c1a9ecfbf/lib/os.js#L42-L47
 * https://github.com/joyent/node/blob/120e5a24df76deb5019abec9744ace94f0f3746a/lib/os.js#L45-L56
 * https://github.com/iojs/io.js/blob/6c80e38b014b7be570ffafa91032a6d67d7dd4ae/lib/os.js#L25-L40
 *
 * Reason for my choice:
 *   Never trust the return string.
 */
function tmpdir() {
  if (IS_WINDOWS) {
    return process.env.TEMP || process.env.TMP ||
           (process.env.SystemRoot || process.env.windir) + '\\temp';
  } else {
    return process.env.TMPDIR || process.env.TMP || process.env.TEMP || '/tmp';
  }
}

function track(on) {
  tracking = (on == null ? true : Boolean(on));
}

function clearManuallyTracked() {
  var unlinkers = [];
  for (var k in manuallyTrackedFiles) {
    manuallyTrackedFiles[k] && unlinkers.push(manuallyTrackedFiles[k]);
  }
  for (var k in manuallyTrackedDirs) {
    manuallyTrackedDirs[k] && unlinkers.push(manuallyTrackedDirs[k]);
  }
  for (var i = 0, l = unlinkers.length; i < l; i++) {
    unlinkers[i]();
  }
}

function clearSync() {
  var unlinkers = [];
  for (var k in trackedFiles) {
    trackedFiles[k] && unlinkers.push(trackedFiles[k]);
  }
  for (var k in manuallyTrackedFiles) {
    manuallyTrackedFiles[k] && unlinkers.push(manuallyTrackedFiles[k]);
  }
  for (var k in trackedDirs) {
    trackedDirs[k] && unlinkers.push(trackedDirs[k]);
  }
  for (var k in manuallyTrackedDirs) {
    manuallyTrackedDirs[k] && unlinkers.push(manuallyTrackedDirs[k]);
  }
  for (var i = 0, l = unlinkers.length; i < l; i++) {
    unlinkers[i]();
  }
}

function clear(callback) {
  var jobs = [];
  for (var k in trackedFiles) {
    if (trackedFiles[k]) {
      (function (k) {
        jobs.push(function (next) {
          trackedFiles[k](next);
        });
      })(k);
    }
  }
  for (var k in manuallyTrackedFiles) {
    if (manuallyTrackedFiles[k]) {
      (function (k) {
        jobs.push(function (next) {
          manuallyTrackedFiles[k](next);
        });
      })(k);
    }
  }
  for (var k in trackedDirs) {
    if (trackedDirs[k]) {
      (function (k) {
        jobs.push(function (next) {
          trackedDirs[k](next);
        });
      })(k);
    }
  }
  for (var k in manuallyTrackedDirs) {
    if (manuallyTrackedDirs[k]) {
      (function (k) {
        jobs.push(function (next) {
          manuallyTrackedDirs[k](next);
        });
      })(k);
    }
  }
  callback && jobs.push(function (next) { callback(); });
  queue(jobs);
}

function generateSimpleFileUnlinker(path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        callback && callback(err);
      });
    } else {
      fs.unlinkSync(path);
    }
  };
  return unlink;
}

function generateSimpleDirUnlinker(path, recursive) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      if (recursive) {
        rm(path, function (err) {
          callback && callback(err);
        });
      } else {
        fs.rmdir(path, function (err) {
          callback && callback(err);
        });
      }
    } else {
      if (recursive) {
        rm.sync(path);
      } else {
        fs.rmdirSync(path);
      }
    }
  };
  return unlink;
}

function generateFileUnlinker(fd, path, manually) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        if (manually) {
          delete manuallyTrackedFiles[fd];
        } else {
          delete trackedFiles[fd];
        }
        callback && callback(null);
      });
    } else {
      try {
        fs.unlinkSync(path);
      } finally {
        if (manually) {
          delete manuallyTrackedFiles[fd];
        } else {
          delete trackedFiles[fd];
        }
      }
    }
  };
  if (manually) {
    manuallyTrackedFiles[fd] = unlink;
  } else {
    trackedFiles[fd] = unlink;
  }
  return unlink;
}

function generateDirUnlinker(recursive, path, manually) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      var rmdir = recursive ? rm : fs.rmdir.bind(fs);
      rmdir(path, function (err) {
        if (manually) {
          delete manuallyTrackedDirs[path];
        } else {
          delete trackedDirs[path];
        }
        callback && callback(null);
      });
    } else {
      try {
        if (recursive) {
          rm.sync(path);
        } else {
          fs.rmdirSync(path);
        }
      } finally {
        if (manually) {
          delete manuallyTrackedDirs[path];
        } else {
          delete trackedDirs[path];
        }
      }
    }
  };
  if (manually) {
    manuallyTrackedDirs[path] = unlink;
  } else {
    trackedDirs[path] = unlink;
  }
  return unlink;
}

function queue(jobs) {
  var next = function() {
    if (jobs.length && !this.called) {
      this.called = true;
      jobs.shift()(next.bind({}));
    }
  };
  next.call({});
}

function registerFilename(path, opts, callback) {
  fs.open(path, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE, function (err, fd) {
    if (err) {
      callback(null);
      return;
    }
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd] && !manuallyTrackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = generateSimpleFileUnlinker(path);
    }
    callback({path: path, fd: fd, unlink: unlink});
  });
}

function generateFile() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (file) {
    if (limit-- >= 0) {
      if (file) {
        callback && callback(null, file);
      } else {
        registerFilename(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary file within limits.');
      callback && callback(err, null);
    }
  };
  registerFilename(generateName(opts), opts, registerCallback);
}

function registerFilenameSync(path, opts) {
  try {
    var fd = fs.openSync(path, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE);
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd] && !manuallyTrackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = generateSimpleFileUnlinker(path);
    }
    return {path: path, fd: fd, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateFileSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var file = registerFilenameSync(generateName(opts), opts);
    if (file) {
      return file;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary file within limits.');
}

function registerDirname(path, opts, callback) {
  fs.mkdir(path, opts.mode || SYS_DIR_MODE, function (err) {
    if (err) {
      callback(null);
      return;
    }
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path] && !manuallyTrackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = generateSimpleDirUnlinker(path, recursive);
    }
    callback({path: path, recursive: recursive, unlink: unlink});
  });
}

function generateDir() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (dir) {
    if (limit-- >= 0) {
      if (dir) {
        callback && callback(null, dir);
      } else {
        registerDirname(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary directory within limits.');
      callback && callback(err, null);
    }
  };
  registerDirname(generateName(opts), opts, registerCallback);
}

function registerDirnameSync(path, opts) {
  try {
    fs.mkdirSync(path, opts.mode || SYS_DIR_MODE);
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path] && !manuallyTrackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = generateSimpleDirUnlinker(path, recursive);
    }
    return {path: path, recursive: recursive, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateDirSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var dir = registerDirnameSync(generateName(opts), opts);
    if (dir) {
      return dir;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary directory within limits.');
}

function getArgs(args) {
  var opts, callback;
  if (typeof args[0] === 'function') {
    opts = args[1];
    callback = args[0];
  } else {
    opts = args[0];
    callback = args[1];
  }
  opts = opts || {};
  return [opts, callback];
}

function randomString(length) {
  var buffer;
  try {
    buffer = cs.randomBytes(length);
  } catch (err) {
    buffer = cs.pseudoRandomBytes(length);
  }
  var chars = [];
  for (var i = 0; i < length; i++) {
    chars.push(CHARS[buffer[i]%CHARS.length]);
  }
  return chars.join('');
}

function generateName(opts) {
  opts = opts || {};
  if (opts.name) {
    return ps.resolve(ps.join(opts.dir || tmpdir(), opts.name));
  }
  if (opts.template) {
    if (TEMPLATE_RE.test(opts.template)) {
      var name = opts.template.replace(TEMPLATE_RE, function (s) {
        return randomString(s.length);
      });
      return ps.resolve(ps.join(opts.dir || tmpdir(), name));
    } else {
      throw new Error('Invalid template string.');
    }
  }
  var name = [
    opts.prefix || 'tmp-',
    Date.now(),
    '-',
    process.pid,
    '-',
    randomString(12),
    opts.suffix || ''
  ].join('');
  return ps.resolve(ps.join(opts.dir || tmpdir(), name));
}

module.exports = {
  track: track,
  clear: clear,
  clearSync: clearSync,
  open: generateFile,
  openSync: generateFileSync,
  mkdir: generateDir,
  mkdirSync: generateDirSync,
  name: generateName,
  dir: tmpdir
};
<commit_msg>Some improvements on clear()<commit_after>var fs = require('fs');
var ps = require('path');
var cs = require('crypto');
var rm = require('rimraf');

var IS_WINDOWS = process.platform === 'win32';
var SYS_DIR_MODE = 0700;
var SYS_FILE_MODE = 0600;
var SYS_FILE_FLAGS = 'wx+';
var TEMPLATE_RE = /X+/g;
var CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';

var tracking = false;
var trackedDirs = {};
var trackedFiles = {};
var manuallyTrackedDirs = {};
var manuallyTrackedFiles = {};

process.addListener('exit', function (exitcode) {
  if (tracking) {
    clearSync();
  } else {
    clearManuallyTracked();
  }
});

var onUncaughtException = function (err) {
  process.removeListener('uncaughtException', onUncaughtException);
  clearSync();
  throw err;
};
process.addListener('uncaughtException', onUncaughtException);

/* History:
 * https://github.com/joyent/node/blob/a11bf99ce0dae4d8f4de8a9c0c32159c1a9ecfbf/lib/os.js#L42-L47
 * https://github.com/joyent/node/blob/120e5a24df76deb5019abec9744ace94f0f3746a/lib/os.js#L45-L56
 * https://github.com/iojs/io.js/blob/6c80e38b014b7be570ffafa91032a6d67d7dd4ae/lib/os.js#L25-L40
 *
 * Reason for my choice:
 *   Never trust the return string.
 */
function tmpdir() {
  if (IS_WINDOWS) {
    return process.env.TEMP || process.env.TMP ||
           (process.env.SystemRoot || process.env.windir) + '\\temp';
  } else {
    return process.env.TMPDIR || process.env.TMP || process.env.TEMP || '/tmp';
  }
}

function track(on) {
  tracking = (on == null ? true : Boolean(on));
}

function clearManuallyTracked() {
  var unlinkers = [];
  for (var k in manuallyTrackedFiles) {
    manuallyTrackedFiles[k] && unlinkers.push(manuallyTrackedFiles[k]);
  }
  for (var k in manuallyTrackedDirs) {
    manuallyTrackedDirs[k] && unlinkers.push(manuallyTrackedDirs[k]);
  }
  for (var i = 0, l = unlinkers.length; i < l; i++) {
    unlinkers[i]();
  }
}

function clearSync() {
  var unlinkers = [];
  for (var k in trackedFiles) {
    trackedFiles[k] && unlinkers.push(trackedFiles[k]);
  }
  for (var k in manuallyTrackedFiles) {
    manuallyTrackedFiles[k] && unlinkers.push(manuallyTrackedFiles[k]);
  }
  for (var k in trackedDirs) {
    trackedDirs[k] && unlinkers.push(trackedDirs[k]);
  }
  for (var k in manuallyTrackedDirs) {
    manuallyTrackedDirs[k] && unlinkers.push(manuallyTrackedDirs[k]);
  }
  for (var i = 0, l = unlinkers.length; i < l; i++) {
    unlinkers[i]();
  }
}

function clear(callback) {
  var jobs = [];
  for (var k in trackedFiles) {
    if (trackedFiles[k]) {
      jobs.push(trackedFiles[k]);
    }
  }
  for (var k in manuallyTrackedFiles) {
    if (manuallyTrackedFiles[k]) {
      jobs.push(manuallyTrackedFiles[k]);
    }
  }
  for (var k in trackedDirs) {
    if (trackedDirs[k]) {
      jobs.push(trackedDirs[k]);
    }
  }
  for (var k in manuallyTrackedDirs) {
    if (manuallyTrackedDirs[k]) {
      jobs.push(manuallyTrackedDirs[k]);
    }
  }
  parallel(jobs, callback);
}

function generateSimpleFileUnlinker(path) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        callback && callback(err);
      });
    } else {
      fs.unlinkSync(path);
    }
  };
  return unlink;
}

function generateSimpleDirUnlinker(path, recursive) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      if (recursive) {
        rm(path, function (err) {
          callback && callback(err);
        });
      } else {
        fs.rmdir(path, function (err) {
          callback && callback(err);
        });
      }
    } else {
      if (recursive) {
        rm.sync(path);
      } else {
        fs.rmdirSync(path);
      }
    }
  };
  return unlink;
}

function generateFileUnlinker(fd, path, manually) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      fs.unlink(path, function (err) {
        if (manually) {
          delete manuallyTrackedFiles[fd];
        } else {
          delete trackedFiles[fd];
        }
        callback && callback(null);
      });
    } else {
      try {
        fs.unlinkSync(path);
      } finally {
        if (manually) {
          delete manuallyTrackedFiles[fd];
        } else {
          delete trackedFiles[fd];
        }
      }
    }
  };
  if (manually) {
    manuallyTrackedFiles[fd] = unlink;
  } else {
    trackedFiles[fd] = unlink;
  }
  return unlink;
}

function generateDirUnlinker(recursive, path, manually) {
  var called = false;
  var unlink = function unlink(callback) {
    if (called) {
      return;
    }
    called = true;
    if (callback) {
      var rmdir = recursive ? rm : fs.rmdir.bind(fs);
      rmdir(path, function (err) {
        if (manually) {
          delete manuallyTrackedDirs[path];
        } else {
          delete trackedDirs[path];
        }
        callback && callback(null);
      });
    } else {
      try {
        if (recursive) {
          rm.sync(path);
        } else {
          fs.rmdirSync(path);
        }
      } finally {
        if (manually) {
          delete manuallyTrackedDirs[path];
        } else {
          delete trackedDirs[path];
        }
      }
    }
  };
  if (manually) {
    manuallyTrackedDirs[path] = unlink;
  } else {
    trackedDirs[path] = unlink;
  }
  return unlink;
}

function parallel(jobs, callback) {
  var called = !callback;
  var count = jobs.length;
  var done = function () {
    if (count > 0 && !this.called) {
      count--;
    }
    if (count === 0 && !called) {
      called = true;
      callback();
    }
  };
  for (var i = 0, l = jobs.length; i < l; i++) {
    jobs[i](done.bind({}));
  }
}

function registerFilename(path, opts, callback) {
  fs.open(path, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE, function (err, fd) {
    if (err) {
      callback(null);
      return;
    }
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd] && !manuallyTrackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = generateSimpleFileUnlinker(path);
    }
    callback({path: path, fd: fd, unlink: unlink});
  });
}

function generateFile() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (file) {
    if (limit-- >= 0) {
      if (file) {
        callback && callback(null, file);
      } else {
        registerFilename(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary file within limits.');
      callback && callback(err, null);
    }
  };
  registerFilename(generateName(opts), opts, registerCallback);
}

function registerFilenameSync(path, opts) {
  try {
    var fd = fs.openSync(path, SYS_FILE_FLAGS, opts.mode || SYS_FILE_MODE);
    var unlink;
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedFiles[fd] && !manuallyTrackedFiles[fd]) {
        unlink = generateFileUnlinker(fd, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete files via file.unlink()?");
      }
    } else {
      unlink = generateSimpleFileUnlinker(path);
    }
    return {path: path, fd: fd, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateFileSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var file = registerFilenameSync(generateName(opts), opts);
    if (file) {
      return file;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary file within limits.');
}

function registerDirname(path, opts, callback) {
  fs.mkdir(path, opts.mode || SYS_DIR_MODE, function (err) {
    if (err) {
      callback(null);
      return;
    }
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path] && !manuallyTrackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = generateSimpleDirUnlinker(path, recursive);
    }
    callback({path: path, recursive: recursive, unlink: unlink});
  });
}

function generateDir() {
  var args = getArgs(arguments);
  var opts = args[0];
  var callback = args[1];
  var limit = opts.limit || 5;
  var registerCallback = function (dir) {
    if (limit-- >= 0) {
      if (dir) {
        callback && callback(null, dir);
      } else {
        registerDirname(generateName(opts), opts, registerCallback);
      }
    } else {
      var err = new Error('Failed to get a temporary directory within limits.');
      callback && callback(err, null);
    }
  };
  registerDirname(generateName(opts), opts, registerCallback);
}

function registerDirnameSync(path, opts) {
  try {
    fs.mkdirSync(path, opts.mode || SYS_DIR_MODE);
    var unlink;
    var recursive = Boolean(opts.recursive);
    if (opts.track || (opts.track == null && tracking)) {
      if (!trackedDirs[path] && !manuallyTrackedDirs[path]) {
        unlink = generateDirUnlinker(recursive, path, Boolean(opts.track));
      } else {
        throw new Error("Didn't you delete directories via directory.unlink()?");
      }
    } else {
      unlink = generateSimpleDirUnlinker(path, recursive);
    }
    return {path: path, recursive: recursive, unlink: unlink};
  } catch (err) {
    return null;
  }
}

function generateDirSync(opts) {
  opts = opts || {};
  var limit = opts.limit || 5;
  do {
    var dir = registerDirnameSync(generateName(opts), opts);
    if (dir) {
      return dir;
    }
  } while (limit-- > 0);
  throw new Error('Failed to get a temporary directory within limits.');
}

function getArgs(args) {
  var opts, callback;
  if (typeof args[0] === 'function') {
    opts = args[1];
    callback = args[0];
  } else {
    opts = args[0];
    callback = args[1];
  }
  opts = opts || {};
  return [opts, callback];
}

function randomString(length) {
  var buffer;
  try {
    buffer = cs.randomBytes(length);
  } catch (err) {
    buffer = cs.pseudoRandomBytes(length);
  }
  var chars = [];
  for (var i = 0; i < length; i++) {
    chars.push(CHARS[buffer[i]%CHARS.length]);
  }
  return chars.join('');
}

function generateName(opts) {
  opts = opts || {};
  if (opts.name) {
    return ps.resolve(ps.join(opts.dir || tmpdir(), opts.name));
  }
  if (opts.template) {
    if (TEMPLATE_RE.test(opts.template)) {
      var name = opts.template.replace(TEMPLATE_RE, function (s) {
        return randomString(s.length);
      });
      return ps.resolve(ps.join(opts.dir || tmpdir(), name));
    } else {
      throw new Error('Invalid template string.');
    }
  }
  var name = [
    opts.prefix || 'tmp-',
    Date.now(),
    '-',
    process.pid,
    '-',
    randomString(12),
    opts.suffix || ''
  ].join('');
  return ps.resolve(ps.join(opts.dir || tmpdir(), name));
}

module.exports = {
  track: track,
  clear: clear,
  clearSync: clearSync,
  open: generateFile,
  openSync: generateFileSync,
  mkdir: generateDir,
  mkdirSync: generateDirSync,
  name: generateName,
  dir: tmpdir
};
<|endoftext|>


<commit_before>module.exports = (function() {
    'use strict';

    var coordinator = require('./coordinator'),
        middleware = require('../middleware'),
        roles = require('../security/roles'),
        createError = require('../utils/error'),
        _ = require('underscore'),
        Strings = require('../strings'),
        strings = new Strings();

    /**
     * Middleware the ensures that the user either has a good enough role or is trying to get information
     * about themselves.
     * @param role
     * @returns {Function}
     */
    function roleOrSelf(role){
        if(!_.isNumber(role)){
            role = roles[role.toUpperCase()];
        }

        return function validateRoleOrSelf(kontx, next){
            var userPrivLevel = roles[kontx.user.role.toUpperCase()],
                passedInUserId = kontx.args[0],
                err = createError(strings.group('codes').forbidden, strings.group('errors').user_privileges_exceeded);

            //If user object passed in instead of a string then parse.
            if(!_.isUndefined(kontx.args[0]._id)){
                passedInUserId = kontx.args[0]._id;
            }

            //If user has enough priviliges then keep going
            if (userPrivLevel <= parseInt(role, 10) || kontx.user._id.toString() === passedInUserId.toString()){
                next();
                return;
            }

            next(err);
        };
    }

    /**
     * Middleware that will set the function argument equal to the currently logged in user id if it is left
     * empty. This can be used for returning back the currently logged in user's information.
     * @param kontx
     * @param next
     */
    function setDefaultUser(kontx, next){
        if(kontx.args.length === 0){
            kontx.args[0] = kontx.user._id;
        }
        next();
    }

    coordinator.batch(
        middleware.users,
        ['insert','deleteById','getByEmail','create','getByLogin','query','deletePermissions','savePermissions', 'list'],
        [middleware.identity, middleware.role(roles.ADMIN)]
    );

    coordinator.batch(
        middleware.users,
        ['getById', 'update'],
        [middleware.identity, setDefaultUser, roleOrSelf(roles.ADMIN)]
    );

    coordinator.use('users.authenticate', []);

    return function users(kontx){
        return {
            insert: function(user){
                return coordinator.handle('users.insert', [user], kontx);
            },
            getByLogin: function(login){
                return coordinator.handle('users.getByLogin', [login], kontx);
            },
            getById: function(id){
                return coordinator.handle('users.getById', [id], kontx);
            },
            current: function(){
                return coordinator.handle('users.getById', [], kontx);
            },
            deleteById: function(id){
                return coordinator.handle('users.deleteById', [id], kontx);
            },
            getByEmail: function(email){
                return coordinator.handle('users.getByEmail', [email], kontx);
            },
            authenticate: function(login, password){
                return coordinator.handle('users.authenticate', [login, password], kontx);
            },
            savePermissions: function(userId, nodeid, role){
                return coordinator.handle('users.savePermissions', [userId, nodeid, role], kontx);
            },
            deletePermissions: function(userId, nodeId){
                return coordinator.handle('users.deletePermissions', [userId, nodeId], kontx);
            },
            query: function(criteria){
                var filters = {},
                    options = {};
                if(!_.isUndefined(criteria)){
                    filters = criteria.filters;
                    options = criteria.options;
                }
                kontx.args = [filters, options];
                return coordinator.handle('users.query', [filters, options], kontx);
            },
            update: function(user){
                return coordinator.handle('users.update', [user], kontx);
            },
            list: function(options){
                return coordinator.handle('users.list', [options], kontx);
            }
        };
    };
})();<commit_msg>Changed casing of variable to be consist<commit_after>module.exports = (function() {
    'use strict';

    var coordinator = require('./coordinator'),
        middleware = require('../middleware'),
        roles = require('../security/roles'),
        createError = require('../utils/error'),
        _ = require('underscore'),
        Strings = require('../strings'),
        strings = new Strings();

    /**
     * Middleware the ensures that the user either has a good enough role or is trying to get information
     * about themselves.
     * @param role
     * @returns {Function}
     */
    function roleOrSelf(role){
        if(!_.isNumber(role)){
            role = roles[role.toUpperCase()];
        }

        return function validateRoleOrSelf(kontx, next){
            var userPrivLevel = roles[kontx.user.role.toUpperCase()],
                passedInUserId = kontx.args[0],
                err = createError(strings.group('codes').forbidden, strings.group('errors').user_privileges_exceeded);

            //If user object passed in instead of a string then parse.
            if(!_.isUndefined(kontx.args[0]._id)){
                passedInUserId = kontx.args[0]._id;
            }

            //If user has enough priviliges then keep going
            if (userPrivLevel <= parseInt(role, 10) || kontx.user._id.toString() === passedInUserId.toString()){
                next();
                return;
            }

            next(err);
        };
    }

    /**
     * Middleware that will set the function argument equal to the currently logged in user id if it is left
     * empty. This can be used for returning back the currently logged in user's information.
     * @param kontx
     * @param next
     */
    function setDefaultUser(kontx, next){
        if(kontx.args.length === 0){
            kontx.args[0] = kontx.user._id;
        }
        next();
    }

    coordinator.batch(
        middleware.users,
        ['insert','deleteById','getByEmail','create','getByLogin','query','deletePermissions','savePermissions', 'list'],
        [middleware.identity, middleware.role(roles.ADMIN)]
    );

    coordinator.batch(
        middleware.users,
        ['getById', 'update'],
        [middleware.identity, setDefaultUser, roleOrSelf(roles.ADMIN)]
    );

    coordinator.use('users.authenticate', []);

    return function users(kontx){
        return {
            insert: function(user){
                return coordinator.handle('users.insert', [user], kontx);
            },
            getByLogin: function(login){
                return coordinator.handle('users.getByLogin', [login], kontx);
            },
            getById: function(id){
                return coordinator.handle('users.getById', [id], kontx);
            },
            current: function(){
                return coordinator.handle('users.getById', [], kontx);
            },
            deleteById: function(id){
                return coordinator.handle('users.deleteById', [id], kontx);
            },
            getByEmail: function(email){
                return coordinator.handle('users.getByEmail', [email], kontx);
            },
            authenticate: function(login, password){
                return coordinator.handle('users.authenticate', [login, password], kontx);
            },
            savePermissions: function(userid, nodeid, role){
                return coordinator.handle('users.savePermissions', [userid, nodeid, role], kontx);
            },
            deletePermissions: function(userid, nodeid){
                return coordinator.handle('users.deletePermissions', [userid, nodeid], kontx);
            },
            query: function(criteria){
                var filters = {},
                    options = {};
                if(!_.isUndefined(criteria)){
                    filters = criteria.filters;
                    options = criteria.options;
                }
                kontx.args = [filters, options];
                return coordinator.handle('users.query', [filters, options], kontx);
            },
            update: function(user){
                return coordinator.handle('users.update', [user], kontx);
            },
            list: function(options){
                return coordinator.handle('users.list', [options], kontx);
            }
        };
    };
})();<|endoftext|>


<commit_before>var tar = require('tar-stream');
var pump = require('pump');
var mkdirp = require('mkdirp');
var fs = require('fs');
var path = require('path');
var os = require('os');

var win32 = os.platform() === 'win32';

var noop = function() {};

var echo = function(name) {
	return name;
};

var normalize = !win32 ? echo : function() {
	return name.replace(/\\/g, '/');
};

var statAll = function(cwd, ignore) {
	var queue = ['.'];

	return function loop(callback) {
		if (!queue.length) return callback();
		var next = queue.shift();
		var nextAbs = path.join(cwd, next);

		fs.lstat(nextAbs, function(err, stat) {
			if (err) return callback(err);

			if (!stat.isDirectory()) return callback(null, next, stat);

			fs.readdir(nextAbs, function(err, files) {
				if (err) return callback(err);

				for (var i = 0; i < files.length; i++) {
					if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]));
				}

				callback(null, next, stat);
			});
		});
	};
};

exports.pack = function(cwd, opts) {
	if (!cwd) cwd = '.';
	if (!opts) opts = {};

	var ignore = opts.ignore || noop;
	var statNext = statAll(cwd, ignore);
	var pack = tar.pack();

	var onlink = function(filename, header) {
		fs.readlink(path.join(cwd, filename), function(err, linkname) {
			if (err) return pack.destroy(err);
			header.linkname = normalize(linkname);
			pack.entry(header, onnextentry);
		});
	};

	var onstat = function(err, filename, stat) {
		if (err) return pack.destroy(err);
		if (!filename) return pack.finalize();

		var header = {
			name: normalize(filename),
			mode: stat.mode,
			mtime: stat.mtime,
			size: stat.size,
			type: 'file',
			uid: stat.uid,
			gid: stat.gid
		};

		if (stat.isDirectory()) {
			header.size = 0;
			header.type = 'directory';
			return pack.entry(header, onnextentry);
		}

		if (stat.isSymbolicLink()) {
			header.size = 0;
			header.type = 'symlink';
			return onlink(filename, header);
		}

		// TODO: add fifo etc...

		if (!stat.isFile()) return pack.destroy(new Error('unsupported type for '+filename));

		var entry = pack.entry(header, onnextentry);
		var rs = fs.createReadStream(path.join(cwd, filename));

		pump(rs, entry);
	};

	var onnextentry = function(err) {
		if (err) return pack.destroy(err);
		statNext(onstat);
	};

	onnextentry();

	return pack;
};

var head = function(list) {
	return list.length ? list[list.length-1] : null
};

exports.extract = function(cwd, opts) {
	if (!cwd) cwd = '.';
	if (!opts) opts = {};

	var ignore = opts.ignore || noop;
	var own = opts.chown !== false && !win32 && process.getuid() === 0;
	var extract = tar.extract();
	var stack = [];
	var now = new Date();

	var utimesParent = function(name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
		var top;
		while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop();
		if (!top) return cb();
		fs.utimes(top[0], now, top[1], cb);
	};

	var utimes = function(name, header, cb) {
		if (opts.utimes === false) return cb();

		if (header.type === 'directory') return fs.utimes(name, now, header.mtime, cb);
		if (header.type === 'symlink') return utimesParent(name, cb); // TODO: how to set mtime on link?

		fs.utimes(name, now, header.mtime, function(err) {
			if (err) return cb(err);
			utimesParent(name, cb);
		});
	};

	var chperm = function(name, header, cb) {
		var link = header.type === 'symlink';
		var chmod = link ? fs.lchmod : fs.chmod;
		var chown = link ? fs.lchown : fs.chown;

		chmod(name, header.mode, function(err) {
			if (err) return cb(err);
			if (!own) return cb();
			chown(name, header.uid, header.gid, cb);
		});
	};

	extract.on('entry', function(header, stream, next) {
		var name = path.join(cwd, path.join('/', header.name));

		if (ignore(name)) {
			stream.resume();
			return next();
		}

		var stat = function(err) {
			if (err) return next(err);
			if (win32) return next();
			utimes(name, header, function(err) {
				if (err) return next(err);
				chperm(name, header, next);
			});
		};

		var onlink = function() {
			if (win32) return next(); // skip symlinks on win for now before it can be tested
			fs.unlink(name, function() {
				fs.symlink(header.linkname, name, stat);
			});
		};

		var onfile = function() {
			var ws = fs.createWriteStream(name);

			pump(stream, ws, function(err) {
				if (err) return next(err);
				ws.on('close', stat);
			});
		};

		if (header.type === 'directory') {
			stack.push([name, header.mtime]);
			return mkdirp(name, stat);
		}

		mkdirp(path.dirname(name), function(err) {
			if (err) return next(err);
			if (header.type === 'symlink') return onlink();
			if (header.type !== 'file') return next(new Error('unsupported type for '+name+' ('+header.type+')'));

			onfile();
		});
	});

	return extract;
};<commit_msg>ignore sockets<commit_after>var tar = require('tar-stream');
var pump = require('pump');
var mkdirp = require('mkdirp');
var fs = require('fs');
var path = require('path');
var os = require('os');

var win32 = os.platform() === 'win32';

var noop = function() {};

var echo = function(name) {
	return name;
};

var normalize = !win32 ? echo : function() {
	return name.replace(/\\/g, '/');
};

var statAll = function(cwd, ignore) {
	var queue = ['.'];

	return function loop(callback) {
		if (!queue.length) return callback();
		var next = queue.shift();
		var nextAbs = path.join(cwd, next);

		fs.lstat(nextAbs, function(err, stat) {
			if (err) return callback(err);

			if (!stat.isDirectory()) return callback(null, next, stat);

			fs.readdir(nextAbs, function(err, files) {
				if (err) return callback(err);

				for (var i = 0; i < files.length; i++) {
					if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]));
				}

				callback(null, next, stat);
			});
		});
	};
};

exports.pack = function(cwd, opts) {
	if (!cwd) cwd = '.';
	if (!opts) opts = {};

	var ignore = opts.ignore || noop;
	var statNext = statAll(cwd, ignore);
	var pack = tar.pack();

	var onlink = function(filename, header) {
		fs.readlink(path.join(cwd, filename), function(err, linkname) {
			if (err) return pack.destroy(err);
			header.linkname = normalize(linkname);
			pack.entry(header, onnextentry);
		});
	};

	var onstat = function(err, filename, stat) {
		if (err) return pack.destroy(err);
		if (!filename) return pack.finalize();

		if (stat.isSocket()) return onnextentry() // tar does not support sockets...

		var header = {
			name: normalize(filename),
			mode: stat.mode,
			mtime: stat.mtime,
			size: stat.size,
			type: 'file',
			uid: stat.uid,
			gid: stat.gid
		};

		if (stat.isDirectory()) {
			header.size = 0;
			header.type = 'directory';
			return pack.entry(header, onnextentry);
		}

		if (stat.isSymbolicLink()) {
			header.size = 0;
			header.type = 'symlink';
			return onlink(filename, header);
		}

		// TODO: add fifo etc...

		if (!stat.isFile()) return pack.destroy(new Error('unsupported type for '+filename));

		var entry = pack.entry(header, onnextentry);
		var rs = fs.createReadStream(path.join(cwd, filename));

		pump(rs, entry);
	};

	var onnextentry = function(err) {
		if (err) return pack.destroy(err);
		statNext(onstat);
	};

	onnextentry();

	return pack;
};

var head = function(list) {
	return list.length ? list[list.length-1] : null
};

exports.extract = function(cwd, opts) {
	if (!cwd) cwd = '.';
	if (!opts) opts = {};

	var ignore = opts.ignore || noop;
	var own = opts.chown !== false && !win32 && process.getuid() === 0;
	var extract = tar.extract();
	var stack = [];
	var now = new Date();

	var utimesParent = function(name, cb) { // we just set the mtime on the parent dir again everytime we write an entry
		var top;
		while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop();
		if (!top) return cb();
		fs.utimes(top[0], now, top[1], cb);
	};

	var utimes = function(name, header, cb) {
		if (opts.utimes === false) return cb();

		if (header.type === 'directory') return fs.utimes(name, now, header.mtime, cb);
		if (header.type === 'symlink') return utimesParent(name, cb); // TODO: how to set mtime on link?

		fs.utimes(name, now, header.mtime, function(err) {
			if (err) return cb(err);
			utimesParent(name, cb);
		});
	};

	var chperm = function(name, header, cb) {
		var link = header.type === 'symlink';
		var chmod = link ? fs.lchmod : fs.chmod;
		var chown = link ? fs.lchown : fs.chown;

		chmod(name, header.mode, function(err) {
			if (err) return cb(err);
			if (!own) return cb();
			chown(name, header.uid, header.gid, cb);
		});
	};

	extract.on('entry', function(header, stream, next) {
		var name = path.join(cwd, path.join('/', header.name));

		if (ignore(name)) {
			stream.resume();
			return next();
		}

		var stat = function(err) {
			if (err) return next(err);
			if (win32) return next();
			utimes(name, header, function(err) {
				if (err) return next(err);
				chperm(name, header, next);
			});
		};

		var onlink = function() {
			if (win32) return next(); // skip symlinks on win for now before it can be tested
			fs.unlink(name, function() {
				fs.symlink(header.linkname, name, stat);
			});
		};

		var onfile = function() {
			var ws = fs.createWriteStream(name);

			pump(stream, ws, function(err) {
				if (err) return next(err);
				ws.on('close', stat);
			});
		};

		if (header.type === 'directory') {
			stack.push([name, header.mtime]);
			return mkdirp(name, stat);
		}

		mkdirp(path.dirname(name), function(err) {
			if (err) return next(err);
			if (header.type === 'symlink') return onlink();
			if (header.type !== 'file') return next(new Error('unsupported type for '+name+' ('+header.type+')'));

			onfile();
		});
	});

	return extract;
};<|endoftext|>


<commit_before>"use strict";

// This module should be compatible with PhantomJS v1, just like the other files
// in reify/lib/runtime. Node 4+ features like const/let and arrow functions are
// not acceptable here, and importing any npm packages should be contemplated
// with extreme skepticism.

var utils = require("./utils.js");

var GETTER_ERROR = {};
var NAN = {};
var UNDEFINED = {};
var weakEntryMap = new WeakMap;
var hasOwn = Object.prototype.hasOwnProperty;
var keySalt = 0;

function Entry(exported) {
  // The module.exports of the module this Entry is managing.
  this.exports = exported;
  // Getters for local variables exported from the managed module.
  this.getters = Object.create(null);
  // Setters for assigning to local variables in parent modules.
  this.setters = Object.create(null);
  // The normalized namespace object that importers receive when they use
  // `import * as namespace from "..."` syntax.
  this.namespace = utils.createNamespace();
  // Map from module.id string to module object for each module this Entry
  // is managing.
  this.ownerModules = Object.create(null);
  // Boolean indicating whether all the modules this Entry is managing
  // have finished loading yet. Call entry.hasLoaded() to compute.
  this._loaded = false;
}

var Ep = utils.setPrototypeOf(Entry.prototype, null);

Entry.get = function (exported) {
  if (utils.isObjectLike(exported) &&
      weakEntryMap.has(exported)) {
    return weakEntryMap.get(exported);
  }
  return null;
};

Entry.getOrCreate = function (exported, mod) {
  var entry = getOrCreate(exported);

  if (utils.isObject(mod)) {
    entry.ownerModules[mod.id] = mod;
  }

  return entry;
};

function getOrCreate(exported) {
  if (! utils.isObjectLike(exported)) {
    // In case the child module modified module.exports, create a temporary
    // Entry object so that we can call the entry.addSetters method once,
    // which will trigger entry.runSetters(names), so that module.importSync
    // behaves as expected.
    return new Entry(exported);
  }

  if (weakEntryMap.has(exported)) {
    return weakEntryMap.get(exported);
  }

  var entry = new Entry(exported);
  weakEntryMap.set(exported, entry);
  return entry;
};

function safeKeys(obj) {
  var keys = Object.keys(obj);
  var esModuleIndex = keys.indexOf("__esModule");
  if (esModuleIndex >= 0) {
    keys.splice(esModuleIndex, 1);
  }
  return keys;
}

Ep.addGetters = function (getters, constant) {
  var names = safeKeys(getters);
  var nameCount = names.length;
  constant = !! constant;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var getter = getters[name];

    if (typeof getter === "function" &&
        // Should this throw if this.getters[name] exists?
        ! (name in this.getters)) {
      this.getters[name] = getter;
      getter.constant = constant;
      getter.runCount = 0;
    }
  }
};

Ep.addSetters = function (parent, setters, key) {
  var names = safeKeys(setters);
  var nameCount = names.length;

  if (! nameCount) {
    return;
  }

  // If no key is provided, make a unique key. Otherwise, make sure the key is
  // distinct from keys provided by other parent modules.
  key = key === void 0
    ? makeUniqueKey()
    : parent.id + ":" + key;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var setter = setters[name];

    if (typeof setter === "function") {
      setter.parent = parent;
      if (! (name in this.setters)) {
        this.setters[name] = Object.create(null);
      }
      this.setters[name][key] = setter;
    }
  }

  this.runSetters(names);
};

Ep.runGetters = function () {
  var names = Object.keys(this.getters);

  if (! utils.getESModule(this.exports)) {
    // If the module this Entry is managing overrides module.exports, that
    // value should be exposed as the .default property of the namespace,
    // unless module.exports is marked as an ECMASCript module.
    this.namespace.default = this.exports;
  }

  // Before running getters, copy anything added to the exports object
  // over to the namespace. Values returned by getters take precedence
  // over these values, but we don't want to miss anything.
  if (utils.isObject(this.exports)) {
    var exportsKeys = safeKeys(this.exports);
    var exportsKeyCount = exportsKeys.length;
    for (var i = 0; i < exportsKeyCount; ++i) {
      var key = exportsKeys[i];
      var desc = Object.getOwnPropertyDescriptor(this.exports, key);
      if (hasOwn.call(desc, "value")) {
        // If this.exports[key] is a simple property, simply copy its
        // value over to this.namespace[key].
        this.namespace[key] = desc.value;
      } else {
        // Avoid triggering getters until necessary.
        desc.configurable = true;
        Object.defineProperty(this.namespace, key, desc);
      }
    }
  }

  var nameCount = names.length;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var value = runGetter(this, name);

    // If the getter is run without error, update both entry.namespace and
    // module.exports with the current value so that CommonJS require
    // calls remain consistent with module.watch.
    if (value !== GETTER_ERROR) {
      this.namespace[name] = value;
      this.exports[name] = value;
    }
  }
};

// Called by module.runSetters once the module this Entry is managing has
// finished loading.
Ep.hasLoaded = function () {
  if (this._loaded) {
    return true;
  }

  var ids = Object.keys(this.ownerModules);
  var idCount = ids.length;

  for (var i = 0; i < idCount; ++i) {
    var owner = this.ownerModules[ids[i]];
    if (! owner.loaded && owner.exports === this.exports) {
      // At least one owner module whose exports are still ===
      // this.exports has not finished loading, so this this Entry cannot
      // be marked as loaded yet.
      return false;
    }
  }

  // Set entry._loaded = true only if all the modules in
  // entry.ownerModules that are still associated with entry.exports have
  // finished loading.
  return this._loaded = true;
};

// Called whenever module.exports might have changed, to trigger any
// setters associated with the newly exported values. The names parameter
// is optional; without it, all getters and setters will run.
Ep.runSetters = function (names) {
  // Make sure entry.namespace and module.exports are up to date before we
  // call getExportByName(entry, name).
  this.runGetters();

  // Lazily-initialized object mapping parent module identifiers to parent
  // module objects whose setters we might need to run.
  var parents;

  forEachSetter(this, names, function (setter, name, value) {
    if (parents === void 0) {
      parents = Object.create(null);
    }
    parents[setter.parent.id] = setter.parent;

    // The param order for setters is `value` then `name` because the `name`
    // param is only used by namespace exports.
    setter(value, name);
  });

  if (! parents) {
    return;
  }

  // If any of the setters updated the module.exports of a parent module,
  // or updated local variables that are exported by that parent module,
  // then we must re-run any setters registered by that parent module.
  var parentIDs = Object.keys(parents);
  var parentIDCount = parentIDs.length;

  for (var i = 0; i < parentIDCount; ++i) {
    // What happens if parents[parentIDs[id]] === module, or if
    // longer cycles exist in the parent chain? Thanks to our setter.last
    // bookkeeping above, the runSetters broadcast will only proceed
    // as far as there are any actual changes to report.
    var parent = parents[parentIDs[i]];
    var parentEntry = Entry.get(parent.exports);
    if (parentEntry) {
      parentEntry.runSetters();
    }
  }
};

function callSetterIfNecessary(setter, name, value, callback) {
  if (name === "__esModule") {
    // Ignore setters asking for module.exports.__esModule.
    return;
  }

  if (setter.last === void 0) {
    setter.last = Object.create(null);
  }

  function changed(name, value) {
    var valueToCompare = value;
    if (valueToCompare !== valueToCompare) {
      valueToCompare = NAN;
    } else if (valueToCompare === void 0) {
      valueToCompare = UNDEFINED;
    }

    if (setter.last[name] === valueToCompare) {
      return false;
    }

    setter.last[name] = valueToCompare;
    return true;
  }

  var shouldCall = false;

  if (name === "*") {
    var keys = safeKeys(value);
    var keyCount = keys.length;
    for (var i = 0; i < keyCount; ++i) {
      var key = keys[i];
      if (changed(key, value[key])) {
        shouldCall = true;
      }
    }
  } else if (changed(name, value)) {
    shouldCall = true;
  }

  if (shouldCall) {
    // Only invoke the callback if we have not called this setter
    // (with a value of this name) before, or the current value is
    // different from the last value we passed to this setter.
    return callback(setter, name, value);
  }
}

// Invoke the given callback once for every (setter, name, value) that needs to
// be called. Note that forEachSetter does not call any setters itself, only the
// given callback.
function forEachSetter(entry, names, callback) {
  var needToCheckNames = true;

  if (names === void 0) {
    names = Object.keys(entry.setters);
    needToCheckNames = false;
  }

  var nameCount = names.length;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];

    if (needToCheckNames &&
        ! hasOwn.call(entry.setters, name)) {
      continue;
    }

    var setters = entry.setters[name];
    var keys = Object.keys(setters);
    var keyCount = keys.length;

    for (var j = 0; j < keyCount; ++j) {
      var key = keys[j];
      var value = getExportByName(entry, name);

      callSetterIfNecessary(setters[key], name, value, callback);

      var getter = entry.getters[name];
      if (typeof getter === "function" &&
          // Sometimes a getter function will throw because it's called
          // before the variable it's supposed to return has been
          // initialized, so we need to know that the getter function has
          // run to completion at least once.
          getter.runCount > 0 &&
          getter.constant) {
        // If we happen to know that this getter function has run
        // successfully, and will never return a different value, then we
        // can forget the corresponding setter, because we've already
        // reported that constant value. Note that we can't forget the
        // getter, because we need to remember the original value in case
        // anyone tampers with entry.exports[name].
        delete setters[key];
      }
    }
  }
}

function getExportByName(entry, name) {
  if (name === "*") {
    return entry.namespace;
  }

  if (hasOwn.call(entry.namespace, name)) {
    return entry.namespace[name];
  }

  var exported = entry.exports;

  if (name === "default" &&
      ! (utils.getESModule(exported) &&
         "default" in exported)) {
    return exported;
  }

  if (exported == null) {
    return;
  }

  return exported[name];
}

function makeUniqueKey() {
  return Math.random()
    .toString(36)
    // Add an incrementing salt to help track key ordering and also
    // absolutely guarantee we never return the same key twice.
    .replace("0.", ++keySalt + "$");
}

function runGetter(entry, name) {
  var getter = entry.getters[name];
  try {
    var result = getter();
    ++getter.runCount;
    return result;
  } catch (e) {}
  return GETTER_ERROR;
}

module.exports = Entry;
<commit_msg>Decompose syncExportsToNamespace helper function.<commit_after>"use strict";

// This module should be compatible with PhantomJS v1, just like the other files
// in reify/lib/runtime. Node 4+ features like const/let and arrow functions are
// not acceptable here, and importing any npm packages should be contemplated
// with extreme skepticism.

var utils = require("./utils.js");

var GETTER_ERROR = {};
var NAN = {};
var UNDEFINED = {};
var weakEntryMap = new WeakMap;
var hasOwn = Object.prototype.hasOwnProperty;
var keySalt = 0;

function Entry(exported) {
  // The module.exports of the module this Entry is managing.
  this.exports = exported;
  // Getters for local variables exported from the managed module.
  this.getters = Object.create(null);
  // Setters for assigning to local variables in parent modules.
  this.setters = Object.create(null);
  // The normalized namespace object that importers receive when they use
  // `import * as namespace from "..."` syntax.
  this.namespace = utils.createNamespace();
  // Map from module.id string to module object for each module this Entry
  // is managing.
  this.ownerModules = Object.create(null);
  // Boolean indicating whether all the modules this Entry is managing
  // have finished loading yet. Call entry.hasLoaded() to compute.
  this._loaded = false;
}

var Ep = utils.setPrototypeOf(Entry.prototype, null);

Entry.get = function (exported) {
  if (utils.isObjectLike(exported) &&
      weakEntryMap.has(exported)) {
    return weakEntryMap.get(exported);
  }
  return null;
};

Entry.getOrCreate = function (exported, mod) {
  var entry = getOrCreate(exported);

  if (utils.isObject(mod)) {
    entry.ownerModules[mod.id] = mod;
  }

  return entry;
};

function getOrCreate(exported) {
  if (! utils.isObjectLike(exported)) {
    // In case the child module modified module.exports, create a temporary
    // Entry object so that we can call the entry.addSetters method once,
    // which will trigger entry.runSetters(names), so that module.importSync
    // behaves as expected.
    return new Entry(exported);
  }

  if (weakEntryMap.has(exported)) {
    return weakEntryMap.get(exported);
  }

  var entry = new Entry(exported);
  weakEntryMap.set(exported, entry);
  return entry;
};

function safeKeys(obj) {
  var keys = Object.keys(obj);
  var esModuleIndex = keys.indexOf("__esModule");
  if (esModuleIndex >= 0) {
    keys.splice(esModuleIndex, 1);
  }
  return keys;
}

Ep.addGetters = function (getters, constant) {
  var names = safeKeys(getters);
  var nameCount = names.length;
  constant = !! constant;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var getter = getters[name];

    if (typeof getter === "function" &&
        // Should this throw if this.getters[name] exists?
        ! (name in this.getters)) {
      this.getters[name] = getter;
      getter.constant = constant;
      getter.runCount = 0;
    }
  }
};

Ep.addSetters = function (parent, setters, key) {
  var names = safeKeys(setters);
  var nameCount = names.length;

  if (! nameCount) {
    return;
  }

  // If no key is provided, make a unique key. Otherwise, make sure the key is
  // distinct from keys provided by other parent modules.
  key = key === void 0
    ? makeUniqueKey()
    : parent.id + ":" + key;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var setter = setters[name];

    if (typeof setter === "function") {
      setter.parent = parent;
      if (! (name in this.setters)) {
        this.setters[name] = Object.create(null);
      }
      this.setters[name][key] = setter;
    }
  }

  this.runSetters(names);
};

Ep.runGetters = function () {
  var names = Object.keys(this.getters);

  // Before running getters, copy anything added to the exports object
  // over to the namespace. Values returned by getters take precedence
  // over these values, but we don't want to miss anything.
  syncExportsToNamespace(this);

  var nameCount = names.length;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];
    var value = runGetter(this, name);

    // If the getter is run without error, update both entry.namespace and
    // module.exports with the current value so that CommonJS require
    // calls remain consistent with module.watch.
    if (value !== GETTER_ERROR) {
      this.namespace[name] = value;
      this.exports[name] = value;
    }
  }
};

function syncExportsToNamespace(entry) {
  if (! utils.getESModule(entry.exports)) {
    // If the module entry is managing overrides module.exports, that
    // value should be exposed as the .default property of the namespace,
    // unless module.exports is marked as an ECMASCript module.
    entry.namespace.default = entry.exports;
  }

  if (utils.isObject(entry.exports)) {
    var exportsKeys = safeKeys(entry.exports);
    var exportsKeyCount = exportsKeys.length;
    for (var i = 0; i < exportsKeyCount; ++i) {
      var key = exportsKeys[i];
      if (typeof Object.getOwnPropertyDescriptor === "function") {
        var desc = Object.getOwnPropertyDescriptor(entry.exports, key);
        if (hasOwn.call(desc, "value")) {
          // If entry.exports[key] is a simple property, simply copy its
          // value over to entry.namespace[key].
          entry.namespace[key] = desc.value;
        } else {
          // Avoid triggering getters until necessary.
          desc.configurable = true;
          Object.defineProperty(entry.namespace, key, desc);
        }
      } else {
        entry.namespace[key] = entry.exports[key];
      }
    }
  }
}

// Called by module.runSetters once the module this Entry is managing has
// finished loading.
Ep.hasLoaded = function () {
  if (this._loaded) {
    return true;
  }

  var ids = Object.keys(this.ownerModules);
  var idCount = ids.length;

  for (var i = 0; i < idCount; ++i) {
    var owner = this.ownerModules[ids[i]];
    if (! owner.loaded && owner.exports === this.exports) {
      // At least one owner module whose exports are still ===
      // this.exports has not finished loading, so this this Entry cannot
      // be marked as loaded yet.
      return false;
    }
  }

  // Set entry._loaded = true only if all the modules in
  // entry.ownerModules that are still associated with entry.exports have
  // finished loading.
  return this._loaded = true;
};

// Called whenever module.exports might have changed, to trigger any
// setters associated with the newly exported values. The names parameter
// is optional; without it, all getters and setters will run.
Ep.runSetters = function (names) {
  // Make sure entry.namespace and module.exports are up to date before we
  // call getExportByName(entry, name).
  this.runGetters();

  // Lazily-initialized object mapping parent module identifiers to parent
  // module objects whose setters we might need to run.
  var parents;

  forEachSetter(this, names, function (setter, name, value) {
    if (parents === void 0) {
      parents = Object.create(null);
    }
    parents[setter.parent.id] = setter.parent;

    // The param order for setters is `value` then `name` because the `name`
    // param is only used by namespace exports.
    setter(value, name);
  });

  if (! parents) {
    return;
  }

  // If any of the setters updated the module.exports of a parent module,
  // or updated local variables that are exported by that parent module,
  // then we must re-run any setters registered by that parent module.
  var parentIDs = Object.keys(parents);
  var parentIDCount = parentIDs.length;

  for (var i = 0; i < parentIDCount; ++i) {
    // What happens if parents[parentIDs[id]] === module, or if
    // longer cycles exist in the parent chain? Thanks to our setter.last
    // bookkeeping above, the runSetters broadcast will only proceed
    // as far as there are any actual changes to report.
    var parent = parents[parentIDs[i]];
    var parentEntry = Entry.get(parent.exports);
    if (parentEntry) {
      parentEntry.runSetters();
    }
  }
};

function callSetterIfNecessary(setter, name, value, callback) {
  if (name === "__esModule") {
    // Ignore setters asking for module.exports.__esModule.
    return;
  }

  if (setter.last === void 0) {
    setter.last = Object.create(null);
  }

  function changed(name, value) {
    var valueToCompare = value;
    if (valueToCompare !== valueToCompare) {
      valueToCompare = NAN;
    } else if (valueToCompare === void 0) {
      valueToCompare = UNDEFINED;
    }

    if (setter.last[name] === valueToCompare) {
      return false;
    }

    setter.last[name] = valueToCompare;
    return true;
  }

  var shouldCall = false;

  if (name === "*") {
    var keys = safeKeys(value);
    var keyCount = keys.length;
    for (var i = 0; i < keyCount; ++i) {
      var key = keys[i];
      if (changed(key, value[key])) {
        shouldCall = true;
      }
    }
  } else if (changed(name, value)) {
    shouldCall = true;
  }

  if (shouldCall) {
    // Only invoke the callback if we have not called this setter
    // (with a value of this name) before, or the current value is
    // different from the last value we passed to this setter.
    return callback(setter, name, value);
  }
}

// Invoke the given callback once for every (setter, name, value) that needs to
// be called. Note that forEachSetter does not call any setters itself, only the
// given callback.
function forEachSetter(entry, names, callback) {
  var needToCheckNames = true;

  if (names === void 0) {
    names = Object.keys(entry.setters);
    needToCheckNames = false;
  }

  var nameCount = names.length;

  for (var i = 0; i < nameCount; ++i) {
    var name = names[i];

    if (needToCheckNames &&
        ! hasOwn.call(entry.setters, name)) {
      continue;
    }

    var setters = entry.setters[name];
    var keys = Object.keys(setters);
    var keyCount = keys.length;

    for (var j = 0; j < keyCount; ++j) {
      var key = keys[j];
      var value = getExportByName(entry, name);

      callSetterIfNecessary(setters[key], name, value, callback);

      var getter = entry.getters[name];
      if (typeof getter === "function" &&
          // Sometimes a getter function will throw because it's called
          // before the variable it's supposed to return has been
          // initialized, so we need to know that the getter function has
          // run to completion at least once.
          getter.runCount > 0 &&
          getter.constant) {
        // If we happen to know that this getter function has run
        // successfully, and will never return a different value, then we
        // can forget the corresponding setter, because we've already
        // reported that constant value. Note that we can't forget the
        // getter, because we need to remember the original value in case
        // anyone tampers with entry.exports[name].
        delete setters[key];
      }
    }
  }
}

function getExportByName(entry, name) {
  if (name === "*") {
    return entry.namespace;
  }

  if (hasOwn.call(entry.namespace, name)) {
    return entry.namespace[name];
  }

  var exported = entry.exports;

  if (name === "default" &&
      ! (utils.getESModule(exported) &&
         "default" in exported)) {
    return exported;
  }

  if (exported == null) {
    return;
  }

  return exported[name];
}

function makeUniqueKey() {
  return Math.random()
    .toString(36)
    // Add an incrementing salt to help track key ordering and also
    // absolutely guarantee we never return the same key twice.
    .replace("0.", ++keySalt + "$");
}

function runGetter(entry, name) {
  var getter = entry.getters[name];
  try {
    var result = getter();
    ++getter.runCount;
    return result;
  } catch (e) {}
  return GETTER_ERROR;
}

module.exports = Entry;
<|endoftext|>