<commit_before>'use strict';
var moment = require('moment');

moment.fn.isBusinessDay = function() {
    return !(this.day() === 0 || this.day() === 6);
};

moment.fn.businessDiff = function(param) {
    param = moment(param);
    var signal = param.unix() < this.unix()?1:-1;
    var start = moment.min(param, this).clone();
    var end = moment.max(param, this).clone();
    var start_offset = start.day() - 7;
    var end_offset = end.day();

    var end_sunday = end.clone().subtract('d', end_offset);
    var start_sunday = start.clone().subtract('d', start_offset);
    var weeks = end_sunday.diff(start_sunday, 'days') / 7;

    start_offset = Math.abs(start_offset);
    if (start_offset == 7) {
      start_offset = 5;
    } else if (start_offset == 1) {
      start_offset = 0;
    } else {
      start_offset -= 2;
    };

    if (end_offset == 6) {
      end_offset--;
    };

    return signal * (weeks * 5 + start_offset + end_offset);
};

moment.fn.businessAdd = function(days) {
    var signal = days < 0 ? -1 : 1;
    days = Math.abs(days);
    var d = this.clone().add(Math.floor(days / 5) * 7 * signal, 'd');
    var remaining = days % 5;
    while (remaining) {
      d.add(signal, 'd');
      if (d.isBusinessDay()) {
        remaining--;
      };
    };
    return d;
};

moment.fn.businessSubtract = function(days) {
    return this.businessAdd(-days);
};

moment.fn.nextBusinessDay = function() {
    var loop = 1;
    var limit = 7;
    while (loop < limit) {
        if (this.add(1, 'd').isBusinessDay()) {
            break;
        };
        loop++;
    };
    return this;
};

moment.fn.monthBusinessDays = function() {
    var me = this.clone();
    var day = me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var daysArr = [];
    var done = false;
    while (!done) {
        if (day.isBusinessDay()) {
            daysArr.push(day.clone());
        };
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return daysArr;
};

moment.fn.monthNaturalDays = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var daysArr = [];
    var done = false;
    while (!done) {
        daysArr.push(day.clone());
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return daysArr;
};

moment.fn.monthBusinessWeeks = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var weeksArr = [];
    var daysArr = [];
    var done = false;

    while(!done) {
        if(day.day() >= 1 && day.day() < 6) {
            daysArr.push(day.clone());
        };
        if(day.day() === 5) {
            weeksArr.push(daysArr);
            daysArr = [];
        };
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return weeksArr;
};

moment.fn.monthNaturalWeeks = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var weeksArr = [];
    var daysArr = [];
    var done = false;

    while(!done) {
        daysArr.push(day.clone());
        if(day.day() === 6) {
            weeksArr.push(daysArr);
            daysArr = [];
        };
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return weeksArr;
};

module.exports = moment;
<commit_msg>las month days err fixed<commit_after>'use strict';
var moment = require('moment');

moment.fn.isBusinessDay = function() {
    return !(this.day() === 0 || this.day() === 6);
};

moment.fn.businessDiff = function(param) {
    param = moment(param);
    var signal = param.unix() < this.unix()?1:-1;
    var start = moment.min(param, this).clone();
    var end = moment.max(param, this).clone();
    var start_offset = start.day() - 7;
    var end_offset = end.day();

    var end_sunday = end.clone().subtract('d', end_offset);
    var start_sunday = start.clone().subtract('d', start_offset);
    var weeks = end_sunday.diff(start_sunday, 'days') / 7;

    start_offset = Math.abs(start_offset);
    if (start_offset == 7) {
      start_offset = 5;
    } else if (start_offset == 1) {
      start_offset = 0;
    } else {
      start_offset -= 2;
    };

    if (end_offset == 6) {
      end_offset--;
    };

    return signal * (weeks * 5 + start_offset + end_offset);
};

moment.fn.businessAdd = function(days) {
    var signal = days < 0 ? -1 : 1;
    days = Math.abs(days);
    var d = this.clone().add(Math.floor(days / 5) * 7 * signal, 'd');
    var remaining = days % 5;
    while (remaining) {
      d.add(signal, 'd');
      if (d.isBusinessDay()) {
        remaining--;
      };
    };
    return d;
};

moment.fn.businessSubtract = function(days) {
    return this.businessAdd(-days);
};

moment.fn.nextBusinessDay = function() {
    var loop = 1;
    var limit = 7;
    while (loop < limit) {
        if (this.add(1, 'd').isBusinessDay()) {
            break;
        };
        loop++;
    };
    return this;
};

moment.fn.monthBusinessDays = function() {
    var me = this.clone();
    var day = me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var daysArr = [];
    var done = false;
    while (!done) {
        if (day.isBusinessDay()) {
            daysArr.push(day.clone());
        };
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return daysArr;
};

moment.fn.monthNaturalDays = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var daysArr = [];
    var done = false;
    while (!done) {
        daysArr.push(day.clone());
        if(end.diff(day.add(1,'d')) < 0) {
            done = true;
        };
    };
    return daysArr;
};

moment.fn.monthBusinessWeeks = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var weeksArr = [];
    var daysArr = [];
    var done = false;

    while(!done) {
        if(day.day() >= 1 && day.day() < 6) {
            daysArr.push(day.clone());
        };
        if(day.day() === 5) {
            weeksArr.push(daysArr);
            daysArr = [];
        };
        if(end.diff(day.add(1,'d')) < 0) {
            if(daysArr.length < 5) {
                weeksArr.push(daysArr);
            };
            done = true;
        };
    };
    return weeksArr;
};

moment.fn.monthNaturalWeeks = function(fromToday) {
    var me = this.clone();
    var day = fromToday ? me.clone() : me.clone().startOf('month');
    var end = me.clone().endOf('month');
    var weeksArr = [];
    var daysArr = [];
    var done = false;

    while(!done) {
        daysArr.push(day.clone());
        if(day.day() === 6) {
            weeksArr.push(daysArr);
            daysArr = [];
        };
        if(end.diff(day.add(1,'d')) < 0) {
            if(daysArr.length < 7) {
                weeksArr.push(daysArr);
            };
            done = true;
        };
    };
    return weeksArr;
};

module.exports = moment;
<|endoftext|>


<commit_before>'use strict';
module.exports = function (str) {
	if (typeof str !== 'string') {
		throw new TypeError('Expected a string');
	}

	var currentChar = '';
	var nextChar = '';
	var insideString = false;
	var insideComment = false;
	var ret = '';

	for (var i = 0; i < str.length; i++) {
		currentChar = str[i];
		nextChar = str[i + 1];

		if (!insideComment && str[i - 1] !== '\\') {
			if (currentChar === '"' || currentChar === '\'') {
				if (insideString === currentChar) {
					insideString = false;
				} else if (!insideString) {
					insideString = currentChar;
				}
			}
		}

		if (insideString) {
			ret += currentChar;
			continue;
		}

		if (!insideComment && currentChar + nextChar === '/*') {
			insideComment = true;
			i++;
			continue;
		}

		if (insideComment && currentChar + nextChar === '*/') {
			insideComment = false;
			i++;
			continue;
		}

		if (insideComment) {
			continue;
		}

		ret += currentChar;
	}

	return ret;
}
<commit_msg>improve performance see #1<commit_after>'use strict';
module.exports = function (str) {
	if (typeof str !== 'string') {
		throw new TypeError('Expected a string');
	}

	var currentChar = '';
	var nextChar = '';
	var insideString = false;
	var ret = '';

	for (var i = 0, strLength = str.length; i < strLength; i++) {
		currentChar = str[i];

		if (str[i - 1] !== '\\') {
			if (currentChar === '"' || currentChar === '\'') {
				if (insideString === currentChar) {
					insideString = false;
				} else if (!insideString) {
					insideString = currentChar;
				}
			}
		}

		if (insideString) {
			ret += currentChar;
			continue;
		}

		nextChar = str[i + 1];
		//start /* type comment
		if (currentChar + nextChar === '/*') {
			//start skipping until we reach end of comment
			for (var j = i + 2; j < strLength; j++) {
				if (str[j] + str[j + 1] === '*/') {
					break;
				}
			}
			//skip i to the end of the comment
			i = j + 1;
			continue;
		}

		ret += currentChar;
	}

	return ret;
};
<|endoftext|>


<commit_before>var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 5000));

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

app.get('/css/', function (req, res) {
	res.sendFile(__dirname + req.url);
});

app.get('/js/', function (req, res) {
	res.sendFile(__dirname = req.url);
})

app.listen(app.get('port'), function () {
  console.log("Node app is running on port:" + app.get('port'));
});<commit_msg>Checking the css directory<commit_after>var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 5000));

app.get('/', function (req, res) {
	res.send(__dirname + '/css');
});

app.get('/css/', function (req, res) {
	res.sendFile(__dirname + req.url);
});

app.get('/js/', function (req, res) {
	res.sendFile(__dirname = req.url);
})

app.listen(app.get('port'), function () {
  console.log("Node app is running on port:" + app.get('port'));
});<|endoftext|>


<commit_before>const PORT = 8080;
const SESSION_SECRET = process.env.TANDEM_SESSION_SECRET;
const SOUNDCLOUD_APP_ID = process.env.TANDEM_SOUNDCLOUD_APP_ID;
const SOUNDCLOUD_APP_SECRET = process.env.TANDEM_SOUNDCLOUD_APP_SECRET;
const YOUTUBE_APP_ID = process.env.TANDEM_YOUTUBE_APP_ID;
const YOUTUBE_APP_SECRET = process.env.TANDEM_YOUTUBE_APP_SECRET;
const YOUTUBE_API_KEY = process.env.TANDEM_YOUTUBE_API_KEY;
const MONGO_URL = process.env.TANDEM_MONGO_URL || 'mongodb://localhost/tandem';
const URL = process.env.TANDEM_URL || 'http://dev.tandem.io:8080';
const ENV = process.env.NODE_ENV || 'development';
const SOUNDCLOUD_API_BASE_URL = 'https://api.soundcloud.com';
const YOUTUBE_API_BASE_URL = 'https://www.googleapis.com/youtube/v3';
const SENTRY_DSN = process.env.TANDEM_SENTRY_DSN;
const VIEWS_PATH = __dirname +'/views';
const NO_OP = function(){};

var http = require('http');
var socket_io = require('socket.io');
var async = require('async');
var _ = require('underscore');
var request = require('request');
var express = require('express');
var expose = require('express-expose');
var server = express();
var http_server = http.createServer( server );
var io = socket_io.listen( http_server );

var generateAuthToken = require('./utils/generateAuthToken.js');

var Room = require('./models/room.js')({ io: io });

// Database
var mongoose = require('mongoose');
var User = require('./db/models/user.js');
mongoose.connect( MONGO_URL );

// Set up templates for Express
var express_handlebars = require('express-hbs');
var handlebars = express_handlebars.express3({
	extname: '.hbs',
	defaultLayout: VIEWS_PATH +'/layouts/main.hbs',
	partialsDir: VIEWS_PATH +'/partials',
	layoutsDir: VIEWS_PATH +'/layouts'
});
server.engine( 'hbs', handlebars );
server.set( 'view engine', 'hbs' );
server.set( 'views', VIEWS_PATH );

// Sessions
var MongoStore = require('connect-mongo')( express );
server.use( express.cookieParser() );
server.use( express.bodyParser() );
server.use( express.session({
	secret: SESSION_SECRET,
	cookie: {
		maxAge: 1000 * 60 * 60 * 24 * 14 // 2 weeks from now
	},
	store: new MongoStore({
		url: MONGO_URL
	})
}) );

// Routes
server.use( server.router );

// Compress responses
server.use( express.compress() );

// Static file serving
server.use( express.static( __dirname + '/assets' ) );

// Exception tracking
if( SENTRY_DSN ){
	var raven = require('raven');
	server.use( raven.middleware.express( SENTRY_DSN ) );
}

// Socket.io configuration
io.use( function( socket, next ){
	var auth_data = _.pick( socket.request._query, 'id', 'name', 'avatar', 'token' );
	var is_authentic = ( generateAuthToken( auth_data.id, auth_data.name, auth_data.avatar ) === auth_data.token );
	if( !is_authentic ){
		next( new Error('Invalid user token') );
		return;
	}
	socket.auth_data = auth_data;
	next();
});

// Pass environment to views
server.locals.dev = ( ENV === 'development' );

// Passport stuff
var passport = require('passport');
var guestSetup = require('./middleware/guest.js');

server.use( passport.initialize() );
server.use( passport.session() );
server.use( guestSetup );

passport.serializeUser( function( user, done ){
	done( null, user );
});

passport.deserializeUser( function( obj, done ){
	done( null, obj );
});

// Soundcloud login
var passport_soundcloud = require('passport-soundcloud');
var SoundcloudStrategy = passport_soundcloud.Strategy;

passport.use( new SoundcloudStrategy({
	clientID: SOUNDCLOUD_APP_ID,
	clientSecret: SOUNDCLOUD_APP_SECRET,
	callbackURL: URL +'/auth/soundcloud/callback',
	passReqToCallback: true
}, function( req, access_token, refresh_token, params, profile, done ){
	var auth_data = {
		provider: 'soundcloud',
		client_id: profile.id,
		access_token: access_token
	};
	User.findOrCreate( auth_data, req.user, function( err, user ){
		if( err ) return done( err, null );
		var user_json = user.toJSON();
		// if we already have a user session, merge them
		if( req.user ){
			user_json = _.extend( req.user, user_json );
		}
		done( null, user_json );
	});
}));

// Youtube login
var passport_google = require('passport-google-oauth');
var GoogleStrategy = passport_google.OAuth2Strategy;

var getLikesID = function( access_token, callback ){
	callback = callback || NO_OP;
	request({
		url: YOUTUBE_API_BASE_URL +'/channels',
		qs: {
			part: 'contentDetails',
			mine: true
		},
		headers: {
			'Authorization': 'Bearer '+ access_token
		},
		method: 'GET',
		json: true
	}, function( err, res, body ){
		callback( err, body.items[0].contentDetails.relatedPlaylists.likes );
	});
};

passport.use( new GoogleStrategy({
	clientID: YOUTUBE_APP_ID,
	clientSecret: YOUTUBE_APP_SECRET,
	callbackURL: URL +'/auth/youtube/callback',
	profileURL: 'https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true',
	passReqToCallback: true
}, function( req, access_token, refresh_token, params, profile, done ){
	getLikesID( access_token, function( err, likes_id ){
		if( err ) return done( err, null );
		var auth_data = {
			provider: 'youtube',
			client_id: profile.id,
			access_token: access_token,
			access_token_expiry: Date.now() + ( params.expires_in * 1000 ),
			refresh_token: refresh_token,
			likes_id: likes_id
		};
		User.findOrCreate( auth_data, req.user, function( err, user ){
			if( err ) return done( err, null );
			var user_json = user.toJSON();
			// if we already have a user session, merge them
			if( req.user ){
				user_json = _.extend( req.user, user_json );
			}
			done( null, user_json );
		});
	});
}));

// Routes
server.get( '/auth/soundcloud',	passport.authenticate( 'soundcloud', {
	scope: 'non-expiring'
}));

server.get( '/auth/soundcloud/callback', passport.authenticate( 'soundcloud', {
	successRedirect: '/',
	failureRedirect: '/?err=soundcloud-login-failed'
}));

server.get( '/auth/soundcloud/unlink', function( req, res ){
	if( !req.user.soundcloud ) res.redirect('/');
	User.unlinkProvider( req.user.id, 'soundcloud', function( err ){
		req.user.soundcloud = null;
		res.redirect('/');
	});
});

server.get( '/auth/youtube', passport.authenticate( 'google', {
	scope: 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
	accessType: 'offline',
	approvalPrompt: 'force'
}));

server.get( '/auth/youtube/unlink', function( req, res ){
	if( !req.user.youtube ) res.redirect('/');
	User.unlinkProvider( req.user.id, 'youtube', function( err ){
		req.user.youtube = null;
		res.redirect('/');
	});
});

server.get( '/auth/youtube/callback', passport.authenticate( 'google', {
	successRedirect: '/',
	failureRedirect: '/?err=youtube-login-failed'
}));

server.post( '/api/v1/rooms', function( req, res ){
	var room = new Room;
	room.save( function( err, room ){
		res.json( room );
	});
});

server.get( '/api/v1/rooms/:id?', function( req, res ){
	if( req.params.id ){
		Room.findById( req.params.id, function( err, room ){
			res.json( room );
		});
	}
	else {
		Room.find( function( err, rooms ){
			res.json( rooms );
		});
	}
});

server.put( '/api/v1/rooms/:id', function( req, res ){
	var new_data = _.omit( req.body, '_id' );
	Room.findByIdAndUpdate( req.params.id, new_data, function( err, room ){
		res.json( room );
	});
});

server.delete( '/api/v1/rooms/:id', function( req, res ){
	Room.findByIdAndRemove( req.params.id, function( err, room ){
		res.json( room );
	});
});

server.all( /^\/api\/v1\/proxy\/soundcloud\/(.+)$/, function( req, res ){
	if( !req.user.soundcloud ) return res.json( 500, { error: 'Error: User has no SoundCloud credentials' });
	if( !req.user.soundcloud.access_token ) return res.json( 500, { error: 'Error: Missing access token' });
	var query = _.extend( req.query, {
		oauth_token: req.user.soundcloud.access_token
	});
	var endpoint = req.params[0];
	request({
		url: SOUNDCLOUD_API_BASE_URL +'/'+ endpoint,
		qs: query,
		method: req.method
	}).pipe( res );
});

// use refresh_token to get a new access_token
var refreshYouTubeToken = function( refresh_token, cb ){
	request({
		url: 'https://accounts.google.com/o/oauth2/token',
		form: {
			client_id: YOUTUBE_APP_ID,
			client_secret: YOUTUBE_APP_SECRET,
			refresh_token: refresh_token,
			grant_type: 'refresh_token'
		},
		method: 'POST'
	}, function( err, res, body ){
		if( err ) return cb( err, null );
		body = JSON.parse( body );
		if( body.error ) return cb( new Error( body.error +' '+ body.error_description ), null );
		cb( null, body.access_token, body.expires_in );
	});
};

server.all( /^\/api\/v1\/proxy\/youtube\/(.+)$/, function( req, res ){
	if( !req.user.youtube ) return res.json( 500, { error: 'Error: User has no YouTube credentials' });
	if( !req.user.youtube.access_token ) return res.json( 500, { error: 'Error: Missing access token' });
	async.waterfall([ function checkToken( next ){
		if( Date.now() > req.user.youtube.access_token_expiry ){
			refreshYouTubeToken( req.user.youtube.refresh_token, function( err, access_token, expires_in ){
				if( err ) return next( err, null );
				req.user.youtube.access_token = access_token;
				req.user.youtube.access_token_expiry = Date.now() + ( expires_in * 1000 );
				next( null, access_token );
			});
		}
		else {
			next( null, req.user.youtube.access_token );
		}
	}, function makeRequest( access_token, next ){
		var query = _.extend( req.query, {
			key: YOUTUBE_API_KEY
		});
		var endpoint = req.params[0];
		var proxied_request = request({
			url: YOUTUBE_API_BASE_URL +'/'+ endpoint,
			qs: query,
			json: !_.isEmpty( req.body ) ? req.body : null,
			headers: {
				'Authorization': 'Bearer '+ access_token
			},
			method: req.method
		});
		next( null, proxied_request );
	}], function( err, proxied_request ){
		if( err ) return res.json( 500, { error: err.toString() });
		proxied_request.pipe( res );
	});
});

server.get( '/logout', function( req, res ){
	req.logout();
	res.redirect('/');
});

server.post( '/rooms', function( req, res ){
	var room = new Room;
	res.redirect( '/rooms/'+ room.id );
});

server.get( '/rooms/:id', function( req, res ){
	var user = req.session.passport.user || {};
	user = _.pick( user, 'id', 'name', 'avatar', 'youtube', 'soundcloud' );
	user.token = generateAuthToken( user.id, user.name, user.avatar );
	var room = Room.findById( req.params.id, true );
	res.expose( room, 'tandem.bridge.room' );
	res.expose( user, 'tandem.bridge.user' );
	res.expose( {
		soundcloud: {
			client_id: SOUNDCLOUD_APP_ID
		}
	}, 'tandem.bridge.apis' );
	res.render( 'room.hbs', {
		room: room,
		user: user
	});
});

var renderIndex = function( req, res ){
	var rooms = Room.list( true );
	res.render( 'index.hbs', {
		rooms: rooms
	});
};

server.get( '/', renderIndex );
server.get( '/rooms/:id', renderIndex );

http_server.listen( PORT );

console.log('[tandem] listening on port', PORT );
<commit_msg>60 properly order middleware fixes #60 fixes #58<commit_after>const PORT = 8080;
const SESSION_SECRET = process.env.TANDEM_SESSION_SECRET;
const SOUNDCLOUD_APP_ID = process.env.TANDEM_SOUNDCLOUD_APP_ID;
const SOUNDCLOUD_APP_SECRET = process.env.TANDEM_SOUNDCLOUD_APP_SECRET;
const YOUTUBE_APP_ID = process.env.TANDEM_YOUTUBE_APP_ID;
const YOUTUBE_APP_SECRET = process.env.TANDEM_YOUTUBE_APP_SECRET;
const YOUTUBE_API_KEY = process.env.TANDEM_YOUTUBE_API_KEY;
const MONGO_URL = process.env.TANDEM_MONGO_URL || 'mongodb://localhost/tandem';
const URL = process.env.TANDEM_URL || 'http://dev.tandem.io:8080';
const ENV = process.env.NODE_ENV || 'development';
const SOUNDCLOUD_API_BASE_URL = 'https://api.soundcloud.com';
const YOUTUBE_API_BASE_URL = 'https://www.googleapis.com/youtube/v3';
const SENTRY_DSN = process.env.TANDEM_SENTRY_DSN;
const VIEWS_PATH = __dirname +'/views';
const NO_OP = function(){};

var http = require('http');
var socket_io = require('socket.io');
var async = require('async');
var _ = require('underscore');
var request = require('request');
var express = require('express');
var expose = require('express-expose');
var server = express();
var http_server = http.createServer( server );
var io = socket_io.listen( http_server );

var generateAuthToken = require('./utils/generateAuthToken.js');

var Room = require('./models/room.js')({ io: io });

// Database
var mongoose = require('mongoose');
var User = require('./db/models/user.js');
mongoose.connect( MONGO_URL );

// Set up templates for Express
var express_handlebars = require('express-hbs');
var handlebars = express_handlebars.express3({
	extname: '.hbs',
	defaultLayout: VIEWS_PATH +'/layouts/main.hbs',
	partialsDir: VIEWS_PATH +'/partials',
	layoutsDir: VIEWS_PATH +'/layouts'
});
server.engine( 'hbs', handlebars );
server.set( 'view engine', 'hbs' );
server.set( 'views', VIEWS_PATH );

// Sessions
var MongoStore = require('connect-mongo')( express );
server.use( express.cookieParser() );
server.use( express.bodyParser() );
server.use( express.session({
	secret: SESSION_SECRET,
	cookie: {
		maxAge: 1000 * 60 * 60 * 24 * 14 // 2 weeks from now
	},
	store: new MongoStore({
		url: MONGO_URL
	})
}) );

// Compress responses
server.use( express.compress() );

// Static file serving
server.use( express.static( __dirname + '/assets' ) );

// Exception tracking
if( SENTRY_DSN ){
	var raven = require('raven');
	server.use( raven.middleware.express( SENTRY_DSN ) );
}

// Socket.io configuration
io.use( function( socket, next ){
	var auth_data = _.pick( socket.request._query, 'id', 'name', 'avatar', 'token' );
	var is_authentic = ( generateAuthToken( auth_data.id, auth_data.name, auth_data.avatar ) === auth_data.token );
	if( !is_authentic ){
		next( new Error('Invalid user token') );
		return;
	}
	socket.auth_data = auth_data;
	next();
});

// Pass environment to views
server.locals.dev = ( ENV === 'development' );

// Passport stuff
var passport = require('passport');
var guestSetup = require('./middleware/guest.js');

server.use( passport.initialize() );
server.use( passport.session() );
server.use( guestSetup );

// Routing comes last
server.use( server.router );

passport.serializeUser( function( user, done ){
	done( null, user );
});

passport.deserializeUser( function( obj, done ){
	done( null, obj );
});

// Soundcloud login
var passport_soundcloud = require('passport-soundcloud');
var SoundcloudStrategy = passport_soundcloud.Strategy;

passport.use( new SoundcloudStrategy({
	clientID: SOUNDCLOUD_APP_ID,
	clientSecret: SOUNDCLOUD_APP_SECRET,
	callbackURL: URL +'/auth/soundcloud/callback',
	passReqToCallback: true
}, function( req, access_token, refresh_token, params, profile, done ){
	var user_session = req.session.passport.user;
	var auth_data = {
		provider: 'soundcloud',
		client_id: profile.id,
		access_token: access_token
	};
	User.findOrCreate( auth_data, user_session, function( err, user ){
		if( err ) return done( err, null );
		var user_json = user.toJSON();
		// if we already have a user session, merge them
		if( user_session ){
			user_json = _.extend( user_session, user_json );
		}
		done( null, user_json );
	});
}));

// Youtube login
var passport_google = require('passport-google-oauth');
var GoogleStrategy = passport_google.OAuth2Strategy;

var getLikesID = function( access_token, callback ){
	callback = callback || NO_OP;
	request({
		url: YOUTUBE_API_BASE_URL +'/channels',
		qs: {
			part: 'contentDetails',
			mine: true
		},
		headers: {
			'Authorization': 'Bearer '+ access_token
		},
		method: 'GET',
		json: true
	}, function( err, res, body ){
		callback( err, body.items[0].contentDetails.relatedPlaylists.likes );
	});
};

passport.use( new GoogleStrategy({
	clientID: YOUTUBE_APP_ID,
	clientSecret: YOUTUBE_APP_SECRET,
	callbackURL: URL +'/auth/youtube/callback',
	profileURL: 'https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true',
	passReqToCallback: true
}, function( req, access_token, refresh_token, params, profile, done ){
	getLikesID( access_token, function( err, likes_id ){
		if( err ) return done( err, null );
		var user_session = req.session.passport.user;
		var auth_data = {
			provider: 'youtube',
			client_id: profile.id,
			access_token: access_token,
			access_token_expiry: Date.now() + ( params.expires_in * 1000 ),
			refresh_token: refresh_token,
			likes_id: likes_id
		};
		User.findOrCreate( auth_data, user_session, function( err, user ){
			if( err ) return done( err, null );
			var user_json = user.toJSON();
			// if we already have a user session, merge them
			if( user_session ){
				user_json = _.extend( user_session, user_json );
			}
			done( null, user_json );
		});
	});
}));

// Routes
server.get( '/auth/soundcloud',	passport.authenticate( 'soundcloud', {
	scope: 'non-expiring'
}));

server.get( '/auth/soundcloud/callback', passport.authenticate( 'soundcloud', {
	successRedirect: '/',
	failureRedirect: '/?err=soundcloud-login-failed'
}));

server.get( '/auth/soundcloud/unlink', function( req, res ){
	if( !req.user.soundcloud ) res.redirect('/');
	User.unlinkProvider( req.user.id, 'soundcloud', function( err ){
		req.user.soundcloud = null;
		res.redirect('/');
	});
});

server.get( '/auth/youtube', passport.authenticate( 'google', {
	scope: 'https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile',
	accessType: 'offline',
	approvalPrompt: 'force'
}));

server.get( '/auth/youtube/unlink', function( req, res ){
	if( !req.user.youtube ) res.redirect('/');
	User.unlinkProvider( req.user.id, 'youtube', function( err ){
		req.user.youtube = null;
		res.redirect('/');
	});
});

server.get( '/auth/youtube/callback', passport.authenticate( 'google', {
	successRedirect: '/',
	failureRedirect: '/?err=youtube-login-failed'
}));

server.post( '/api/v1/rooms', function( req, res ){
	var room = new Room;
	room.save( function( err, room ){
		res.json( room );
	});
});

server.get( '/api/v1/rooms/:id?', function( req, res ){
	if( req.params.id ){
		Room.findById( req.params.id, function( err, room ){
			res.json( room );
		});
	}
	else {
		Room.find( function( err, rooms ){
			res.json( rooms );
		});
	}
});

server.put( '/api/v1/rooms/:id', function( req, res ){
	var new_data = _.omit( req.body, '_id' );
	Room.findByIdAndUpdate( req.params.id, new_data, function( err, room ){
		res.json( room );
	});
});

server.delete( '/api/v1/rooms/:id', function( req, res ){
	Room.findByIdAndRemove( req.params.id, function( err, room ){
		res.json( room );
	});
});

server.all( /^\/api\/v1\/proxy\/soundcloud\/(.+)$/, function( req, res ){
	if( !req.user.soundcloud ) return res.json( 500, { error: 'Error: User has no SoundCloud credentials' });
	if( !req.user.soundcloud.access_token ) return res.json( 500, { error: 'Error: Missing access token' });
	var query = _.extend( req.query, {
		oauth_token: req.user.soundcloud.access_token
	});
	var endpoint = req.params[0];
	request({
		url: SOUNDCLOUD_API_BASE_URL +'/'+ endpoint,
		qs: query,
		method: req.method
	}).pipe( res );
});

// use refresh_token to get a new access_token
var refreshYouTubeToken = function( refresh_token, cb ){
	request({
		url: 'https://accounts.google.com/o/oauth2/token',
		form: {
			client_id: YOUTUBE_APP_ID,
			client_secret: YOUTUBE_APP_SECRET,
			refresh_token: refresh_token,
			grant_type: 'refresh_token'
		},
		method: 'POST'
	}, function( err, res, body ){
		if( err ) return cb( err, null );
		body = JSON.parse( body );
		if( body.error ) return cb( new Error( body.error +' '+ body.error_description ), null );
		cb( null, body.access_token, body.expires_in );
	});
};

server.all( /^\/api\/v1\/proxy\/youtube\/(.+)$/, function( req, res ){
	if( !req.user.youtube ) return res.json( 500, { error: 'Error: User has no YouTube credentials' });
	if( !req.user.youtube.access_token ) return res.json( 500, { error: 'Error: Missing access token' });
	async.waterfall([ function checkToken( next ){
		if( Date.now() > req.user.youtube.access_token_expiry ){
			refreshYouTubeToken( req.user.youtube.refresh_token, function( err, access_token, expires_in ){
				if( err ) return next( err, null );
				req.user.youtube.access_token = access_token;
				req.user.youtube.access_token_expiry = Date.now() + ( expires_in * 1000 );
				next( null, access_token );
			});
		}
		else {
			next( null, req.user.youtube.access_token );
		}
	}, function makeRequest( access_token, next ){
		var query = _.extend( req.query, {
			key: YOUTUBE_API_KEY
		});
		var endpoint = req.params[0];
		var proxied_request = request({
			url: YOUTUBE_API_BASE_URL +'/'+ endpoint,
			qs: query,
			json: !_.isEmpty( req.body ) ? req.body : null,
			headers: {
				'Authorization': 'Bearer '+ access_token
			},
			method: req.method
		});
		next( null, proxied_request );
	}], function( err, proxied_request ){
		if( err ) return res.json( 500, { error: err.toString() });
		proxied_request.pipe( res );
	});
});

server.get( '/logout', function( req, res ){
	req.logout();
	res.redirect('/');
});

server.post( '/rooms', function( req, res ){
	var room = new Room;
	res.redirect( '/rooms/'+ room.id );
});

server.get( '/rooms/:id', function( req, res ){
	var user = req.session.passport.user || {};
	user = _.pick( user, 'id', 'name', 'avatar', 'youtube', 'soundcloud' );
	user.token = generateAuthToken( user.id, user.name, user.avatar );
	var room = Room.findById( req.params.id, true );
	res.expose( room, 'tandem.bridge.room' );
	res.expose( user, 'tandem.bridge.user' );
	res.expose( {
		soundcloud: {
			client_id: SOUNDCLOUD_APP_ID
		}
	}, 'tandem.bridge.apis' );
	res.render( 'room.hbs', {
		room: room,
		user: user
	});
});

var renderIndex = function( req, res ){
	var rooms = Room.list( true );
	res.render( 'index.hbs', {
		rooms: rooms
	});
};

server.get( '/', renderIndex );
server.get( '/rooms/:id', renderIndex );

http_server.listen( PORT );

console.log('[tandem] listening on port', PORT );
<|endoftext|>


<commit_before>var lexint = require('lexicographic-integer')
var collect = require('stream-collector')
var through = require('through2')
var from = require('from2')
var pump = require('pump')

var noop = function () {}

var Logs = function (db, opts) {
  if (!(this instanceof Logs)) return new Logs(db, opts)
  if (!opts) opts = {}

  this.db = db
  this.sep = opts.separator || opts.sep || '!'
  this.prefix = opts.prefix ? this.sep + opts.prefix + this.sep : ''
  this.valueEncoding = opts.valueEncoding
}

Logs.prototype.key = function (log, seq) {
  return this.prefix + log + this.sep + (seq === -1 ? '\xff' : lexint.pack(seq, 'hex'))
}

Logs.prototype.list = function (cb) {
  var self = this
  var prev = this.prefix
  var end = prev + '\xff'

  var rs = from.obj(function (size, cb) {
    collect(self.db.createKeyStream({gt: prev, lt: end, limit: 1}), function (err, keys) {
      if (err) return cb(err)

      if (!keys.length) return cb(null, null)
      var log = keys[0].slice(self.prefix.length, keys[0].lastIndexOf(self.sep))
      prev = self.key(log, -1)

      cb(null, log)
    })
  })

  return collect(rs, cb)
}

Logs.prototype.get = function (log, seq, cb) {
  this.db.get(this.key(log, seq), {valueEncoding: this.valueEncoding}, cb)
}

Logs.prototype.put = function (log, seq, value, cb) {
  this.db.put(this.key(log, seq), value, {valueEncoding: this.valueEncoding}, cb)
}

Logs.prototype.append = function (log, value, cb) {
  if (!cb) cb = noop
  var self = this

  this.head(log, function (err, seq) {
    if (err) return cb(err)
    self.put(log, seq + 1, value, function (err) {
      if (err) return cb(err)
      cb(null, seq + 1)
    })
  })
}

Logs.prototype.head = function (log, cb) {
  var self = this

  var keys = this.db.createKeyStream({
    gt: this.key(log, 0),
    lt: this.key(log, -1),
    reverse: true,
    limit: 1
  })

  collect(keys, function (err, head) {
    if (err) return cb(err)
    cb(null, head.length ? lexint.unpack(head[0].slice(head[0].lastIndexOf(self.sep) + 1), 'hex') : 0)
  })
}

Logs.prototype.createValueStream = function (log, opts) {
  if (!opts) opts = {}
  return this.db.createValueStream({
    gt: this.key(log, opts.since || 0),
    lt: this.key(log, opts.until || -1),
    valueEncoding: this.valueEncoding,
    reverse: opts.reverse
  })
}

Logs.prototype.createReadStream = function (log, opts) {
  if (!opts) opts = {}

  var self = this

  var rs = this.db.createReadStream({
    gt: this.key(log, opts.since || 0),
    lt: this.key(log, opts.until || -1),
    valueEncoding: this.valueEncoding,
    reverse: opts.reverse
  })

  var format = through.obj(function (data, enc, cb) {
    var key = data.key
    var log = key.slice(self.prefix.length, key.lastIndexOf(self.sep))
    var seq = lexint.unpack(key.slice(self.prefix.length + log.length + 1), 'hex')
    cb(null, {log: log, seq: seq, value: data.value})
  })

  return pump(rs, format)
}

module.exports = Logs
<commit_msg>support limit option (#2)<commit_after>var lexint = require('lexicographic-integer')
var collect = require('stream-collector')
var through = require('through2')
var from = require('from2')
var pump = require('pump')

var noop = function () {}

var Logs = function (db, opts) {
  if (!(this instanceof Logs)) return new Logs(db, opts)
  if (!opts) opts = {}

  this.db = db
  this.sep = opts.separator || opts.sep || '!'
  this.prefix = opts.prefix ? this.sep + opts.prefix + this.sep : ''
  this.valueEncoding = opts.valueEncoding
}

Logs.prototype.key = function (log, seq) {
  return this.prefix + log + this.sep + (seq === -1 ? '\xff' : lexint.pack(seq, 'hex'))
}

Logs.prototype.list = function (cb) {
  var self = this
  var prev = this.prefix
  var end = prev + '\xff'

  var rs = from.obj(function (size, cb) {
    collect(self.db.createKeyStream({gt: prev, lt: end, limit: 1}), function (err, keys) {
      if (err) return cb(err)

      if (!keys.length) return cb(null, null)
      var log = keys[0].slice(self.prefix.length, keys[0].lastIndexOf(self.sep))
      prev = self.key(log, -1)

      cb(null, log)
    })
  })

  return collect(rs, cb)
}

Logs.prototype.get = function (log, seq, cb) {
  this.db.get(this.key(log, seq), {valueEncoding: this.valueEncoding}, cb)
}

Logs.prototype.put = function (log, seq, value, cb) {
  this.db.put(this.key(log, seq), value, {valueEncoding: this.valueEncoding}, cb)
}

Logs.prototype.append = function (log, value, cb) {
  if (!cb) cb = noop
  var self = this

  this.head(log, function (err, seq) {
    if (err) return cb(err)
    self.put(log, seq + 1, value, function (err) {
      if (err) return cb(err)
      cb(null, seq + 1)
    })
  })
}

Logs.prototype.head = function (log, cb) {
  var self = this

  var keys = this.db.createKeyStream({
    gt: this.key(log, 0),
    lt: this.key(log, -1),
    reverse: true,
    limit: 1
  })

  collect(keys, function (err, head) {
    if (err) return cb(err)
    cb(null, head.length ? lexint.unpack(head[0].slice(head[0].lastIndexOf(self.sep) + 1), 'hex') : 0)
  })
}

Logs.prototype.createValueStream = function (log, opts) {
  if (!opts) opts = {}
  return this.db.createValueStream({
    gt: this.key(log, opts.since || 0),
    lt: this.key(log, opts.until || -1),
    valueEncoding: this.valueEncoding,
    reverse: opts.reverse,
    limit: opts.limit
  })
}

Logs.prototype.createReadStream = function (log, opts) {
  if (!opts) opts = {}

  var self = this

  var rs = this.db.createReadStream({
    gt: this.key(log, opts.since || 0),
    lt: this.key(log, opts.until || -1),
    valueEncoding: this.valueEncoding,
    reverse: opts.reverse,
    limit: opts.limit
  })

  var format = through.obj(function (data, enc, cb) {
    var key = data.key
    var log = key.slice(self.prefix.length, key.lastIndexOf(self.sep))
    var seq = lexint.unpack(key.slice(self.prefix.length + log.length + 1), 'hex')
    cb(null, {log: log, seq: seq, value: data.value})
  })

  return pump(rs, format)
}

module.exports = Logs
<|endoftext|>


<commit_before>module.exports = function (opts) {
  var req = 1, p

  var requests = [], instreams = [], outstreams = []

  function onMessage (msg) {
    opts.message(msg)
  }

  function onRequest (msg) {
    //call the local api.
    if(msg.req < 0)
      requests[msg.req*-1](msg.error, msg.value)
    else {
      var id = msg.req*-1, once = false
      //must callback exactly once.
      //any extra callbacks are just ignored.

      opts.request(msg.value, function (err, value) {
        if(once) throw new Error('cb called twice from local api')
        once = true
        if(err) p.read({error: err.message, req: id})
        else    p.read({value: value, req: id})
      })
    }
  }

  function onStream (msg) {

    if(msg.req < 0) // it's a response
      outstreams[msg.req*-1].read(msg.value)

    else {
      var ins = instreams[msg.req]
      if(ins) {
        if(ins.read) ins.read(msg.value)
        else console.error('no .read for stream:', ins.id, 'dropped:', msg)
      }
      else {
        var seq = 1, req = msg.req
        var stream = instreams[req] = {
          id: req,
          write: function (data) {
            p.read({req: req*-1, seq: seq++, value: data})
          },
          read: null
        }
        opts.stream(stream)
        stream.read(msg.value)
      }
    }

  }

  return p = {
    //message with no response, or stream
    message: function (obj) {
      p.read(obj)
    },

    request: function (obj, callback) {
      var id = req++
      requests[id] = function (err, value) {
        requests[id] = null
        callback(err, value)
      }
      p.read({value: obj, req: id})
    },

    stream: function (recv) {
      var id = req++, seq = 1
      return outstreams[id] = {
        req: id,
        write: function (data) {
          p.read({
            req: id, seq: seq++, value: data
          })
        },
        read: recv || null
      }
    },

    read: function (msg) {
      console.error('please overwrite write method to do IO', msg)
    },

    write: function (msg) {
      //handle requests
      if(msg.req && !msg.seq)
        onRequest(msg)
      else if(msg.req && msg.seq)
        onStream(msg)
      else
        onMessage(msg)
    }
  }
}
<commit_msg>decided that stream must have end/err<commit_after>module.exports = function (opts) {
  var req = 1, p

  var requests = [], instreams = [], outstreams = []

  function onMessage (msg) {
    opts.message(msg)
  }

  function onRequest (msg) {
    //call the local api.
    if(msg.req < 0)
      requests[msg.req*-1](msg.error, msg.value)
    else {
      var id = msg.req*-1, once = false
      //must callback exactly once.
      //any extra callbacks are just ignored.

      opts.request(msg.value, function (err, value) {
        if(once) throw new Error('cb called twice from local api')
        once = true
        if(err) p.read({error: err.message, req: id})
        else    p.read({value: value, req: id})
      })
    }
  }

  function createStream(id) {
    var seq = 1
    var stream = {
      id: id,
      write: function (data, err) {
        p.read({req: id, seq: seq++, value: data, end: err})
      },
      end: function (err) {
        stream.write(null, err || true)
      },
      read: null
    }

    return stream
  }

  function onStream (msg) {

    if(msg.req < 0) { // it's a response
      var outs = outstreams[msg.req*-1]
      if(msg.end) {
        outstreams[msg.req*-1] = null
        outs.read(null, msg.end)
      }
      else
        outs.read(msg.value)
    }
    else {
      var ins = instreams[msg.req]
      if(ins) {
        if(ins.read) {
          if(msg.end) {
            instreams[msg.req] = null
            ins.read(null, msg.end)
          }
          else
            ins.read(msg.value)
        }
        else console.error('no .read for stream:', ins.id, 'dropped:', msg)
      }
      else {
        var seq = 1, req = msg.req
        var stream = instreams[req] = createStream(req*-1)
        opts.stream(stream)
        stream.read(msg.value, msg.end)
      }
    }

  }

  return p = {
    //message with no response, or stream
    message: function (obj) {
      p.read(obj)
    },

    request: function (obj, callback) {
      var id = req++
      requests[id] = function (err, value) {
        requests[id] = null
        callback(err, value)
      }
      p.read({value: obj, req: id})
    },

    stream: function (recv) {
      var id = req++
      return outstreams[id] = createStream(id)
    },

    read: function (msg) {
      console.error('please overwrite write method to do IO', msg)
    },

    write: function (msg, end) {
      if(end) {
        var err = end === true ? new Error('unexpected end of parent stream') : err
        instreams.forEach(function (s) {
          s.end(err)
        })
        outstreams.forEach(function (s) {
          s.end(err)
        })
        return
      }
      //handle requests
      ; (msg.req && !msg.seq) ? onRequest(msg)
      : (msg.req && msg.seq)  ? onStream(msg)
      :                         onMessage(msg)
    }
  }
}
<|endoftext|>


<commit_before>"use strict";

/*global module, require*/

var elasticSearch = require('elasticsearch'),
    apiVersion = "1.7",

    snapshotType = 'snapshot',
    opType = 'op',

    mappings = require("./mappings.js");

module.exports = function(host, index) {
    index = index || 'livedb';

    var client = new elasticSearch.Client({
	host: host || 'http://localhost:9200',
	apiVersion: apiVersion,
	suggestCompression: true
    }),

	makeSnapshotId = function(collection, doc) {
	    return collection + "-" + doc + "-snapshot";
	},

	makeOpId = function(collection, doc, op) {
	    return collection + "-" + doc + "-op-v" + op.v;
	},

	matchColl = function(coll) {
	    return {
		term: {
		    collection: coll
		}
	    };
	},

	matchDoc = function(doc) {
	    return {
		term: {
		    doc: doc
		}
	    };
	},

	versionRange = function(start, end) {
	    var filter = {
		range: {
		    v: {
			gte: start || 0
		    }
		}
	    };

	    if (end !== null && end !== undefined) {
		filter.range.v.lt = end;
	    }

	    return filter;
	},

	searchCallback = function(callback) {
	    return function(error, response) {
		if (error) {
		    callback(error, null);
		} else {
		    callback(
			null,
			response.hits.hits.map(function(hit) {
			    return hit._source;
			})
		    );
		}
	    };
	},

	m = {
	    closed: false,
	    close: function() {
		if (!m.closed) {
		    m.closed = true;
		    client.close();
		}
	    },

	    /*
	     Get a single snapshot back from the database.
	     */
	    getSnapshot: function(collection, doc, callback) {
		client.get(
		    {
			index: index,
			type: snapshotType,
			id: makeSnapshotId(collection, doc)
		    },
		    function(error, response) {
			if (error) {
			    callback(error, null);
			} else {
			    callback(
				null,
				{
				    type: response._source.type,
				    data: response._source.data
				}
			    );
			}
		    }
		);
	    },

	    /*
	     Write a snapshot to the database.
	     */
	    writeSnapshot: function(collection, doc, snapshot, callback) {
		client.index(
		    {
			index: index,
			type: snapshotType,
			id: makeSnapshotId(collection, doc),
			version: snapshot.v,
			body: {
			    collection: collection,
			    doc: doc,
			    type: snapshot.type,
			    data: snapshot.data
			}
		    },
		    callback
		);
	    },

	    /*
	     Get multiple snapshots at once by collection and document name.

	     requests is a map of collection => [document names]
	     */
	    bulkGetSnapshot: function(requests, callback) {
		var criteria = Object.keys(requests).map(function(coll) {
		    return {
			bool: {
			    must: [
				matchColl(coll),
				{
				    terms: {
					doc: requests[coll]
				    }
				}
			    ]
			}
		    };
		});

		client.search(
		    {
			index: index,
			type: snapshotType,
			body: {
			    query: {
				filtered: {
				    filter: {
					bool: {
					    should: criteria
					}
				    }
				}
			    }
			}
		    },
		    searchCallback(callback)
		);
	    },

	    /*
	     Create an operation for the specified document.
	     */
	    writeOp: function(collection, doc, op, callback) {
		var body = {
		    collection: collection,
		    doc: doc,
		    v: op.v,
		    src: op.src,
		    seq: op.seq,
		    meta: op.meta
		};

		if (op.op) {
		    body.op = op.op;
		} else if (op.create) {
		    body.create = op.create;

		} else if (op.del) {
		    body.del = op.del;

		} else {
		    callback("Unknown op type. Should have a property op|create|del. " + JSON.stringify(op), null);
		}

		client.create(
		    {
			index: index,
			type: opType,
			/*
			 We specify the id in this case to prevent writing the same operation twice.
			 */
			id: makeOpId(collection, doc, op),
			body: body
		    },
		    callback
		);
	    },

	    /*
	     The version of a document is its most recent op + 1.
	     */
	    getVersion: function(collection, doc, callback) {
		client.count(
		    {
			index: index,
			type: opType,
			body: {
			    query: {
				filtered: {
				    filter: {
					bool: {
					    must: [
						matchColl(collection),
						matchDoc(doc),
					    ]
					}
				    }
				}
			    },

			    aggs: {
				version: {
				    max: {
					field: 'v'
				    }
				}
			    }
			}
		    },
		    function(error, response) {
			if (error) {
			    callback(error, null);
			} else {
			    callback(null, response.aggregations.version);
			}
		    }
		);
	    },

	    /*
	     Returns ops for a document from start (inclusive) to end (exclusive), sorted by version.
	     */
	    getOps: function(collection, doc, start, end, callback) {
		client.search(
		    {
			index: index,
			type: opType,
			body: {
			    sort: {
				v: {
				    order: 'asc'
				}
			    },
			    query: {
				filtered: {
				    filter: {
					bool: {
					    must: [
						matchColl(collection),
						matchDoc(doc),
						versionRange(start, end)
					    ]
					}
				    }
				}
			    }
			}
		    },
		    searchCallback(callback)
		);
	    },

	    /*
	     Not part of the liveDB API.

	     Search for a document with a title matching our query.
	     */
	    titleSearch: function(collection, searchTerm, callback) {
		client.search(
		    {
			index: index,
			type: snapshotType,
			body: {
			    query: {
				filtered: {
				    filter: matchColl(collection),
				    query: {
					match: {
					    doc: searchTerm
					}
				    }
				}
			    }
			}
		    },
		    searchCallback(callback)
		);
	    }
	};

    mappings(client, index);

    return m;
};
<commit_msg>bulkGetSnapshot now returns its results in the correct format: a dictionary of dictionarys mapping collection -> documentName -> documentBody.<commit_after>"use strict";

/*global module, require*/

var elasticSearch = require('elasticsearch'),
    apiVersion = "1.7",

    snapshotType = 'snapshot',
    opType = 'op',

    mappings = require("./mappings.js");

module.exports = function(host, index) {
    index = index || 'livedb';

    var client = new elasticSearch.Client({
	host: host || 'http://localhost:9200',
	apiVersion: apiVersion,
	suggestCompression: true
    }),

	makeSnapshotId = function(collection, doc) {
	    return collection + "-" + doc + "-snapshot";
	},

	makeOpId = function(collection, doc, op) {
	    return collection + "-" + doc + "-op-v" + op.v;
	},

	matchColl = function(coll) {
	    return {
		term: {
		    collection: coll
		}
	    };
	},

	matchDoc = function(doc) {
	    return {
		term: {
		    doc: doc
		}
	    };
	},

	versionRange = function(start, end) {
	    var filter = {
		range: {
		    v: {
			gte: start || 0
		    }
		}
	    };

	    if (end !== null && end !== undefined) {
		filter.range.v.lt = end;
	    }

	    return filter;
	},

	searchCallback = function(callback) {
	    return function(error, response) {
		if (error) {
		    callback(error, null);
		} else {
		    callback(
			null,
			response.hits.hits.map(function(hit) {
			    return hit._source;
			})
		    );
		}
	    };
	},

	m = {
	    closed: false,
	    close: function() {
		if (!m.closed) {
		    m.closed = true;
		    client.close();
		}
	    },

	    /*
	     Get a single snapshot back from the database.
	     */
	    getSnapshot: function(collection, doc, callback) {
		client.get(
		    {
			index: index,
			type: snapshotType,
			id: makeSnapshotId(collection, doc)
		    },
		    function(error, response) {
			if (error) {
			    callback(error, null);
			} else {
			    callback(
				null,
				{
				    type: response._source.type,
				    data: response._source.data
				}
			    );
			}
		    }
		);
	    },

	    /*
	     Write a snapshot to the database.
	     */
	    writeSnapshot: function(collection, doc, snapshot, callback) {
		client.index(
		    {
			index: index,
			type: snapshotType,
			id: makeSnapshotId(collection, doc),
			version: snapshot.v,
			body: {
			    collection: collection,
			    doc: doc,
			    type: snapshot.type,
			    data: snapshot.data
			}
		    },
		    callback
		);
	    },

	    /*
	     Get multiple snapshots at once by collection and document name.

	     requests is a map of collection => [document names]
	     */
	    bulkGetSnapshot: function(requests, callback) {
		var criteria = Object.keys(requests).map(function(coll) {
		    return {
			bool: {
			    must: [
				matchColl(coll),
				{
				    terms: {
					doc: requests[coll]
				    }
				}
			    ]
			}
		    };
		});

		client.search(
		    {
			index: index,
			type: snapshotType,
			body: {
			    query: {
				filtered: {
				    filter: {
					bool: {
					    should: criteria
					}
				    }
				}
			    }
			}
		    },
		    function(error, results) {
			if (error) {
			    callback(error, results);
			} else {
			    var resultsDict = {};
			    Object.keys(requests).forEach(function(coll) {
				resultsDict[coll] = {};
			    });

			    results.hits.hits.forEach(function(hit) {
				resultsDict[hit.coll][hit.doc] = hit._source;
			    });

			    callback(
				null,
				resultsDict
			    );
			}
		    }
		);
	    },

	    /*
	     Create an operation for the specified document.
	     */
	    writeOp: function(collection, doc, op, callback) {
		var body = {
		    collection: collection,
		    doc: doc,
		    v: op.v,
		    src: op.src,
		    seq: op.seq,
		    meta: op.meta
		};

		if (op.op) {
		    body.op = op.op;
		} else if (op.create) {
		    body.create = op.create;

		} else if (op.del) {
		    body.del = op.del;

		} else {
		    callback("Unknown op type. Should have a property op|create|del. " + JSON.stringify(op), null);
		}

		client.create(
		    {
			index: index,
			type: opType,
			/*
			 We specify the id in this case to prevent writing the same operation twice.
			 */
			id: makeOpId(collection, doc, op),
			body: body
		    },
		    callback
		);
	    },

	    /*
	     The version of a document is its most recent op + 1.
	     */
	    getVersion: function(collection, doc, callback) {
		client.count(
		    {
			index: index,
			type: opType,
			body: {
			    query: {
				filtered: {
				    filter: {
					bool: {
					    must: [
						matchColl(collection),
						matchDoc(doc),
					    ]
					}
				    }
				}
			    },

			    aggs: {
				version: {
				    max: {
					field: 'v'
				    }
				}
			    }
			}
		    },
		    function(error, response) {
			if (error) {
			    callback(error, null);
			} else {
			    callback(null, response.aggregations.version);
			}
		    }
		);
	    },

	    /*
	     Returns ops for a document from start (inclusive) to end (exclusive), sorted by version.
	     */
	    getOps: function(collection, doc, start, end, callback) {
		client.search(
		    {
			index: index,
			type: opType,
			body: {
			    sort: {
				v: {
				    order: 'asc'
				}
			    },
			    query: {
				filtered: {
				    filter: {
					bool: {
					    must: [
						matchColl(collection),
						matchDoc(doc),
						versionRange(start, end)
					    ]
					}
				    }
				}
			    }
			}
		    },
		    searchCallback(callback)
		);
	    },

	    /*
	     Not part of the liveDB API.

	     Search for a document with a title matching our query.
	     */
	    titleSearch: function(collection, searchTerm, callback) {
		client.search(
		    {
			index: index,
			type: snapshotType,
			body: {
			    query: {
				filtered: {
				    filter: matchColl(collection),
				    query: {
					match: {
					    doc: searchTerm
					}
				    }
				}
			    }
			}
		    },
		    searchCallback(callback)
		);
	    }
	};

    mappings(client, index);

    return m;
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */
'use strict';

var Promise = require('bluebird');
var filename = require('filename.js');

var ALLOWED_FILETYPES = ['image/jpg', 'image/jpeg', 'image/gif', 'image/png'];

module.exports.handler = function(event, context) {
  console.log(event);
  var s3Object = event.Records[0].s3;
  if (s3Object.object.size === 0) {
    return context.fail('Object size is 0');
  }

  if (!filename.directoryName(s3Object.object.key)) {
    return context.fail('Resize images function will not run for files at the bucket root');
  }

  var config;
  var s3 = require('./s3.js');
  var path = require('path');
  return Promise.promisify(require('fs').readFile)(path.resolve(__dirname, 'config.json'), 'utf8')
  .then(function(configString) {
    console.log(configString);
    return JSON.parse(configString);
  })
  .then(function validateConfig(_config_) {
    config = _config_;
    if (!config.destinationBucket) {
      throw new Error('Config must provide a destinationBucket');
    }
    config.sizes = config.sizes || [];
    config.sizes = config.sizes.filter(function(size) {
      return !isNaN(parseInt(size, 10)) && isFinite(size);
    });
    if (!config.sizes.length) {
      throw new Error('Config must contain an array of widths to resize images to');
    }
    return config;
  })
  .then(function validateBucket() {
    if (s3Object.bucket.name === config.destinationBucket) {
      throw new Error('Source and destination buckets must be different');
    }

    console.log('bucket valid', s3Object.bucket.name);
  })
  .then(function getObject() {
    console.log('getting object', s3Object.bucket.name + '/' + s3Object.object.key);
    return s3
    .getObjectAsync({
      Bucket: s3Object.bucket.name,
      Key: s3Object.object.key
    });
  })
  .then(function validateImageType(image) {
    console.log('checking filetype', image.ContentType);
    if (ALLOWED_FILETYPES.indexOf(image.ContentType) === -1) {
      throw new Error('Invalid content type: ' + image.ContentType + ' is not one of ' + ALLOWED_FILETYPES.join(', '));
    }

    return image;
  })
  .then(function resizeImage(image) {
    console.log('resizing images');
    var imageProcessor = require('./functions/image-processor.js')({
      data: image.Body,
      type: image.ContentType,
      key: s3Object.object.key
    });
    return Promise.all(config.sizes.map(function(size) {
      return Promise.all([
        imageProcessor(size),
        imageProcessor(size * 2, '@2x')
      ]);
    }));
  })
  .then(function putObjects(images) {
    console.log('uploading images');
    return Promise.all(images.map(function(image) {
      console.log({
        Bucket: config.destinationBucket,
        Key: image.key,
        ContentType: image.type
      });
      return s3.putObject({
        Bucket: config.destinationBucket,
        Key: image.key,
        Body: image.data,
        ContentType: image.type
      });
    }));
  })
  .then(function(responses) {
    context.succeed(responses.length + ' images resized from ' + s3Object.object.key + ' and uploaded to ' + config.destinationBucket);
  })
  .catch(function(error) {
    if (error.code === 'ENOENT') {
      return context.fail('Error ' + error.code + ': ' + error.path + ' not found');
    }
    return context.fail(error.message);
  });

};
<commit_msg>Yet more debug output<commit_after>/* eslint-disable no-console */
'use strict';

process.on('uncaughtException', function(error) {
  console.log('Uncaught exception', error);
});

var Promise = require('bluebird');
var filename = require('filename.js');

var ALLOWED_FILETYPES = ['image/jpg', 'image/jpeg', 'image/gif', 'image/png'];

module.exports.handler = function(event, context) {
  console.log(event);
  var s3Object = event.Records[0].s3;
  if (s3Object.object.size === 0) {
    return context.fail('Object size is 0');
  }

  if (!filename.directoryName(s3Object.object.key)) {
    return context.fail('Resize images function will not run for files at the bucket root');
  }

  var config;
  var s3 = require('./s3.js');
  var path = require('path');
  return Promise.promisify(require('fs').readFile)(path.resolve(__dirname, 'config.json'), 'utf8')
  .then(function(configString) {
    console.log(configString);
    return JSON.parse(configString);
  })
  .then(function validateConfig(_config_) {
    config = _config_;
    if (!config.destinationBucket) {
      throw new Error('Config must provide a destinationBucket');
    }
    config.sizes = config.sizes || [];
    config.sizes = config.sizes.filter(function(size) {
      return !isNaN(parseInt(size, 10)) && isFinite(size);
    });
    if (!config.sizes.length) {
      throw new Error('Config must contain an array of widths to resize images to');
    }
    return config;
  })
  .then(function validateBucket() {
    if (s3Object.bucket.name === config.destinationBucket) {
      throw new Error('Source and destination buckets must be different');
    }

    console.log('bucket valid', s3Object.bucket.name);
  })
  .then(function getObject() {
    console.log('getting object', s3Object.bucket.name + '/' + s3Object.object.key);
    return s3
    .getObjectAsync({
      Bucket: s3Object.bucket.name,
      Key: s3Object.object.key
    });
  })
  .then(function validateImageType(image) {
    console.log('checking filetype', image.ContentType);
    if (ALLOWED_FILETYPES.indexOf(image.ContentType) === -1) {
      throw new Error('Invalid content type: ' + image.ContentType + ' is not one of ' + ALLOWED_FILETYPES.join(', '));
    }

    return image;
  })
  .then(function resizeImage(image) {
    console.log('resizing images');
    var imageProcessor = require('./functions/image-processor.js')({
      data: image.Body,
      type: image.ContentType,
      key: s3Object.object.key
    });
    return Promise.all(config.sizes.map(function(size) {
      return Promise.all([
        imageProcessor(size),
        imageProcessor(size * 2, '@2x')
      ]);
    }));
  })
  .then(function putObjects(images) {
    console.log('uploading images');
    return Promise.all(images.map(function(image) {
      console.log({
        Bucket: config.destinationBucket,
        Key: image.key,
        ContentType: image.type
      });
      return s3.putObject({
        Bucket: config.destinationBucket,
        Key: image.key,
        Body: image.data,
        ContentType: image.type
      });
    }));
  })
  .then(function(responses) {
    context.succeed(responses.length + ' images resized from ' + s3Object.object.key + ' and uploaded to ' + config.destinationBucket);
  })
  .catch(function(error) {
    if (error.code === 'ENOENT') {
      return context.fail('Error ' + error.code + ': ' + error.path + ' not found');
    }
    return context.fail(error.message);
  });

};
<|endoftext|>


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

/**
 * A sample AMQP microservice for service bus communication via RabbitMQ with the seneca-service-api
 * @param options
 */
function twitter(options) {
  var log;

  this.add('init:twitter', init);
  this.add('role:twitter,cmd:*', noMatch);
  this.add('role:twitter,cmd:tweets', tweets);

  function init(msg, respond) {
    // Note, all the code below is optional
    // log to a custom file
    fs.open(options.logfile, 'a', function (err, fd) {

      // cannot open for writing, so fail
      // this error is fatal to Seneca
      if (err) return respond(err);

      log = makeLog(fd);
      respond();
    });
  }

  function makeLog(fd) {
    // TODO: Tie this into something like Winston
    return function (entry) {
      fs.write(fd, '\n' + new Date().toISOString() + ' ' + entry, null, 'utf8', function (err) {
        if (err) return console.log(err);

        // ensure log entry is flushed
        fs.fsync(fd, function (err) {
          if (err) return console.log(err);
        })
      });
    }
  }

  function noMatch(payload, respond) {
    respond(null, {
      statusCode: 404,
      original: payload,
      error: {
        message: 'Invalid service command'
      }
    });
  }

  function tweets(payload, respond) {
    // TODO: Your service begins here
    log('RECEIVED: ' + payload);
    respond(null, {status: 'success', tweets: []});
  }
}

// Define queues
require('seneca')()
  .use(twitter, { logfile: './twitter.log'})
  .use('seneca-amqp-transport')
  .listen({
    type: 'amqp',
    pin: 'role:twitter,cmd:*',
    url: process.env.AMQP_URL || 'amqp://127.0.0.1'
  });<commit_msg>adds version and method scheme for pin<commit_after>var fs = require('fs');

/**
 * A sample AMQP microservice for service bus communication via RabbitMQ with the seneca-service-api
 * @param options
 */
function twitter(options) {
  var log;

  this.add('init:twitter', init);
  this.add('role:twitter,version:*,cmd:*,method:*', noMatch);
  this.add('role:twitter,version:*,cmd:tweets,method:GET', tweets);

  function init(msg, respond) {
    // Note, all the code below is optional
    // log to a custom file
    fs.open(options.logfile, 'a', function (err, fd) {

      // cannot open for writing, so fail
      // this error is fatal to Seneca
      if (err) return respond(err);

      log = makeLog(fd);
      respond();
    });
  }

  function makeLog(fd) {
    // TODO: Tie this into something like Winston
    return function (entry) {
      fs.write(fd, '\n' + new Date().toISOString() + ' ' + entry, null, 'utf8', function (err) {
        if (err) return console.log(err);

        // ensure log entry is flushed
        fs.fsync(fd, function (err) {
          if (err) return console.log(err);
        })
      });
    }
  }

  function noMatch(payload, respond) {
    respond(null, {
      statusCode: 404,
      original: payload,
      error: {
        message: 'Invalid service command'
      }
    });
  }

  function tweets(payload, respond) {
    // TODO: Your service begins here
    log('RECEIVED: ' + payload);
    respond(null, {status: 'success', tweets: []});
  }
}

// Define queues
require('seneca')()
  .use(twitter, { logfile: './twitter.log'})
  .use('seneca-amqp-transport')
  .listen({
    type: 'amqp',
    pin: 'role:twitter,version:*,cmd:*,method:*',
    url: process.env.AMQP_URL || 'amqp://127.0.0.1'
  });<|endoftext|>


<commit_before>var path = require('path')
var http = require('http')
var fs = require('fs')
var Router = require('./router')
var settings = require('./settings')
var request = require('hyperrequest')

var args = require('minimist')(process.argv, {
  alias:{
    p:'port',
    s:'storage',
    d:'datafile',
    lh:'levelhost',
    lp:'levelport'
  },
  default:{
    port:process.env.PORT || 80,
    storage:process.env.STORAGE || 'jsonfile',
    datafile:process.env.DATAFILE || settings.defaultFilePath,
    levelhost:process.env.LEVEL_HOST || '127.0.0.1',
    levelport:process.env.LEVEL_PORT || 80,
    runtimehost:process.env.RUNTIME_HOST || '127.0.0.1',
    runtimeport:process.env.RUNTIME_PORT || 80,
    authhost:process.env.AUTH_HOST || '127.0.0.1',
    authport:process.env.AUTH_PORT || 80,
  }
})

function processArg(value){
  value = value || ''
  if(value.indexOf('env:')){
    value = process.env[value.split(':')[1]]
  }
  return value
}

var storageoptions = {}

if(args.storage=='jsonfile'){
  storageoptions.datafile = args.datafile
}
else if(args.storage=='leveldb'){
  storageoptions.host = processArg(args.levelhost || '')
  storageoptions.port = args.levelport
}

/*

  we will put an api call to the runtime service here

*/
function containerizer(opts, done){
  hyperrequest({
    url: "http://" + processArg(args.runtimehost) + ":"+ args.runtimeport +"/v1/" + opts.action,
    method: "POST",
    headers:{
      'x-jenca-user':opts.user,
      'Content-type':'application/json'
    },
    json:true,
    body:opts.project
  }, function(err, resp){

    if(err) return done(err.toString())

    done(null, resp.body)
  })
}

/*

  we will put an api call to the authentication service here

*/

function authenticator(req, done){
  hyperrequest({
    url: "http://" + processArg(args.authhost) + ":"+ args.authport +"/status",
    method: "GET",
    headers:{
      'set-cookie':req.headers['set-cookie'],
      'Content-type':'application/json'
    },
    json:true
  }, function(err, resp){

    if(err) return done(err.toString())

    done(null, resp.body)
  })
}

var storage = require('./storage/' + args.storage)(storageoptions)
var router = Router({
  storage:storage,
  datafile:args.datafile,
  containerizer:containerizer,
  authenticator:authenticator
})

var server = http.createServer(router.handler)

server.listen(args.port, function(err){
  if(err){
    console.error(err.toString())
    return
  }
  console.log('server listening on port: ' + args.port)
})<commit_msg>hyperreqeust<commit_after>var path = require('path')
var http = require('http')
var fs = require('fs')
var Router = require('./router')
var settings = require('./settings')
var hyperrequest = require('hyperrequest')

var args = require('minimist')(process.argv, {
  alias:{
    p:'port',
    s:'storage',
    d:'datafile',
    lh:'levelhost',
    lp:'levelport'
  },
  default:{
    port:process.env.PORT || 80,
    storage:process.env.STORAGE || 'jsonfile',
    datafile:process.env.DATAFILE || settings.defaultFilePath,
    levelhost:process.env.LEVEL_HOST || '127.0.0.1',
    levelport:process.env.LEVEL_PORT || 80,
    runtimehost:process.env.RUNTIME_HOST || '127.0.0.1',
    runtimeport:process.env.RUNTIME_PORT || 80,
    authhost:process.env.AUTH_HOST || '127.0.0.1',
    authport:process.env.AUTH_PORT || 80,
  }
})

function processArg(value){
  value = value || ''
  if(value.indexOf('env:')){
    value = process.env[value.split(':')[1]]
  }
  return value
}

var storageoptions = {}

if(args.storage=='jsonfile'){
  storageoptions.datafile = args.datafile
}
else if(args.storage=='leveldb'){
  storageoptions.host = processArg(args.levelhost || '')
  storageoptions.port = args.levelport
}

/*

  we will put an api call to the runtime service here

*/
function containerizer(opts, done){
  hyperrequest({
    url: "http://" + processArg(args.runtimehost) + ":"+ args.runtimeport +"/v1/" + opts.action,
    method: "POST",
    headers:{
      'x-jenca-user':opts.user,
      'Content-type':'application/json'
    },
    json:true,
    body:opts.project
  }, function(err, resp){

    if(err) return done(err.toString())

    done(null, resp.body)
  })
}

/*

  we will put an api call to the authentication service here

*/

function authenticator(req, done){
  hyperrequest({
    url: "http://" + processArg(args.authhost) + ":"+ args.authport +"/status",
    method: "GET",
    headers:{
      'set-cookie':req.headers['set-cookie'],
      'Content-type':'application/json'
    },
    json:true
  }, function(err, resp){

    if(err) return done(err.toString())

    done(null, resp.body)
  })
}

var storage = require('./storage/' + args.storage)(storageoptions)
var router = Router({
  storage:storage,
  datafile:args.datafile,
  containerizer:containerizer,
  authenticator:authenticator
})

var server = http.createServer(router.handler)

server.listen(args.port, function(err){
  if(err){
    console.error(err.toString())
    return
  }
  console.log('server listening on port: ' + args.port)
})<|endoftext|>


<commit_before>/*!
 * Percent v1.1.1 (http://git.io/percentjs)
 * Licensed under the MIT license.
 */

'use strict';

/*
 * Percent calculation
 */

exports.calc = function (value, total, decimal, sign) {
  var badNumbers = [NaN, Infinity, -Infinity];

  // Avoid argument type problems
  if (typeof value !== 'number' ||
      typeof total !== 'number' ||
      typeof decimal !== 'number') {
    return null;
  }

  // Don't divide by zero
  if (total === 0) {
    return 0;
  }

  // Avoid wrong numbers
  for (var i = 0; i < badNumbers.length; i++) {
    if ([value, total, decimal].indexOf(badNumbers[i]) > -1) {
      return badNumbers[i];
    }
  }

  // Define the sign
  if (typeof sign !== 'string') {
    sign = sign ? '%' : '';
  }

  return (value / total * 100).toFixed(decimal) + sign;
};

/*
 * Percent validation
 */

// Supreme percent regexp
exports.re = /^\s?[-+]?(\d*[.])?\d+\s?%?\s?$/;

exports.valid = function (value) {
  if (typeof value === 'number' ||
      (typeof value === 'string' && value.match(exports.re))) {
    return true;
  }

  return false;
};

/*
 * Add percent sign
 */

exports.sign = function (value) {
  if (typeof value === 'number' ||
      (typeof value === 'string' && !value.match(/%/g))) {
    return value + '%';
  }

  return value;
};

/*
 * Clean the percent
 */

exports.unsign = function (value) {
  if (typeof value === 'string') {
    return value.replace(/%/g, '');
  }

  return value;
};

exports.clean = function (value) {
  value = exports.unsign(value);

  if (typeof value === 'string') {
    return value.replace(/\s/g, '');
  }

  return value;
};

exports.convert = function (value, negative) {
  value = exports.clean(value);

  if (exports.valid(value)) {
    if (negative) {
      return -value;
    }

    return +value;
  }

  return value;
};

/*
 * Percent comparision
 */

exports.lt = function (l, t) {
  if (exports.valid(l) && exports.valid(t) &&
      exports.convert(l) < exports.convert(t)) {
    return true;
  }

  return false;
};

exports.gt = function (g, t) {
  if (exports.valid(g) && exports.valid(t) &&
      exports.convert(g) > exports.convert(t)) {
    return true;
  }

  return false;
};

exports.eq = function (e, q) {
  if (exports.valid(e) && exports.valid(q) &&
      exports.convert(e) == exports.convert(q)) {
    return true;
  }

  return false;
};

exports.neq = function (ne, q) {
  if (exports.valid(ne) && exports.valid(q) &&
      exports.convert(ne) != exports.convert(q)) {
    return true;
  }

  return false;
};

exports.satisfies = function (value, min, max) {
  // Sort min and max by size
  if (min > max) {
    var _max = max;
    max = min;
    min = _max;
  }

  if (exports.valid(value) &&
      exports.valid(min) && exports.valid(max) &&
      exports.convert(value) >= exports.convert(min) &&
      exports.convert(value) <= exports.convert(max)) {
    return true;
  }

  return false;
};
<commit_msg>Trim trailing spaces<commit_after>/*!
 * Percent v1.1.1 (http://git.io/percentjs)
 * Licensed under the MIT license.
 */

'use strict';

/*
 * Percent calculation
 */

exports.calc = function (value, total, decimal, sign) {
  var badNumbers = [NaN, Infinity, -Infinity];

  // Avoid argument type problems
  if (typeof value !== 'number' ||
      typeof total !== 'number' ||
      typeof decimal !== 'number') {
    return null;
  }

  // Don't divide by zero
  if (total === 0) {
    return 0;
  }

  // Avoid wrong numbers
  for (var i = 0; i < badNumbers.length; i++) {
    if ([value, total, decimal].indexOf(badNumbers[i]) > -1) {
      return badNumbers[i];
    }
  }

  // Define the sign
  if (typeof sign !== 'string') {
    sign = sign ? '%' : '';
  }

  return (value / total * 100).toFixed(decimal) + sign;
};

/*
 * Percent validation
 */

// Supreme percent regexp
exports.re = /^\s?[-+]?(\d*[.])?\d+\s?%?\s?$/;

exports.valid = function (value) {
  if (typeof value === 'number' ||
      (typeof value === 'string' && value.match(exports.re))) {
    return true;
  }

  return false;
};

/*
 * Add percent sign
 */

exports.sign = function (value) {
  if (typeof value === 'number' ||
      (typeof value === 'string' && !value.match(/%/g))) {
    return value + '%';
  }

  return value;
};

/*
 * Clean the percent
 */

exports.unsign = function (value) {
  if (typeof value === 'string') {
    return value.replace(/%/g, '');
  }

  return value;
};

exports.clean = function (value) {
  value = exports.unsign(value);

  if (typeof value === 'string') {
    return value.replace(/\s/g, '');
  }

  return value;
};

exports.convert = function (value, negative) {
  value = exports.clean(value);

  if (exports.valid(value)) {
    if (negative) {
      return -value;
    }

    return +value;
  }

  return value;
};

/*
 * Percent comparision
 */

exports.lt = function (l, t) {
  if (exports.valid(l) && exports.valid(t) &&
      exports.convert(l) < exports.convert(t)) {
    return true;
  }

  return false;
};

exports.gt = function (g, t) {
  if (exports.valid(g) && exports.valid(t) &&
      exports.convert(g) > exports.convert(t)) {
    return true;
  }

  return false;
};

exports.eq = function (e, q) {
  if (exports.valid(e) && exports.valid(q) &&
      exports.convert(e) == exports.convert(q)) {
    return true;
  }

  return false;
};

exports.neq = function (ne, q) {
  if (exports.valid(ne) && exports.valid(q) &&
      exports.convert(ne) != exports.convert(q)) {
    return true;
  }

  return false;
};

exports.satisfies = function (value, min, max) {
  // Sort min and max by size
  if (min > max) {
    var _max = max;
    max = min;
    min = _max;
  }

  if (exports.valid(value) &&
      exports.valid(min) && exports.valid(max) &&
      exports.convert(value) >= exports.convert(min) &&
      exports.convert(value) <= exports.convert(max)) {
    return true;
  }

  return false;
};
<|endoftext|>


<commit_before>var u          = require('./util')
var Api        = require('./api')
var Muxrpc     = require('muxrpc')
var pull       = require('pull-stream')
var createNode = require('secret-handshake/net')
var nonPrivate = require('non-private-ip')
var Inactive   = require('pull-inactivity')

function isFunction (f) { return 'function' === typeof f }

function isString (s) { return 'string' === typeof s }

function each(obj, iter) {
  if(Array.isArray(obj)) return obj.forEach(iter)
  for(var k in obj) iter(obj[k], k, obj)
}

//opts must have appKey
module.exports = function (opts) {

  var appKey = opts.appKey

  opts.permissions = opts.permissions || {}

  var create = Api(opts.permissions ? [{
    permissions: opts.permissions,
    init: function () {}
  }]: null)

  return create.use({
    manifest: {
      auth: 'async',
      address: 'sync',
      manifest: 'sync',
    },
    init: function (api, opts, permissions, manifest) {
      var snet = createNode({
        keys: opts.keys,
        seed: opts.seed,
        appKey: appKey,
        authenticate: function (pub, cb) {
          var id = u.toId(pub)
          api.auth(id, function (err, auth) {
            if(err) cb(err)
            else    cb(null, auth || create.permissions.anonymous)
          })
        }
      })

      //use configured port, or a random user port.
      var port = opts.port || 1024+(~~(Math.random()*(65536-1024)))

      var peers = api.peers = {}

      var server = snet.createServer(setupRPC).listen(port)

      function setupRPC (stream) {
        var rpc = Muxrpc(create.manifest, create.manifest)(api, stream.auth)
        var timeout = opts.timeout || 5e3
        var rpcStream = rpc.createStream()
        if(opts.timeout) rpcStream = Inactive(rpcStream, opts.timeout)

        pull(stream, rpcStream, stream)

        var id = rpc.id = u.toId(stream.remote)

        //keep track of current connections.
        if(!peers[id]) peers[id] = []
        peers[id].push(rpc)
        rpc.once('closed', function () {
          peers[id].splice(peers[id].indexOf(rpc), 1)
        })

        api.emit('rpc:connect', rpc)

        return rpc
      }

      return {
        //can be called remotely.
        publicKey: snet.publicKey,
        auth: function (pub, cb) { cb() },
        address: function () {
                var host = nonPrivate() || nonPrivate.private() || '127.0.0.1'
          return [host, port, u.toId(snet.publicKey)].join(':')
        },
        manifest: function () {
          return create.manifest
        },

        //cannot be called remote.
        connect: function (address, cb) {
          if(isString(address)) address = u.parseAddress(address)

          snet.connect(address, function (err, stream) {
            return err ? cb(err) : cb(null, setupRPC(stream))
          })
        },

        close: function (err, cb) {
          if(isFunction(err)) cb = err, err = null

          server.close(function (err) {
            cb && cb(err)
          })

          if(err) {
            each(peers, function (connections, id) {
              each(connections, function (rpc) {
                rpc.close(err)
              })
            })
          }
        }
      }
    }
  })

}

<commit_msg>use configured host first<commit_after>var u          = require('./util')
var Api        = require('./api')
var Muxrpc     = require('muxrpc')
var pull       = require('pull-stream')
var createNode = require('secret-handshake/net')
var nonPrivate = require('non-private-ip')
var Inactive   = require('pull-inactivity')

function isFunction (f) { return 'function' === typeof f }

function isString (s) { return 'string' === typeof s }

function each(obj, iter) {
  if(Array.isArray(obj)) return obj.forEach(iter)
  for(var k in obj) iter(obj[k], k, obj)
}

function toBuffer(base64) {
  return new Buffer(base64.substring(0, base64.indexOf('.')), 'base64')
}

function toSodiumKeys (keys) {
  if(!(isString(keys.public) && isString(keys.private)))
    return keys
  return {
    publicKey: toBuffer(keys.public),
    secretKey: toBuffer(keys.private)
  }
}

//opts must have appKey
module.exports = function (opts) {

  var appKey = opts.appKey

  opts.permissions = opts.permissions || {}

  var create = Api(opts.permissions ? [{
    permissions: opts.permissions,
    init: function () {}
  }]: null)

  return create.use({
    manifest: {
      auth: 'async',
      address: 'sync',
      manifest: 'sync',
    },
    init: function (api, opts, permissions, manifest) {
      var snet = createNode({
        keys: opts.keys && toSodiumKeys(opts.keys),
        seed: opts.seed,
        appKey: appKey,
        authenticate: function (pub, cb) {
          var id = u.toId(pub)
          api.auth(id, function (err, auth) {
            if(err) cb(err)
            else    cb(null, auth || create.permissions.anonymous)
          })
        }
      })

      //use configured port, or a random user port.
      var port = opts.port || 1024+(~~(Math.random()*(65536-1024)))

      var peers = api.peers = {}

      var server = snet.createServer(setupRPC).listen(port)

      function setupRPC (stream) {
        var rpc = Muxrpc(create.manifest, create.manifest)(api, stream.auth)
        var timeout = opts.timeout || 5e3
        var rpcStream = rpc.createStream()
        if(opts.timeout) rpcStream = Inactive(rpcStream, opts.timeout)

        pull(stream, rpcStream, stream)

        var id = rpc.id = u.toId(stream.remote)

        //keep track of current connections.
        if(!peers[id]) peers[id] = []
        peers[id].push(rpc)
        rpc.once('closed', function () {
          peers[id].splice(peers[id].indexOf(rpc), 1)
        })

        api.emit('rpc:connect', rpc)

        return rpc
      }

      return {
        //can be called remotely.
        publicKey: snet.publicKey,
        auth: function (pub, cb) { cb() },
        address: function () {
          return this.getAddress()
        },
        getAddress: function () {
          var host = opts.host || nonPrivate() || nonPrivate.private() || '127.0.0.1'
          return [host, port, u.toId(snet.publicKey)].join(':')
        },
        manifest: function () {
          return create.manifest
        },

        //cannot be called remote.
        connect: function (address, cb) {
          if(isString(address)) address = u.parseAddress(address)

          snet.connect(address, function (err, stream) {
            return err ? cb(err) : cb(null, setupRPC(stream))
          })
        },

        close: function (err, cb) {
          if(isFunction(err)) cb = err, err = null

          server.close(function (err) {
            cb && cb(err)
          })

          if(err) {
            each(peers, function (connections, id) {
              each(connections, function (rpc) {
                rpc.close(err)
              })
            })
          }
        }
      }
    }
  })

}

<|endoftext|>


<commit_before>/**
 * Handlebars Helpers: {{include}}
 * Copyright (c) 2013 Jon Schlinkert
 * Licensed under the MIT License (MIT).
 */

var path = require('path');
var _ = require('lodash');
var yfm = require('assemble-yaml');
var minimatch = require('minimatch');

// Export helpers
module.exports.register = function (Handlebars, options, params) {

  'use strict';

  var assemble = params.assemble;
  var grunt = params.grunt;
  var opts = options || {};

  /**
   * {{partial}}
   * Alternative to {{> partial }}
   *
   * @param  {String} name    The name of the partial to use
   * @param  {Object} context The context to pass to the partial
   * @return {String}         Returns compiled HTML
   * @xample: {{partial 'foo' bar}}
   */
  Handlebars.registerHelper('include', function(name, context) {

    if(!Array.isArray(assemble.partials)) {
      assemble.partials = [assemble.partials];
    }

    // first try to match on the full name in the assemble.partials array
    var filepaths = _.filter(assemble.partials, function(filepath) {
      return path.basename(filepath, path.extname(filepath)) === name;
    });

    // if no matches, then try minimatch
    if (!filepaths || filepaths.length <= 0) {
      filepaths = assemble.partials.filter(minimatch.filter(name));
    }

    //var partials = grunt.file.expand(fullpath).map(function(filepath) {
    var partials = filepaths.map(function(filepath) {
      name = path.basename(filepath, path.extname(filepath));

      // Filter out the first partial that matches each given pattern
      // var content = _.first(_.filter(assemble.partials, function(fp) {
      //   return path.basename(fp, path.extname(fp)) === name;
      // }));

      // Process context, using YAML front-matter, grunt config and Assemble
      // options.data
      var pageObj = yfm.extract(filepath) || {};
      var metadata = pageObj.context || {};

      // `context`           = the given context (second parameter)
      // `metadata`          = YAML front matter of the partial
      // `opts.data[name]`   = JSON/YAML data file defined in Assemble
      //                       options.data with a basename
      //                       matching the name of the partial, e.g
      //                       {{partial 'foo'}} => foo.json
      // `this`              = Typically either YAML front matter of
      //                       the "inheriting" page, or a block
      //                       expression wrapping the helper
      // `opts`              = Custom properties defined in Assemble options
      // `grunt.config.data` = Data from grunt.config.data
      //                       (e.g. pkg: grunt.file.readJSON('package.json'))

      var ctx = _.extend({}, grunt.config.data, opts, this, opts.data[name], metadata, context);
      ctx = grunt.config.process(ctx);

      var template = Handlebars.partials[name];
      var fn = Handlebars.compile(template);

      var output = fn(ctx).replace(/^\s+/, '');

      // Prepend output with the filepath to the original partial
      var include = opts.include || opts.data.include || {};
      if(include.origin === true) {
        output = '<!-- ' + filepath + ' -->\n' + output;
      }

      return output;
    }).join('\n');

    return new Handlebars.SafeString(partials);
  });
};<commit_msg>cleaning up some comments<commit_after>/**
 * Handlebars Helpers: {{include}}
 * Copyright (c) 2013 Jon Schlinkert
 * Licensed under the MIT License (MIT).
 */

var path = require('path');
var _ = require('lodash');
var yfm = require('assemble-yaml');
var minimatch = require('minimatch');

// Export helpers
module.exports.register = function (Handlebars, options, params) {

  'use strict';

  var assemble = params.assemble;
  var grunt = params.grunt;
  var opts = options || {};

  /**
   * {{partial}}
   * Alternative to {{> partial }}
   *
   * @param  {String} name    The name of the partial to use
   * @param  {Object} context The context to pass to the partial
   * @return {String}         Returns compiled HTML
   * @xample: {{partial 'foo' bar}}
   */
  Handlebars.registerHelper('include', function(name, context) {

    if(!Array.isArray(assemble.partials)) {
      assemble.partials = [assemble.partials];
    }

    // first try to match on the full name in the assemble.partials array
    var filepaths = _.filter(assemble.partials, function(filepath) {
      return path.basename(filepath, path.extname(filepath)) === name;
    });

    // if no matches, then try minimatch
    if (!filepaths || filepaths.length <= 0) {
      filepaths = assemble.partials.filter(minimatch.filter(name));
    }

    //var partials = grunt.file.expand(fullpath).map(function(filepath) {
    var partials = filepaths.map(function(filepath) {
      name = path.basename(filepath, path.extname(filepath));

      // Process context, using YAML front-matter, grunt config and Assemble
      // options.data
      var pageObj = yfm.extract(filepath) || {};
      var metadata = pageObj.context || {};

      // `context`           = the given context (second parameter)
      // `metadata`          = YAML front matter of the partial
      // `opts.data[name]`   = JSON/YAML data file defined in Assemble
      //                       options.data with a basename
      //                       matching the name of the partial, e.g
      //                       {{partial 'foo'}} => foo.json
      // `this`              = Typically either YAML front matter of
      //                       the "inheriting" page, or a block
      //                       expression wrapping the helper
      // `opts`              = Custom properties defined in Assemble options
      // `grunt.config.data` = Data from grunt.config.data
      //                       (e.g. pkg: grunt.file.readJSON('package.json'))

      var ctx = _.extend({}, grunt.config.data, opts, this, opts.data[name], metadata, context);
      ctx = grunt.config.process(ctx);

      var template = Handlebars.partials[name];
      var fn = Handlebars.compile(template);

      var output = fn(ctx).replace(/^\s+/, '');

      // Prepend output with the filepath to the original partial
      var include = opts.include || opts.data.include || {};
      if(include.origin === true) {
        output = '<!-- ' + filepath + ' -->\n' + output;
      }

      return output;
    }).join('\n');

    return new Handlebars.SafeString(partials);
  });
};<|endoftext|>