<commit_before>"use strict";

let express = require('express'),
	cookieParser = require('cookie-parser'),
    mUrl = require('url'),
    http = require('http'),
    monads = require('./monads.js'),
    CSteamCommunity = require('steamcommunity');

let SteamCommunity = new CSteamCommunity();

let opportunisticProcessing = function(options, callback) {
	let E = new monads.ErrorMonad()
	let instructions = [E.try('processing')];
	for (const operation of options) {
		instructions.push(operation);
		instructions.push(E.retry('processing'));
	}
	instructions.pop();
	instructions.push(callback);
	return E.do(...instructions);
};

let mutateInput = (mutate, fun) => function(err, string, cb) {
	try {fun(err, mutate(string), cb)} catch(error) {cb(error)};
};

let toSteamId = (string) => new CSteamCommunity.SteamID(string);

let toSteamUser = function(err, id, cb) {
	if (err) {
		cb(err);
		return;
	}
	if (!id) {
		cb('Empty input provided');
		return;
	}
    SteamCommunity.getSteamUser(id, cb);
};

let nameOutput = (name, fun) => (err, string, rawCb) => fun(err, string, (error, result) => rawCb(error, {'type':name, 'value' : result}));

let isEvenString = (string) => parseInt(string.slice(-1)) % 2;
let onlyIfNumeric = (fun=(x)=>x) => function(data) {
	if(parseInt(data)) {
		return fun(data);
	} else {
		throw `Expected numeric input, got ${data}`;
	}
};

let urlToSteamId = function (url) {
	let dissected = mUrl.parse(url);
	if(dissected.hostname == 'steamcommunity.com') // may or may not start with 'http://'
	{
		let pathArray = dissected.pathname.split('/');
		let trail = pathArray.pop();
		return (trail == '' ? pathArray.pop() : trail); // may or may not end with trailing slash
	}
	else { return null; }
};

let methods = {
	'asId64'	: nameOutput('id64', mutateInput(onlyIfNumeric(), toSteamUser)),
	'asId3Tail'	: nameOutput('id3', mutateInput(
		onlyIfNumeric((string) => toSteamId(`[U:1:${string}]`)),
		toSteamUser
	)),
	'asOldTail'	: nameOutput('old', mutateInput(
		onlyIfNumeric((string) => toSteamId(`STEAM_0:${isEvenString(string)}:${string}`)),
		toSteamUser
	)),
	'asValidId'	: nameOutput('valid', toSteamUser),
	'asUrl'		: nameOutput('url', mutateInput(urlToSteamId, toSteamUser))
};

let stringToSteamId = function(string, cb) {
	let methodsToTry = ['asId64', 'asId3Tail', 'asOldTail', 'asValidId', 'asUrl'].map((name) => methods[name]);
	opportunisticProcessing(methodsToTry, cb)(string);
}

const tests = {
    'steamID' : 'STEAM_0:0:61441014',
    'steamID3' : '[U:1:122882028]',
    'steamID64' : '76561198083147756',
    'customURL' : 'daerdemandt',
    'name' : 'Daerdemandt',
    'profile' : 'http://steamcommunity.com/profiles/76561198083147756'
};

let app = express();

///*
//TODO: implement opportunistingProcessing with something like this:
let tryUntilResult = function(items, process, successCallback, stubData) {
    if (0 == items.length) {
        successCallback(stubData);
    } else {
        let [current, rest] = [items[0], items.slice(1)];
        process(current, function(err, data) {
            if (err || data) {
                successCallback(err, data);
            } else { // no errors, but we need to try other options
                tryUntilResult(rest, process, successCallback, stubData);
            }
        });
    }
}
//*/
app.get('/api/arbitraryStringToSteamId', function(req, res, next) {
    let ret = function(error, data) {
        if (error) {
            res.status(500).send({'error' : error.stack})
        } else if (!data) {
            res.status(404).send({'error' : 'not found'});
        } else {
			console.log(data.type);
			data = data.value;
		let theID = data.steamID;
            res.send({
                'name' : data.name,
                'steamId64' : theID.toString(),
		'steam32AccountId' : theID.accountid,
		'steamId32' : theID.getSteam3RenderedID(),
		'steam2Old' : theID.getSteam2RenderedID(),
		'steam2New' : theID.getSteam2RenderedID(true),
                'customURL' : data.customURL,
		'profileURL' : 'http://steamcommunity.com/profiles/' + theID.toString(),
		'isGroupchat' : theID.isGroupChat(),
		'isSteamLobby' : theID.isLobby(),
                'memberSince' : data.memberSince,
                'isOnline' : data.onlineState
            }); //TODO: more fields here
        }
    };
    stringToSteamId(decodeURIComponent(req.query.string.trim()), ret);
});

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

function processConvertQuery(request, response)
{
	response.status(501).send("STUB!");
}

app.post('/api/convert', processConvertQuery);

http.createServer(app).listen(process.env.PORT || 8080, function() {
    console.log('Listening on port ' + (process.env.PORT || 8080));
});
<commit_msg>Fix decieving name<commit_after>"use strict";

let express = require('express'),
	cookieParser = require('cookie-parser'),
    mUrl = require('url'),
    http = require('http'),
    monads = require('./monads.js'),
    CSteamCommunity = require('steamcommunity');

let SteamCommunity = new CSteamCommunity();

let opportunisticProcessing = function(options, callback) {
	let E = new monads.ErrorMonad()
	let instructions = [E.try('processing')];
	for (const operation of options) {
		instructions.push(operation);
		instructions.push(E.retry('processing'));
	}
	instructions.pop();
	instructions.push(callback);
	return E.do(...instructions);
};

let mutateInput = (mutate, fun) => function(err, string, cb) {
	try {fun(err, mutate(string), cb)} catch(error) {cb(error)};
};

let toSteamId = (string) => new CSteamCommunity.SteamID(string);

let toSteamUser = function(err, id, cb) {
	if (err) {
		cb(err);
		return;
	}
	if (!id) {
		cb('Empty input provided');
		return;
	}
    SteamCommunity.getSteamUser(id, cb);
};

let nameOutput = (name, fun) => (err, string, rawCb) => fun(err, string, (error, result) => rawCb(error, {'type':name, 'value' : result}));

let isOddString = (string) => parseInt(string.slice(-1)) % 2;
let onlyIfNumeric = (fun=(x)=>x) => function(data) {
	if(parseInt(data)) {
		return fun(data);
	} else {
		throw `Expected numeric input, got ${data}`;
	}
};

let urlToSteamId = function (url) {
	let dissected = mUrl.parse(url);
	if(dissected.hostname == 'steamcommunity.com') // may or may not start with 'http://'
	{
		let pathArray = dissected.pathname.split('/');
		let trail = pathArray.pop();
		return (trail == '' ? pathArray.pop() : trail); // may or may not end with trailing slash
	}
	else { return null; }
};

let methods = {
	'asId64'	: nameOutput('id64', mutateInput(onlyIfNumeric(), toSteamUser)),
	'asId3Tail'	: nameOutput('id3', mutateInput(
		onlyIfNumeric((string) => toSteamId(`[U:1:${string}]`)),
		toSteamUser
	)),
	'asOldTail'	: nameOutput('old', mutateInput(
		onlyIfNumeric((string) => toSteamId(`STEAM_0:${isOddString(string)}:${string}`)),
		toSteamUser
	)),
	'asValidId'	: nameOutput('valid', toSteamUser),
	'asUrl'		: nameOutput('url', mutateInput(urlToSteamId, toSteamUser))
};

let stringToSteamId = function(string, cb) {
	let methodsToTry = ['asId64', 'asId3Tail', 'asOldTail', 'asValidId', 'asUrl'].map((name) => methods[name]);
	opportunisticProcessing(methodsToTry, cb)(string);
}

const tests = {
    'steamID' : 'STEAM_0:0:61441014',
    'steamID3' : '[U:1:122882028]',
    'steamID64' : '76561198083147756',
    'customURL' : 'daerdemandt',
    'name' : 'Daerdemandt',
    'profile' : 'http://steamcommunity.com/profiles/76561198083147756'
};

let app = express();

///*
//TODO: implement opportunistingProcessing with something like this:
let tryUntilResult = function(items, process, successCallback, stubData) {
    if (0 == items.length) {
        successCallback(stubData);
    } else {
        let [current, rest] = [items[0], items.slice(1)];
        process(current, function(err, data) {
            if (err || data) {
                successCallback(err, data);
            } else { // no errors, but we need to try other options
                tryUntilResult(rest, process, successCallback, stubData);
            }
        });
    }
}
//*/
app.get('/api/arbitraryStringToSteamId', function(req, res, next) {
    let ret = function(error, data) {
        if (error) {
            res.status(500).send({'error' : error.stack})
        } else if (!data) {
            res.status(404).send({'error' : 'not found'});
        } else {
			console.log(data.type);
			data = data.value;
		let theID = data.steamID;
            res.send({
                'name' : data.name,
                'steamId64' : theID.toString(),
		'steam32AccountId' : theID.accountid,
		'steamId32' : theID.getSteam3RenderedID(),
		'steam2Old' : theID.getSteam2RenderedID(),
		'steam2New' : theID.getSteam2RenderedID(true),
                'customURL' : data.customURL,
		'profileURL' : 'http://steamcommunity.com/profiles/' + theID.toString(),
		'isGroupchat' : theID.isGroupChat(),
		'isSteamLobby' : theID.isLobby(),
                'memberSince' : data.memberSince,
                'isOnline' : data.onlineState
            }); //TODO: more fields here
        }
    };
    stringToSteamId(decodeURIComponent(req.query.string.trim()), ret);
});

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

function processConvertQuery(request, response)
{
	response.status(501).send("STUB!");
}

app.post('/api/convert', processConvertQuery);

http.createServer(app).listen(process.env.PORT || 8080, function() {
    console.log('Listening on port ' + (process.env.PORT || 8080));
});
<|endoftext|>


<commit_before>'use strict';
var util   = require('util'),
    path   = require('path'),
    fs     = require('fs'),
    rimraf = require('rimraf'),
    yeoman = require('yeoman-generator'),
    exec   = require('child_process').exec,
    wp_dir = 'engine',
    themes = wp_dir + '/wp-content/themes/',
    theme  = themes + 'theme';

var JuicerGenerator = module.exports = function JuicerGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    // Change to the theme's directory.
    process.chdir(theme);
    this.installDependencies({ skipInstall: options['skip-install'] });

    console.log('Creating mysql db...');

    var pass = '';
    if (this.mysqlPass.length > 0) {
        pass = ' -p'+this.mysqlPass;
    }
    exec('echo "create database '+this.projectName+'" | mysql -uroot'+pass);
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(JuicerGenerator, yeoman.generators.Base);

JuicerGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(juicer);

  var prompts = [{
    type: 'input',
    name: 'projectName',
    message: 'What is your project\'s name?',
    default: 'Juicer'
  },{
      type: 'input',
      name: 'mysqlUser',
      message: 'What is your mysql user?',
      default: 'root'
  },{
      type: 'input',
      name: 'mysqlPass',
      message: 'What is this mysql user\'s password?',
      default: ''
  }];

  this.prompt(prompts, function (props) {
    this.projectName = props.projectName.toLowerCase().replace(' ', '_');
    this.mysqlUser = props.mysqlUser;
    this.mysqlPass = props.mysqlPass;

    cb();
  }.bind(this));
};

// Get latest stable Wordpress
JuicerGenerator.prototype.wordpress = function wordpress() {
    var cb = this.async(),
        self = this;

    // From: https://github.com/romainberger/yeoman-wordpress (with modifications)
    try {
        var version = exec('git ls-remote --tags git://github.com/WordPress/WordPress.git', function(err, stdout, stderr) {
          if (err !== null) {
            self.writeln('exec error: ' + err);
          }
          else {
            var pattern = /\d\.\d[\.\d]*/ig
              , match = stdout.match(pattern)
              , patternShort = /^\d\.\d$/
              , latestVersion = match[match.length - 1]
              , semverLatestString = latestVersion;

            if (semverLatestString.match(patternShort)) semverLatestString += '.0';

            if (semverLatestString !== null && typeof semverLatestString !== 'undefined') {
              self.latestVersion = latestVersion;
              self.log.writeln('Latest version: '+self.latestVersion);
            }
          }
          self.remote('wordpress', 'wordpress', self.latestVersion, function(err, remote) {
              remote.bulkDirectory('.', wp_dir);

              cb();
          });
        });
      }
    catch(e) {
        cb();
    }
};

JuicerGenerator.prototype.purge_themes = function purge_themes() {
    var cb = this.async(),
        self = this;

    // Clean up themes.
    // From: https://github.com/romainberger/yeoman-wordpress (with modifications)
    fs.readdir(themes, function(err, files) {
        if (typeof files != 'undefined' && files.length !== 0) {
            files.forEach(function(file) {
                var pathFile = fs.realpathSync(themes+file)
                  , isDirectory = fs.statSync(pathFile).isDirectory();

                if (isDirectory) {
                    rimraf.sync(pathFile);
                    self.log.writeln('Removing ' + pathFile);
                }
            });
        }
    });

    cb();
};

// Copy over theme files
JuicerGenerator.prototype.app = function app() {
  this.directory('theme', theme);
  this.copy('server.sh', 'server.sh');
  this.copy('favicon.ico', 'favicon.ico');
  this.copy('index.php', 'index.php');
};

// Copy over MAMP wp-config.php
JuicerGenerator.prototype.wp_config = function wp_config() {
    this.copy('wp-config.php', wp_dir+'/wp-config.php');
    rimraf.sync(wp_dir+'/wp-config-sample.php');
};

JuicerGenerator.prototype.h5bp = function h5bp() {
  var cb = this.async();

  this.remote('h5bp', 'html5-boilerplate', 'master', function(err, remote) {
      if (err) {
          return cb(err);
      }
      remote.copy('.htaccess', '.htaccess');
      remote.copy('crossdomain.xml', 'crossdomain.xml');
      remote.copy('humans.txt', 'humans.txt');
      remote.copy('robots.txt', 'robots.txt');
      cb();
  }, true);
};

JuicerGenerator.prototype.stylesheets = function stylesheets() {
    var cb = this.async();

    this.remote('ftzeng', 'atomic', 'master', function(err, remote) {
        if (err) {
            return cb(err);
        }
        remote.directory('.', theme+'/css/');
        cb();
    }, true);
};

var juicer =
'\n\t     _         _                         '+
'\n\t    (_) _   _ (_)   ___    __   _ __     '+
'\n\t    | |( ) ( )| | /\'___) /\'__`\\( \'__)'+
'\n\t    | || (_) || |( (___ (  ___/| |       '+
'\n\t _  | |`\\___/\'(_)`\\____)`\\____)(_)   '+
'\n\t( )_| |                                  '+
'\n\t\\___/\'                                 '+
'\n\n\t       [A Yeoman generator]\n\n';

<commit_msg>updated for h5bp changes<commit_after>'use strict';
var util   = require('util'),
    path   = require('path'),
    fs     = require('fs'),
    rimraf = require('rimraf'),
    yeoman = require('yeoman-generator'),
    exec   = require('child_process').exec,
    wp_dir = 'engine',
    themes = wp_dir + '/wp-content/themes/',
    theme  = themes + 'theme';

var JuicerGenerator = module.exports = function JuicerGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    // Change to the theme's directory.
    process.chdir(theme);
    this.installDependencies({ skipInstall: options['skip-install'] });

    console.log('Creating mysql db...');

    var pass = '';
    if (this.mysqlPass.length > 0) {
        pass = ' -p'+this.mysqlPass;
    }
    exec('echo "create database '+this.projectName+'" | mysql -uroot'+pass);
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(JuicerGenerator, yeoman.generators.Base);

JuicerGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(juicer);

  var prompts = [{
    type: 'input',
    name: 'projectName',
    message: 'What is your project\'s name?',
    default: 'Juicer'
  },{
      type: 'input',
      name: 'mysqlUser',
      message: 'What is your mysql user?',
      default: 'root'
  },{
      type: 'input',
      name: 'mysqlPass',
      message: 'What is this mysql user\'s password?',
      default: ''
  }];

  this.prompt(prompts, function (props) {
    this.projectName = props.projectName.toLowerCase().replace(' ', '_');
    this.mysqlUser = props.mysqlUser;
    this.mysqlPass = props.mysqlPass;

    cb();
  }.bind(this));
};

// Get latest stable Wordpress
JuicerGenerator.prototype.wordpress = function wordpress() {
    var cb = this.async(),
        self = this;

    // From: https://github.com/romainberger/yeoman-wordpress (with modifications)
    try {
        var version = exec('git ls-remote --tags git://github.com/WordPress/WordPress.git', function(err, stdout, stderr) {
          if (err !== null) {
            self.writeln('exec error: ' + err);
          }
          else {
            var pattern = /\d\.\d[\.\d]*/ig
              , match = stdout.match(pattern)
              , patternShort = /^\d\.\d$/
              , latestVersion = match[match.length - 1]
              , semverLatestString = latestVersion;

            if (semverLatestString.match(patternShort)) semverLatestString += '.0';

            if (semverLatestString !== null && typeof semverLatestString !== 'undefined') {
              self.latestVersion = latestVersion;
              self.log.writeln('Latest version: '+self.latestVersion);
            }
          }
          self.remote('wordpress', 'wordpress', self.latestVersion, function(err, remote) {
              remote.bulkDirectory('.', wp_dir);

              cb();
          });
        });
      }
    catch(e) {
        cb();
    }
};

JuicerGenerator.prototype.purge_themes = function purge_themes() {
    var cb = this.async(),
        self = this;

    // Clean up themes.
    // From: https://github.com/romainberger/yeoman-wordpress (with modifications)
    fs.readdir(themes, function(err, files) {
        if (typeof files != 'undefined' && files.length !== 0) {
            files.forEach(function(file) {
                var pathFile = fs.realpathSync(themes+file)
                  , isDirectory = fs.statSync(pathFile).isDirectory();

                if (isDirectory) {
                    rimraf.sync(pathFile);
                    self.log.writeln('Removing ' + pathFile);
                }
            });
        }
    });

    cb();
};

// Copy over theme files
JuicerGenerator.prototype.app = function app() {
  this.directory('theme', theme);
  this.copy('server.sh', 'server.sh');
  this.copy('favicon.ico', 'favicon.ico');
  this.copy('index.php', 'index.php');
};

// Copy over MAMP wp-config.php
JuicerGenerator.prototype.wp_config = function wp_config() {
    this.copy('wp-config.php', wp_dir+'/wp-config.php');
    rimraf.sync(wp_dir+'/wp-config-sample.php');
};

JuicerGenerator.prototype.h5bp = function h5bp() {
  var cb = this.async();

  this.remote('h5bp', 'html5-boilerplate', 'master', function(err, remote) {
      if (err) {
          return cb(err);
      }
      remote.copy('dist/.htaccess', '.htaccess');
      remote.copy('dist/crossdomain.xml', 'crossdomain.xml');
      remote.copy('dist/humans.txt', 'humans.txt');
      remote.copy('dist/robots.txt', 'robots.txt');
      cb();
  }, true);
};

JuicerGenerator.prototype.stylesheets = function stylesheets() {
    var cb = this.async();

    this.remote('ftzeng', 'atomic', 'master', function(err, remote) {
        if (err) {
            return cb(err);
        }
        remote.directory('.', theme+'/css/');
        cb();
    }, true);
};

var juicer =
'\n\t     _         _                         '+
'\n\t    (_) _   _ (_)   ___    __   _ __     '+
'\n\t    | |( ) ( )| | /\'___) /\'__`\\( \'__)'+
'\n\t    | || (_) || |( (___ (  ___/| |       '+
'\n\t _  | |`\\___/\'(_)`\\____)`\\____)(_)   '+
'\n\t( )_| |                                  '+
'\n\t\\___/\'                                 '+
'\n\n\t       [A Yeoman generator]\n\n';

<|endoftext|>


<commit_before>var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
var path = require('path');

var middleware = require('./middleware');
var routes = require('./routes');
var mailer = require('./mailer');

var app = express();

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

app.get('/', function (req, res) {
	res.status(404);
	res.type('html');
	res.send('
This is only useful to computers. Documentation available here
');
});

app.use(middleware.authorization(app));
app.use(middleware.typeValidation(app));
app.use(bodyParser.json());

routes.setup(app);

app.all('*', function (req, res) {
	res.status(404).end();
});

module.exports = app;

if (require.main === module) {
	var server = http.createServer(app);
	var port = app.get('port');

	server.listen(port, function () {
		console.info('Express server listening on port ' + app.get('port'));
	});
}
<commit_msg>Added Istanbul ignore for the code which makes the server listen<commit_after>var express = require('express');
var bodyParser = require('body-parser');
var http = require('http');
var path = require('path');

var middleware = require('./middleware');
var routes = require('./routes');
var mailer = require('./mailer');

var app = express();

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

app.get('/', function (req, res) {
	res.status(404);
	res.type('html');
	res.send('
This is only useful to computers. Documentation available here
');
});

app.use(middleware.authorization(app));
app.use(middleware.typeValidation(app));
app.use(bodyParser.json());

routes.setup(app);

app.all('*', function (req, res) {
	res.status(404).end();
});

module.exports = app;

/* istanbul ignore if : not used during unit testing */
if (require.main === module) {
	var server = http.createServer(app);
	var port = app.get('port');

	server.listen(port, function () {
		console.info('Express server listening on port ' + app.get('port'));
	});
}
<|endoftext|>


<commit_before>'use strict';

var express    = require('express'),
    app        = module.exports = express(),
    routes     = require('./routes'),
    secrets    = require('../config/secrets'),
    sass       = require('node-sass-middleware'),
    morgan     = require('morgan'),
    bodyParser = require('body-parser'),
    mongoose   = require('mongoose');

mongoose.connect(process.env.MONGODB_URL || secrets.MONGODB_URL);

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

app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(express.static('www'));
app.use(sass({
  src: 'www/styles',
  dest: 'www/styles',
  outputStyle: 'compressed',
  prefix: '/styles'
}));

app.use('/', routes);

app.listen(app.get('port'), function() {
  console.log('Express listening on port ' + app.get('port'));
});
<commit_msg>modified secrets usage to allow for use locally and deployed<commit_after>'use strict';

var express    = require('express'),
    app        = module.exports = express(),
    routes     = require('./routes'),
    sass       = require('node-sass-middleware'),
    morgan     = require('morgan'),
    bodyParser = require('body-parser'),
    mongoose   = require('mongoose');

mongoose.connect(process.env.MONGODB_URL || require('../config/secrets').MONGODB_URL);

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

app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(express.static('www'));
app.use(sass({
  src: 'www/styles',
  dest: 'www/styles',
  outputStyle: 'compressed',
  prefix: '/styles'
}));

app.use('/', routes);

app.listen(app.get('port'), function() {
  console.log('Express listening on port ' + app.get('port'));
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';

import Actions from './actions';
import CardAnswerActions from './components/CardAnswerActions';
import CardItem from './components/CardItem';

const cards = (state = [], action) => {
	switch (action.type) {
		case 'SET_CARDS':
			return action.cards;
		case 'ADD_CARD':
			return [...state, {
				front: action.front,
				back: action.back,
				level: 0
			}];
		case 'REMOVE_CARD':
			return state.filter((card) => card.front !== action.front);
		case 'DIFFICULTY_LEVEL':
			return state.map((card) => {
				if (card.front === action.front) {
					return {
						...card,
						level: action.level
					}
				}
				return card;
			});

		default:
			return state;
	}
}

const memo = (state = [], action) => {
	switch (action.type) {
		case 'START_MEMO':
			return action.cards.map((_, i) => ({index: i, isAnswered: false}));
		case 'SHOW_ANSWER':
			return state.map((m) => {
				if (m.index === action.index) {
					return {
						...m,
						isAnswered: true
					}
				}
				return m;
			});
		case 'DIFFICULTY_LEVEL':
			return state.slice(1)
		default:
			return state;
	}
}

const status = (state = { isStarted: false, dirty: false }, action) => {
	switch (action.type) {
		case 'START_MEMO':
			return {...state, isStarted: true};
		case 'STOP_MEMO':
			return {...state, isStarted: false};
		case 'ADD_CARD':
		case 'REMOVE_CARD':
			return {...state, dirty: true};
		case 'APP_SAVE':
			return {...state, dirty: false};
		default:
			return state;
	}
};

const app = combineReducers({
	status,
	cards,
	memo
});

const store = createStore(app);

const Editor = ({ cards }) => {
	let inputFront = null,
		inputBack = null;

	const handleAdd = () => {
		store.dispatch(Actions.addCard(inputFront.value, inputBack.value));
		inputFront.value = '';
		inputBack.value = '';
	};

	const handleView = () => {

	};

	const handleRemove = (front) => {
		store.dispatch({type: 'REMOVE_CARD', front});
	};

	return (

				Front:
				<input ref={(c) => inputFront = c} />

				Back:
				<input ref={(c) => inputBack = c} />

			<button onClick={handleAdd}>
				Add
			</button>
			<button onClick={handleView}>
				View
			</button>

				{cards.map((card, i) => <CardItem {...card} key={i} onRemove={handleRemove} />  )}

	);
}

const Player = ({ memo, cards }) => {
	const handleOK = () => store.dispatch(Actions.stopLearn());

	if (memo.length === 0) {
		return (

Test Passed!

				<button onClick={handleOK}>OK</button>

		);
	}
	const question = memo[0];
	const card = cards[question.index];

	const handleAnswer = () => store.dispatch(Actions.answer(question.index));
	const handleDifficult = (level) => store.dispatch(Actions.cardLevel(card.front, level));

	return (

					{card.front}

					{card.back}

			<CardAnswerActions
				isAnswered={question.isAnswered}
				onAnswer={handleAnswer}
				onDifficult={handleDifficult}
			/>

	);
}

const FlashApp = (props) => {

	const { cards, status, memo } = props;

	const handleStart = () => store.dispatch(Actions.startLearn(cards));

	const handleSave = () => {
		localStorage.setItem('react-flashcards', JSON.stringify(cards));
		alert(`Saved: ${cards.length} cards`);
	}

	const handleLoad = () => {
		store.dispatch(Actions.load());
	}

	const view = status.isStarted ? <Player cards={cards} memo={memo} /> : <Editor cards={cards} />;

	return (

				FlashCards

Load

Save

{`English: ${cards.length}`}

						<button disabled={!cards.length} onClick={handleStart}>
							Play
						</button>
						<button onClick={handleStart}>
							Add
						</button>

			{view}

				<button onClick={handleLoad}>
					Load
				</button>
				<button onClick={handleSave}>
					Save
				</button>

	);
}

const render = () => {
	ReactDOM.render(
		<FlashApp {...store.getState()} />,
		document.getElementById('app')
	);
};

store.subscribe(render);
render();
<commit_msg>Introduce Editor reducer<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, combineReducers } from 'redux';
import { Provider } from 'react-redux';

import Actions from './actions';
import CardAnswerActions from './components/CardAnswerActions';
import CardItem from './components/CardItem';

const cards = (state = [], action) => {
	switch (action.type) {
		case 'SET_CARDS':
			return action.cards;
		case 'ADD_CARD':
			return [...state, {
				front: action.front,
				back: action.back,
				level: 0
			}];
		case 'REMOVE_CARD':
			return state.filter((card) => card.front !== action.front);
		case 'DIFFICULTY_LEVEL':
			return state.map((card) => {
				if (card.front === action.front) {
					return {
						...card,
						level: action.level
					}
				}
				return card;
			});

		default:
			return state;
	}
}

const editor = (state = {}, action) => {
	switch (action.type) {
		case 'TOGGLE_CARDS_VIEW':
			return {...state, isShowCards: !state.isShowCards}
		default:
			return state;
	}
}

const memo = (state = [], action) => {
	switch (action.type) {
		case 'START_MEMO':
			return action.cards.map((_, i) => ({index: i, isAnswered: false}));
		case 'SHOW_ANSWER':
			return state.map((m) => {
				if (m.index === action.index) {
					return {
						...m,
						isAnswered: true
					}
				}
				return m;
			});
		case 'DIFFICULTY_LEVEL':
			return state.slice(1)
		default:
			return state;
	}
}

const status = (state = { isStarted: false, dirty: false }, action) => {
	switch (action.type) {
		case 'START_MEMO':
			return {...state, isStarted: true};
		case 'STOP_MEMO':
			return {...state, isStarted: false};
		case 'ADD_CARD':
		case 'REMOVE_CARD':
			return {...state, dirty: true};
		case 'APP_SAVE':
			return {...state, dirty: false};
		default:
			return state;
	}
};

const app = combineReducers({
	status,
	cards,
	memo,
	editor
});

const store = createStore(app);

const Editor = ({ cards, isShowCards }) => {
	let inputFront = null,
		inputBack = null;

	const handleAdd = () => {
		store.dispatch(Actions.addCard(inputFront.value, inputBack.value));
		inputFront.value = '';
		inputBack.value = '';
	};

	const handleView = () => {
		store.dispatch({type: 'TOGGLE_CARDS_VIEW'});
	};

	const handleRemove = (front) => {
		store.dispatch({type: 'REMOVE_CARD', front});
	};

	return (

				Front:
				<input ref={(c) => inputFront = c} />

				Back:
				<input ref={(c) => inputBack = c} />

			<button onClick={handleAdd}>
				Add
			</button>
			<button onClick={handleView}>
				{isShowCards ? 'Hide' : 'View'}
			</button>

				{cards.map((card, i) => <CardItem {...card} key={i} onRemove={handleRemove} />  )}

	);
}

const Player = ({ memo, cards }) => {
	const handleOK = () => store.dispatch(Actions.stopLearn());

	if (memo.length === 0) {
		return (

Test Passed!

				<button onClick={handleOK}>OK</button>

		);
	}
	const question = memo[0];
	const card = cards[question.index];

	const handleAnswer = () => store.dispatch(Actions.answer(question.index));
	const handleDifficult = (level) => store.dispatch(Actions.cardLevel(card.front, level));

	return (

					{card.front}

					{card.back}

			<CardAnswerActions
				isAnswered={question.isAnswered}
				onAnswer={handleAnswer}
				onDifficult={handleDifficult}
			/>

	);
}

const FlashApp = (props) => {

	const { cards, status, memo, editor } = props;

	const handleStart = () => store.dispatch(Actions.startLearn(cards));

	const handleSave = () => {
		localStorage.setItem('react-flashcards', JSON.stringify(cards));
		alert(`Saved: ${cards.length} cards`);
	}

	const handleLoad = () => {
		store.dispatch(Actions.load());
	}

	const view = status.isStarted ? <Player cards={cards} memo={memo} /> : <Editor cards={cards} isShowCards={editor.isShowCards}/>;

	return (

				FlashCards

Load

Save

{`English: ${cards.length}`}

						<button disabled={!cards.length || status.isStarted} onClick={handleStart}>
							Play
						</button>
						<button onClick={handleStart}>
							Add
						</button>

			{view}

				<button onClick={handleLoad}>
					Load
				</button>
				<button onClick={handleSave} disabled={!status.dirty}>
					Save
				</button>

	);
}

const render = () => {
	ReactDOM.render(
		<Provider store={store}>
			<FlashApp {...store.getState()} />
		</Provider>,
		document.getElementById('app')
	);
};

store.subscribe(render);
render();
<|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict';

const program = require('commander');
const fs = require('fs');
const path = require('path');
const csvparse = require('csv-parse/lib/sync');

let getFormattedPercentage = (number, total) => {
    let percentage = number / total;
    return String(Number(percentage * 100).toFixed(1)) + '%';
};

let summarizeFunction = (portfolio, options) => {
    let portfolioPath = path.resolve(portfolio);
    let configPath = path.resolve(options.config);
    let portfolioSummary = [];
    let noFundDataList = [];
    let result = {};
    let total = 0;

    // sum and consolidate all the fund values.
    if (fs.existsSync(portfolioPath)) {
        let input = fs.readFileSync(portfolioPath, {encoding: 'utf8'});
        let records = csvparse(input, {comment: '#', columns: true});

        for (let a = 0; a < records.length; a++) {
            if (typeof(records[a].fund) !== 'undefined') {
                if (typeof(portfolioSummary[records[a].fund]) === 'undefined') {
                    portfolioSummary[records[a].fund] = parseFloat(records[a].amount);
                } else {
                    portfolioSummary[records[a].fund] += parseFloat(records[a].amount);
                }
            }
        }
    }

    // convert to iterable pairs
    portfolioSummary = Object.entries(portfolioSummary);

    if (fs.existsSync(configPath)) {
        let fundProperties = require(configPath);

        for (let [fund, amount] of portfolioSummary) {
            total += parseFloat(amount);

            if (typeof(fundProperties[fund]) !== 'undefined') {
                for (let [propertyType, propertyData] of Object.entries(fundProperties[fund])) {

                    // make propertyName part of the result set
                    if (typeof(result[propertyType]) === 'undefined') {
                        result[propertyType] = {};
                    }

                    for (let [propertyName, propertyPercentage] of Object.entries(propertyData)) {
                        if (typeof(result[propertyType][propertyName]) === 'undefined') {
                            result[propertyType][propertyName] = 0;
                        }

                        if (!isNaN(parseFloat(propertyPercentage)) && !isNaN(parseFloat(amount))) {
                            result[propertyType][propertyName] += (parseFloat(propertyPercentage) * parseFloat(amount));
                        }
                    }
                }
            } else {
                noFundDataList.push(fund);
            }
        }
    }

    for (let [propertyType, propertyData] of Object.entries(result)) {
        console.info("\n" + propertyType + "\n" + new Array(propertyType.length + 1).join("-"));

        for (let [propertyName, propertyAmount] of Object.entries(propertyData)) {
            console.log(propertyName + ": " + getFormattedPercentage(propertyAmount, total) + "\t\t(" + Number(propertyAmount).toFixed(2) + " of " + Number(total).toFixed(2) + ")");
        }
    }

    if (noFundDataList.length > 0) {
        console.log("\n");
        for (let fund of noFundDataList) {
            console.error("WARNING: COULD NOT FIND CONFIGURATION DATA FOR " + fund);
        }
    }

    console.log("\n");
};

program
    .version('0.1.0')
    .command('summarize <portfolio>')
    .description('Aggregates and summarizes the properties of a portfolio.')
    .option('-f --filter <name>', 'Only summarize and display the given property.')
    .option('-c --config <path>', 'Which fund property configuration should we use?', path.resolve('/app/config/default.json'))
    .action(summarizeFunction);

program.parse(process.argv);<commit_msg>add commenting and break down display into individual functions.<commit_after>#!/usr/bin/env node
'use strict';

const program = require('commander');
const fs = require('fs');
const path = require('path');
const csvparse = require('csv-parse/lib/sync');

let getFormattedPercentage = (number, total) => {
    let percentage = number / total;
    return String(Number(percentage * 100).toFixed(1)) + '%';
};

let displayErrors = (fundList) => {
    if (fundList.length > 0) {
        console.log("\n");
        for (let fund of fundList) {
            console.error("WARNING: COULD NOT FIND CONFIGURATION DATA FOR " + fund);
        }
    }
};

let displayResults = (result, total) => {
    for (let [propertyType, propertyData] of Object.entries(result)) {
        console.info("\n" + propertyType + "\n" + new Array(propertyType.length + 1).join("-"));

        for (let [propertyName, propertyAmount] of Object.entries(propertyData)) {
            console.log(propertyName + ": " + getFormattedPercentage(propertyAmount, total) + "\t\t(" + Number(propertyAmount).toFixed(2) + " of " + Number(total).toFixed(2) + ")");
        }
    }
};

let summarizeFunction = (portfolio, options) => {
    let portfolioPath = path.resolve(portfolio);
    let configPath = path.resolve(options.config);
    let portfolioSummary = [];
    let noFundDataList = [];
    let result = {};
    let total = 0;

    // sum and consolidate all the fund values.
    if (fs.existsSync(portfolioPath)) {
        let input = fs.readFileSync(portfolioPath, {encoding: 'utf8'});
        let records = csvparse(input, {comment: '#', columns: true});

        // sum up all the entries from the portfolio
        for (let a = 0; a < records.length; a++) {
            if (typeof(records[a].fund) !== 'undefined') {
                if (typeof(portfolioSummary[records[a].fund]) === 'undefined') {
                    portfolioSummary[records[a].fund] = parseFloat(records[a].amount);
                } else {
                    portfolioSummary[records[a].fund] += parseFloat(records[a].amount);
                }
            }
        }
    }

    // create a result set from a combination of portfolio and property config
    if (fs.existsSync(configPath)) {
        let fundProperties = require(configPath);

        for (let [fund, amount] of Object.entries(portfolioSummary)) {
            total += parseFloat(amount);

            if (typeof(fundProperties[fund]) !== 'undefined') {
                for (let [propertyType, propertyData] of Object.entries(fundProperties[fund])) {

                    // make propertyName part of the result set
                    if (typeof(result[propertyType]) === 'undefined') {
                        result[propertyType] = {};
                    }

                    for (let [propertyName, propertyPercentage] of Object.entries(propertyData)) {
                        if (typeof(result[propertyType][propertyName]) === 'undefined') {
                            result[propertyType][propertyName] = 0;
                        }

                        if (!isNaN(parseFloat(propertyPercentage)) && !isNaN(parseFloat(amount))) {
                            result[propertyType][propertyName] += (parseFloat(propertyPercentage) * parseFloat(amount));
                        }
                    }
                }
            } else {
                noFundDataList.push(fund);
            }
        }
    }

    displayResults(result, total);
    displayErrors(noFundDataList);

    console.log("\n");
};

program
    .version('0.1.0')
    .command('summarize <portfolio>')
    .description('Aggregates and summarizes the properties of a portfolio.')
    .option('-f --filter <name>', 'Only summarize and display the given property.')
    .option('-c --config <path>', 'Which fund property configuration should we use?', path.resolve('/app/config/default.json'))
    .action(summarizeFunction);

program.parse(process.argv);<|endoftext|>


<commit_before>'use strict';

const { error, print, strong, warn } = require('../utils/cnsl');
const { hunt: { sync: hunt } } = require('recur-fs');
const { cache: dependencyResolverCache, identify, VERSION_DELIMITER } = require('../dependency-resolver');
const buildParser = require('./buildParser');
const File = require('../File');
const fs = require('fs');
const merge = require('lodash/merge');
const path = require('path');
const pluginLoader = require('./pluginLoader');
const serverParser = require('./serverParser');
const utils = require('../utils');

const DEFAULT_MANIFEST = {
  js: 'buddy.js',
  json: 'buddy.json',
  pkgjson: 'package.json'
};

/**
 * Retrieve new instance of Config
 * @param {String|Object} [configpath]
 * @param {Object} [runtimeOptions]
 * @returns {Config}
 */
module.exports = function configFactory (configpath, runtimeOptions) {
  return new Config(configpath, runtimeOptions);
};

class Config {
  /**
   * Constructor
   * @param {String|Object} [configpath]
   * @param {Object} [runtimeOptions]
   */
  constructor (configpath, runtimeOptions) {
    let data;

    if ('string' == typeof configpath || configpath == null) {
      this.url = locateConfig(configpath);
      data = require(this.url);

      // Set current directory to location of file
      process.chdir(path.dirname(this.url));
      print('loaded config ' + strong(this.url), 0);

    // Passed in JSON object
    } else {
      this.url = '';
      data = configpath;
    }
    // Package.json
    if (data.buddy) data = data.buddy;
    // Handle super simple mode
    if (data.input) data = { build: [data] };

    this.build = [];
    this.fileDefinitionByExtension = {};
    this.fileExtensions = {};
    this.npmModulepaths = parseNpmModulepaths();
    this.runtimeOptions = merge({
      compress: false,
      debug: false,
      deploy: false,
      grep: false,
      invert: false,
      reload: false,
      script: false,
      serve: false,
      watch: false
    }, runtimeOptions);
    this.script = '';
    this.server = {
      directory: '.',
      port: 8080
    };
    this.fileFactory = this.fileFactory.bind(this);

    // Merge config file data
    merge(this, data);

    // Load default/installed plugins
    // Generates fileExtensions/types used to validate build
    pluginLoader.loadBuddyPlugins(this, parsePlugins(this));
    // Parse 'server' data parameter
    serverParser(this);
    // Parse 'build' data parameter
    buildParser(this);
  }

  /**
   * Retrieve File instance for 'filepath'
   * @param {String} filepath
   * @param {Object} options
   *  - {Object} fileCache
   *  - {Object} fileExtensions
   *  - {Function} fileFactory
   *  - {Array} npmModulepaths
   *  - {Object} pluginOptions
   *  - {Object} runtimeOptions
   * @returns {File}
   */
  fileFactory (filepath, options) {
    const { fileCache, fileExtensions } = options;

    // Retrieve cached
    if (fileCache.hasFile(filepath)) {
      const file = fileCache.getFile(filepath);

      file.options = options;
      return file;
    }

    const extension = path.extname(filepath).slice(1);
    const id = identify(filepath, { fileExtensions });
    const ctor = this.fileDefinitionByExtension[extension];

    if (!id) throw Error(`unable to create file for: ${strong(filepath)}`);

    const file = new ctor(id, filepath, options);

    fileCache.addFile(file);

    // Warn of multiple versions
    const versions = dependencyResolverCache.getFileVersions(id);

    if (versions.length > 1) {
      const [name, version] = id.split(VERSION_DELIMITER);
      const parts = name.split('/');
      // Handle scoped
      const pkg = parts.slice(0, (parts[0].charAt(0) == '@') ? 2 : 1).join('/');

      warn(`more than one version of the ${strong(pkg)} package exists (${strong(file.relpath)}). If ${strong(pkg)} is a project dependency, consider using the same version (${strong(version)}) to reduce duplication`, 2);
    }

    return file;
  }

  /**
   * Register file 'extensions' for 'type'
   * @param {Array} extensions
   * @param {String} type
   */
  registerFileExtensionsForType (extensions, type) {
    if (!this.fileExtensions[type]) this.fileExtensions[type] = [];
    this.fileExtensions[type].push(...extensions);
  }

  /**
   * Register target 'version' for 'type'
   * @param {String} version
   * @param {Array} plugins
   * @param {String} type
   */
  registerTargetVersionForType (version, plugins, type) {
    if (type == 'js') {
      pluginLoader.addPreset('babel', version, plugins);
    }
  }

  /**
   * Register file definitiion and 'extensions' for 'type'
   * @param {Function} define
   * @param {Array} extensions
   * @param {String} type
   */
  registerFileDefinitionAndExtensionsForType (define, extensions, type) {
    const def = define(this.fileDefinitionByExtension[type] || File, utils);

    if (extensions) {
      this.registerFileExtensionsForType(extensions, type);
      extensions.forEach((extension) => {
        this.fileDefinitionByExtension[extension] = def;
      });
    }
  }

  /**
   * Extend file definitiion for 'extensions' or 'type'
   * @param {Function} extend
   * @param {Array} extensions
   * @param {String} type
   * @returns {null}
   */
  extendFileDefinitionForExtensionsOrType (extend, extensions, type) {
    const key = extensions
      ? extensions[0]
      : this.fileExtensions[type][0];
    const def = this.fileDefinitionByExtension[key];

    if (!def) return error(`no File type available for extension for ${strong(key)}`);

    extend(def.prototype, utils);
  }

  /**
   * Destroy instance
   */
  destroy () {
    this.build.forEach((build) => {
      build.fileCache.flush();
    });
    dependencyResolverCache.clear();
  }
}

/**
 * Locate the configuration file
 * Walks the directory tree if no file/directory specified
 * @param {String} [url]
 * @returns {String}
 */
function locateConfig (url) {
  let configpath = '';

  function check (dir) {
    // Support js, json, and package.json
    const urljs = path.join(dir, DEFAULT_MANIFEST.js);
    const urljson = path.join(dir, DEFAULT_MANIFEST.json);
    const urlpkgjson = path.join(dir, DEFAULT_MANIFEST.pkgjson);
    let urlFinal;

    if (fs.existsSync(urlFinal = urljs)
      || fs.existsSync(urlFinal = urljson)
      || fs.existsSync(urlFinal = urlpkgjson)) {
        return urlFinal;
    }

    return '';
  }

  if (url) {
    configpath = path.resolve(url);
    try {
      // Try default file name if passed directory
      if (!path.extname(configpath).length || fs.statSync(configpath).isDirectory()) {
        configpath = check(configpath);
        if (!configpath) throw Error('no default found');
      }
    } catch (err) {
      throw Error(strong('buddy') + ' config not found in ' + strong(path.dirname(url)));
    }

  // No url specified
  } else {
    try {
      // Find the first instance of a DEFAULT file based on the current working directory
      configpath = hunt(process.cwd(), (resource, stat) => {
        if (stat.isFile()) {
          const basename = path.basename(resource);

          return (basename == DEFAULT_MANIFEST.js || basename == DEFAULT_MANIFEST.json || basename == DEFAULT_MANIFEST.pkgjson);
        }
      }, true);
    } catch (err) {
      if (!configpath) throw Error(strong('buddy') + ' config not found');
    }
  }

  return configpath;
}

/**
 * Parse plugins defined in 'config'
 * @param {Config} config
 * @returns {Array}
 */
function parsePlugins (config) {
  let plugins = [];

  function parse (plugins) {
    return plugins.map((plugin) => {
      if ('string' == typeof plugin) plugin = path.resolve(plugin);
      return plugin;
    });
  }

  // Handle plugin paths defined in config file
  if (config.plugins) {
    plugins.push(...parse(config.plugins));
    delete config.plugins;
  }
  // Handle plugin paths/functions defined in runtime options
  if (config.runtimeOptions.plugins) {
    plugins.push(...parse(config.runtimeOptions.plugins));
    delete config.runtimeOptions.plugins;
  }

  return plugins;
}

/**
 * Parse all npm package paths
 * @returns {Array}
 */
function parseNpmModulepaths () {
  const jsonpath = path.resolve('package.json');

  try {
    const json = require(jsonpath);

    return ['dependencies', 'devDependencies', 'optionalDependencies'].reduce((packages, type) => {
      if (type in json) {
        for (const dependency in json[type]) {
          packages.push(path.resolve('node_modules', dependency));
        }
      }
      return packages;
    }, []);
  } catch (err) {
    return [];
  }
}<commit_msg>Split warning on to 2 lines<commit_after>'use strict';

const { error, print, strong, warn } = require('../utils/cnsl');
const { hunt: { sync: hunt } } = require('recur-fs');
const { cache: dependencyResolverCache, identify, VERSION_DELIMITER } = require('../dependency-resolver');
const buildParser = require('./buildParser');
const File = require('../File');
const fs = require('fs');
const merge = require('lodash/merge');
const path = require('path');
const pluginLoader = require('./pluginLoader');
const serverParser = require('./serverParser');
const utils = require('../utils');

const DEFAULT_MANIFEST = {
  js: 'buddy.js',
  json: 'buddy.json',
  pkgjson: 'package.json'
};

/**
 * Retrieve new instance of Config
 * @param {String|Object} [configpath]
 * @param {Object} [runtimeOptions]
 * @returns {Config}
 */
module.exports = function configFactory (configpath, runtimeOptions) {
  return new Config(configpath, runtimeOptions);
};

class Config {
  /**
   * Constructor
   * @param {String|Object} [configpath]
   * @param {Object} [runtimeOptions]
   */
  constructor (configpath, runtimeOptions) {
    let data;

    if ('string' == typeof configpath || configpath == null) {
      this.url = locateConfig(configpath);
      data = require(this.url);

      // Set current directory to location of file
      process.chdir(path.dirname(this.url));
      print('loaded config ' + strong(this.url), 0);

    // Passed in JSON object
    } else {
      this.url = '';
      data = configpath;
    }
    // Package.json
    if (data.buddy) data = data.buddy;
    // Handle super simple mode
    if (data.input) data = { build: [data] };

    this.build = [];
    this.fileDefinitionByExtension = {};
    this.fileExtensions = {};
    this.npmModulepaths = parseNpmModulepaths();
    this.runtimeOptions = merge({
      compress: false,
      debug: false,
      deploy: false,
      grep: false,
      invert: false,
      reload: false,
      script: false,
      serve: false,
      watch: false
    }, runtimeOptions);
    this.script = '';
    this.server = {
      directory: '.',
      port: 8080
    };
    this.fileFactory = this.fileFactory.bind(this);

    // Merge config file data
    merge(this, data);

    // Load default/installed plugins
    // Generates fileExtensions/types used to validate build
    pluginLoader.loadBuddyPlugins(this, parsePlugins(this));
    // Parse 'server' data parameter
    serverParser(this);
    // Parse 'build' data parameter
    buildParser(this);
  }

  /**
   * Retrieve File instance for 'filepath'
   * @param {String} filepath
   * @param {Object} options
   *  - {Object} fileCache
   *  - {Object} fileExtensions
   *  - {Function} fileFactory
   *  - {Array} npmModulepaths
   *  - {Object} pluginOptions
   *  - {Object} runtimeOptions
   * @returns {File}
   */
  fileFactory (filepath, options) {
    const { fileCache, fileExtensions } = options;

    // Retrieve cached
    if (fileCache.hasFile(filepath)) {
      const file = fileCache.getFile(filepath);

      file.options = options;
      return file;
    }

    const extension = path.extname(filepath).slice(1);
    const id = identify(filepath, { fileExtensions });
    const ctor = this.fileDefinitionByExtension[extension];

    if (!id) throw Error(`unable to create file for: ${strong(filepath)}`);

    const file = new ctor(id, filepath, options);

    fileCache.addFile(file);

    // Warn of multiple versions
    const versions = dependencyResolverCache.getFileVersions(id);

    if (versions.length > 1) {
      const [name, version] = id.split(VERSION_DELIMITER);
      const parts = name.split('/');
      // Handle scoped
      const pkg = parts.slice(0, (parts[0].charAt(0) == '@') ? 2 : 1).join('/');

      warn(`more than one version of the ${strong(pkg)} package exists (${strong(file.relpath)})`, 2);
      print(`If ${strong(pkg)} is a project dependency, consider using the same version (${strong(version)}) to reduce duplication`, 2);
    }

    return file;
  }

  /**
   * Register file 'extensions' for 'type'
   * @param {Array} extensions
   * @param {String} type
   */
  registerFileExtensionsForType (extensions, type) {
    if (!this.fileExtensions[type]) this.fileExtensions[type] = [];
    this.fileExtensions[type].push(...extensions);
  }

  /**
   * Register target 'version' for 'type'
   * @param {String} version
   * @param {Array} plugins
   * @param {String} type
   */
  registerTargetVersionForType (version, plugins, type) {
    if (type == 'js') {
      pluginLoader.addPreset('babel', version, plugins);
    }
  }

  /**
   * Register file definitiion and 'extensions' for 'type'
   * @param {Function} define
   * @param {Array} extensions
   * @param {String} type
   */
  registerFileDefinitionAndExtensionsForType (define, extensions, type) {
    const def = define(this.fileDefinitionByExtension[type] || File, utils);

    if (extensions) {
      this.registerFileExtensionsForType(extensions, type);
      extensions.forEach((extension) => {
        this.fileDefinitionByExtension[extension] = def;
      });
    }
  }

  /**
   * Extend file definitiion for 'extensions' or 'type'
   * @param {Function} extend
   * @param {Array} extensions
   * @param {String} type
   * @returns {null}
   */
  extendFileDefinitionForExtensionsOrType (extend, extensions, type) {
    const key = extensions
      ? extensions[0]
      : this.fileExtensions[type][0];
    const def = this.fileDefinitionByExtension[key];

    if (!def) return error(`no File type available for extension for ${strong(key)}`);

    extend(def.prototype, utils);
  }

  /**
   * Destroy instance
   */
  destroy () {
    this.build.forEach((build) => {
      build.fileCache.flush();
    });
    dependencyResolverCache.clear();
  }
}

/**
 * Locate the configuration file
 * Walks the directory tree if no file/directory specified
 * @param {String} [url]
 * @returns {String}
 */
function locateConfig (url) {
  let configpath = '';

  function check (dir) {
    // Support js, json, and package.json
    const urljs = path.join(dir, DEFAULT_MANIFEST.js);
    const urljson = path.join(dir, DEFAULT_MANIFEST.json);
    const urlpkgjson = path.join(dir, DEFAULT_MANIFEST.pkgjson);
    let urlFinal;

    if (fs.existsSync(urlFinal = urljs)
      || fs.existsSync(urlFinal = urljson)
      || fs.existsSync(urlFinal = urlpkgjson)) {
        return urlFinal;
    }

    return '';
  }

  if (url) {
    configpath = path.resolve(url);
    try {
      // Try default file name if passed directory
      if (!path.extname(configpath).length || fs.statSync(configpath).isDirectory()) {
        configpath = check(configpath);
        if (!configpath) throw Error('no default found');
      }
    } catch (err) {
      throw Error(strong('buddy') + ' config not found in ' + strong(path.dirname(url)));
    }

  // No url specified
  } else {
    try {
      // Find the first instance of a DEFAULT file based on the current working directory
      configpath = hunt(process.cwd(), (resource, stat) => {
        if (stat.isFile()) {
          const basename = path.basename(resource);

          return (basename == DEFAULT_MANIFEST.js || basename == DEFAULT_MANIFEST.json || basename == DEFAULT_MANIFEST.pkgjson);
        }
      }, true);
    } catch (err) {
      if (!configpath) throw Error(strong('buddy') + ' config not found');
    }
  }

  return configpath;
}

/**
 * Parse plugins defined in 'config'
 * @param {Config} config
 * @returns {Array}
 */
function parsePlugins (config) {
  let plugins = [];

  function parse (plugins) {
    return plugins.map((plugin) => {
      if ('string' == typeof plugin) plugin = path.resolve(plugin);
      return plugin;
    });
  }

  // Handle plugin paths defined in config file
  if (config.plugins) {
    plugins.push(...parse(config.plugins));
    delete config.plugins;
  }
  // Handle plugin paths/functions defined in runtime options
  if (config.runtimeOptions.plugins) {
    plugins.push(...parse(config.runtimeOptions.plugins));
    delete config.runtimeOptions.plugins;
  }

  return plugins;
}

/**
 * Parse all npm package paths
 * @returns {Array}
 */
function parseNpmModulepaths () {
  const jsonpath = path.resolve('package.json');

  try {
    const json = require(jsonpath);

    return ['dependencies', 'devDependencies', 'optionalDependencies'].reduce((packages, type) => {
      if (type in json) {
        for (const dependency in json[type]) {
          packages.push(path.resolve('node_modules', dependency));
        }
      }
      return packages;
    }, []);
  } catch (err) {
    return [];
  }
}<|endoftext|>


<commit_before>"use strict";

var U       = require('util');
var FS      = require('fs');

// ********************************************
// Config parsing - read on startup only
// ********************************************

var Configurator = exports.Configurator = function(config_file, opts, callback_func) {
    var self = this;

    // the config file used
    self.config_file    = config_file;

    // default settings
    self.default_config = {
        no_duplicates:          true,
        stdin:                  false,
        unix_socket:            false,          // like: '/tmp/piped.socket',
        udp_port:               29029,          // like: 1337,
        udp_max_size:           512,            // max message size: http://xrl.us/bm9q4g
        file_mode:              "0600",
        encoding:               'ascii',
        debug:                  false,
        trace:                  false,
        tcp_port:               29029,          // like: 1337,
        bind_address:           '127.0.0.1',
        admin_port:             29030,
        admin_bind_address:     '127.0.0.1',
        overflow_stream:        false,          // opened here based on vars below
        overflow_file_mode:     "0600",
        overflow_file:          '/tmp/node/overflow',
        monitor_interval:       50,             // in ms
        reconnect_interval:     1000,           // in ms
        servers:                [ ],
    };

    // make a quick hash, which will be used in the main loop for option dispatch
    // tried to use argparser (via npm install argparser), but it requires you to
    // define all options up front, including their type, etc. Too cumbersome.
    // Alias the function, so we can test it;
    self._opts_to_hash = function ( opts ) {
        var map = {};
        var idx = 0;
        for( idx = 0; idx < opts.length; idx++ ) {
            var str = opts[idx];
            var kv  = str.split("=");

            // string the leading dash(es) off the key
            var key = kv[0].replace( /^-+/, "" );
            var val =  kv[1] == "false"     ? false             :
                       kv[1] === undefined  ? true              :
                       kv[1] == "true"      ? true              :
                       kv[1].match(/^\d+$/) ? parseInt( kv[1] ) : // XXX: jslint Missing radix parameter.
                       kv[1];

            map[ key ] = val;
        }
        return map;
    };

    self.opts = self._opts_to_hash( opts );

    self._process_config = function( file_config ) {
        var config = {};
        var idx;

        // XXX jslint: The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
        for( idx in self.default_config ) {

            // if specified, use the cli option, otherwise use the version
            // from the file, otherwise, default
            config[idx] = self.opts[idx]   !== undefined ? self.opts[idx]    :
                          file_config[idx] !== undefined ? file_config[idx]  :
                          self.default_config[idx];
        }

        return config;
    };

    // For testing purposes, we can pass in a NULL config and we'll not
    // try to open the file. Won't work for production as it won't start
    // any backend.
    if( config_file === null ) {
        self.config = self._process_config( {} );
        callback_func( self );

    } else {
        (function(config_file, opts) {

            // this will hold the fully integrated config that we'll return.
            var config = {};

            // process the file and create a new config object, merging
            // the default + the file + any cli options
            U.debug( "Reading config file " + config_file );

            FS.readFile( config_file, function (err, data) {

                // for some reason, we can't read the config file. Bail.
                if (err) { throw "ERROR: Could not open "+ config_file +":\n"+ err; }

                // 2 step declaration, as the variable must be IN the eval,
                // and not the result, ie file_config = eval( data ) does not
                // DTRT.
                var file_config;
                eval( 'file_config = ' + data );

                config = self._process_config( file_config );

                //U.log( U.inspect( config ) );

                // polish away the difference between a single
                // list of servers and multiple lists of servers
                // (for fanout purposes) by rewriting the single
                // list to a nested list with one entry. ie:
                // [ foo, bar ] becomes [ [ foo, bar ] ]
                if( !U.isArray( config.servers[0] ) ) {
                    config.servers = [ config.servers ];
                }

                // No servers means fatality; where would we connect to?
                if( !config.servers[0].length) {
                    throw( "No server entries detected: " + U.inspect( config.servers ) );
                }

                // No ports means fatality: where would you connect to?
                if( !config.udp_port && !config.tcp_port && !config.unix_socket ) {
                    throw( "No listening sockets detected: " + U.inspect( config ) );
                }

                // because we're about to call the callback, we have to
                // set self.config here, rather that return it from the
                // function.
                self.config = config;

                callback_func( self );

            });
        }(self.config_file, self.opts));
    }
};

<commit_msg>* add statsd variables, tidy up config<commit_after>"use strict";

var U   = require('util');
var FS  = require('fs');
var OS  = require('os');

// ********************************************
// Config parsing - read on startup only
// ********************************************

var Configurator = exports.Configurator = function(config_file, opts, callback_func) {
    var self = this;

    // the config file used
    self.config_file    = config_file;

    // default settings
    self.default_config = {
        /* statsd settings */
        statsd_port:            false,
        statsd_host:            'localhost',
        statsd_prefix:          'piped.',
        statsd_suffix:          '.' + OS.hostname().split(".")[0],
        /* listeners */
        bind_address:           '127.0.0.1',
        tcp_port:               29029,          // like: 1337,
        udp_port:               29029,          // like: 1337,
        udp_max_size:           512,            // max message size: http://xrl.us/bm9q4g
        stdin:                  false,          // listen on stdin?
        unix_socket:            false,          // like: '/tmp/piped.socket',
        /* admin server */
        admin_port:             29030,          // Can be a unix socket too
        admin_bind_address:     '127.0.0.1',
        /* run time settings */
        monitor_interval:       50,             // in ms
        reconnect_interval:     1000,           // in ms
        no_duplicates:          true,
        encoding:               'ascii',
        debug:                  false,
        trace:                  false,
        /* File settings / Overflow - currently not supported
        file_mode:              "0600",
        overflow_stream:        false,          // opened here based on vars below
        overflow_file_mode:     "0600",
        overflow_file:          '/tmp/node/overflow',
        */
        servers:                [ ],
    };

    // make a quick hash, which will be used in the main loop for option dispatch
    // tried to use argparser (via npm install argparser), but it requires you to
    // define all options up front, including their type, etc. Too cumbersome.
    // Alias the function, so we can test it;
    self._opts_to_hash = function ( opts ) {
        var map = {};
        var idx = 0;
        for( idx = 0; idx < opts.length; idx++ ) {
            var str = opts[idx];
            var kv  = str.split("=");

            // string the leading dash(es) off the key
            var key = kv[0].replace( /^-+/, "" );
            var val =  kv[1] == "false"     ? false             :
                       kv[1] === undefined  ? true              :
                       kv[1] == "true"      ? true              :
                       kv[1].match(/^\d+$/) ? parseInt( kv[1] ) : // XXX: jslint Missing radix parameter.
                       kv[1];

            map[ key ] = val;
        }
        return map;
    };

    self.opts = self._opts_to_hash( opts );

    self._process_config = function( file_config ) {
        var config = {};
        var idx;

        // XXX jslint: The body of a for in should be wrapped in an if statement to filter unwanted properties from the prototype.
        for( idx in self.default_config ) {

            // if specified, use the cli option, otherwise use the version
            // from the file, otherwise, default
            config[idx] = self.opts[idx]   !== undefined ? self.opts[idx]    :
                          file_config[idx] !== undefined ? file_config[idx]  :
                          self.default_config[idx];
        }

        return config;
    };

    // For testing purposes, we can pass in a NULL config and we'll not
    // try to open the file. Won't work for production as it won't start
    // any backend.
    if( config_file === null ) {
        self.config = self._process_config( {} );
        callback_func( self );

    } else {
        (function(config_file, opts) {

            // this will hold the fully integrated config that we'll return.
            var config = {};

            // process the file and create a new config object, merging
            // the default + the file + any cli options
            U.debug( "Reading config file " + config_file );

            FS.readFile( config_file, function (err, data) {

                // for some reason, we can't read the config file. Bail.
                if (err) { throw "ERROR: Could not open "+ config_file +":\n"+ err; }

                // 2 step declaration, as the variable must be IN the eval,
                // and not the result, ie file_config = eval( data ) does not
                // DTRT.
                var file_config;
                eval( 'file_config = ' + data );

                config = self._process_config( file_config );

                //U.log( U.inspect( config ) );

                // polish away the difference between a single
                // list of servers and multiple lists of servers
                // (for fanout purposes) by rewriting the single
                // list to a nested list with one entry. ie:
                // [ foo, bar ] becomes [ [ foo, bar ] ]
                if( !U.isArray( config.servers[0] ) ) {
                    config.servers = [ config.servers ];
                }

                // No servers means fatality; where would we connect to?
                if( !config.servers[0].length) {
                    throw( "No server entries detected: " + U.inspect( config.servers ) );
                }

                // No ports means fatality: where would you connect to?
                if( !config.udp_port && !config.tcp_port && !config.unix_socket ) {
                    throw( "No listening sockets detected: " + U.inspect( config ) );
                }

                // because we're about to call the callback, we have to
                // set self.config here, rather that return it from the
                // function.
                self.config = config;

                callback_func( self );

            });
        }(self.config_file, self.opts));
    }
};

<|endoftext|>


<commit_before>'use strict';

var pathFn = require('path');
var chalk = require('chalk');
var fs = require('hexo-fs');
var tildify = require('tildify');
var spawn = require('hexo-util/lib/spawn');
var assign = require('object-assign');

var ASSET_DIR = pathFn.join(__dirname, '../../assets');
var GIT_REPO_URL = 'https://github.com/hexojs/hexo-starter.git';

function initConsole(args) {
  args = assign({
    install: true,
    clone: true
  }, args);

  var baseDir = this.base_dir;
  var target = args._[0] ? pathFn.resolve(baseDir, args._[0]) : baseDir;
  var log = this.log;
  var promise;

  log.info('Cloning hexo-starter to', chalk.magenta(tildify(target)));

  if (args.clone) {
    promise = spawn('git', ['clone', '--recursive', GIT_REPO_URL, target], {
      stdio: 'inherit'
    });
  } else {
    promise = copyAsset(target);
  }

  return promise.catch(function() {
    log.warn('git clone failed. Copying data instead');

    return copyAsset(target);
  }).then(function() {
    return Promise.all([
      removeGitDir(target),
      removeGitModules(target)
    ]);
  }).then(function() {
    if (!args.install) return;

    log.info('Install dependencies');

    return spawn('npm', ['install', '--production'], {
      cwd: target,
      stdio: 'inherit'
    });
  }).then(function() {
    log.info('Start blogging with Hexo!');
  }).catch(function() {
    log.warn('Failed to install dependencies. Please run \'npm install\' manually!');
  });
}

function copyAsset(target) {
  return fs.copyDir(ASSET_DIR, target, {
    ignoreHidden: false
  });
}

function removeGitDir(target) {
  var gitDir = pathFn.join(target, '.git');

  return fs.stat(gitDir).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  }).then(function(stats) {
    if (stats) {
      if (stats.isDirectory()) return fs.rmdir(gitDir);
      return fs.unlink(gitDir);
    }
  }).then(function() {
    return fs.readdir(target);
  }).map(function(path) {
    return pathFn.join(target, path);
  }).filter(function(path) {
    return fs.stat(path).then(function(stats) {
      return stats.isDirectory();
    });
  }).each(removeGitDir);
}

function removeGitModules(target) {
  return fs.unlink(pathFn.join(target, '.gitmodules')).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  });
}

module.exports = initConsole;
<commit_msg>Fix Promise is not defined<commit_after>'use strict';

var pathFn = require('path');
var chalk = require('chalk');
var fs = require('hexo-fs');
var tildify = require('tildify');
var spawn = require('hexo-util/lib/spawn');
var assign = require('object-assign');
var Promise = require('bluebird');

var ASSET_DIR = pathFn.join(__dirname, '../../assets');
var GIT_REPO_URL = 'https://github.com/hexojs/hexo-starter.git';

function initConsole(args) {
  args = assign({
    install: true,
    clone: true
  }, args);

  var baseDir = this.base_dir;
  var target = args._[0] ? pathFn.resolve(baseDir, args._[0]) : baseDir;
  var log = this.log;
  var promise;

  log.info('Cloning hexo-starter to', chalk.magenta(tildify(target)));

  if (args.clone) {
    promise = spawn('git', ['clone', '--recursive', GIT_REPO_URL, target], {
      stdio: 'inherit'
    });
  } else {
    promise = copyAsset(target);
  }

  return promise.catch(function() {
    log.warn('git clone failed. Copying data instead');

    return copyAsset(target);
  }).then(function() {
    return Promise.all([
      removeGitDir(target),
      removeGitModules(target)
    ]);
  }).then(function() {
    if (!args.install) return;

    log.info('Install dependencies');

    return spawn('npm', ['install', '--production'], {
      cwd: target,
      stdio: 'inherit'
    });
  }).then(function() {
    log.info('Start blogging with Hexo!');
  }).catch(function() {
    log.warn('Failed to install dependencies. Please run \'npm install\' manually!');
  });
}

function copyAsset(target) {
  return fs.copyDir(ASSET_DIR, target, {
    ignoreHidden: false
  });
}

function removeGitDir(target) {
  var gitDir = pathFn.join(target, '.git');

  return fs.stat(gitDir).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  }).then(function(stats) {
    if (stats) {
      if (stats.isDirectory()) return fs.rmdir(gitDir);
      return fs.unlink(gitDir);
    }
  }).then(function() {
    return fs.readdir(target);
  }).map(function(path) {
    return pathFn.join(target, path);
  }).filter(function(path) {
    return fs.stat(path).then(function(stats) {
      return stats.isDirectory();
    });
  }).each(removeGitDir);
}

function removeGitModules(target) {
  return fs.unlink(pathFn.join(target, '.gitmodules')).catch(function(err) {
    if (err.cause && err.cause.code === 'ENOENT') return;
    throw err;
  });
}

module.exports = initConsole;
<|endoftext|>