/* global FileReader */

var methods = {
  arraybuffer: 'readAsArrayBuffer',
  dataurl: 'readAsDataURL',
  text: 'readAsText'
};

function readBlob (blob, type, cb) {
  var promise;

  if (typeof type !== 'string') {
    cb = type;
    type = 'arraybuffer';
  }

  if (!cb) {
    promise = new Promise(function (resolve, reject) {
      cb = function (err, result) {
        if (err) reject(err);
        else resolve(result);
      };
    });
  }

  var method = methods[type.toLowerCase()];
  var reader = new FileReader();

  reader.onload = function () {
    cb(null, reader.result);
  };

  reader.onerror = function () {
    cb(reader.error);
  };

  reader.onabort = function () {
    cb(reader.error);
  };

  if (method) {
    reader[method](blob);
  } else {
    // assume the output value is a text encoding
    reader.readAsText(blob, type);
  }

  return promise;
}

module.exports = readBlob;

// add arraybuffer, dataurl, and text methods
// as aliases to their options counterpart
Object.keys(methods).forEach(function (type) {
  readBlob[type] = function (blob, cb) {
    return readBlob(blob, type, cb);
  };
});

/* global FileReader */

var methods = {
  arraybuffer: 'readAsArrayBuffer',
  dataurl: 'readAsDataURL',
  text: 'readAsText'
};

function readBlob (blob, type, cb) {
  var promise;

  if (typeof type !== 'string') {
    cb = type;
    type = 'arraybuffer';
  }

  if (!cb) {
    promise = new Promise(function (resolve, reject) {
      cb = function (err, result) {
        if (err) reject(err);
        else resolve(result);
      };
    });
  }

  var method = methods[type.toLowerCase()];
  var reader = new FileReader();

  reader.addEventListener('loadend', function onend (e) {
    reader.removeEventListener('loadend', onend);
    if (e.error) {
      cb(e.error);
    } else {
      cb(null, reader.result);
    }
  });

  if (method) {
    reader[method](blob);
  } else {
    // assume the output value is a text encoding
    reader.readAsText(blob, type);
  }

  return promise;
}

module.exports = readBlob;

// add arraybuffer, dataurl, and text methods
// as aliases to their options counterpart
Object.keys(methods).forEach(function (type) {
  readBlob[type] = function (blob, cb) {
    return readBlob(blob, type, cb);
  };
});

Use loadend to capture error or result


'use strict';

var got = require('got');
var cheerio = require('cheerio');
var md = require('html-md');

module.exports = function(id, callback) {
  var url = 'http://www.stm.dk/_p_' + id + '.html';

  got(url, function(err, data){
    var $ = cheerio.load(data);

    var meta = $('meta[name="created"]');
    var speech = $('.maininner.maininner-page');

    speech.find('h1').remove();
    speech.find('.nedtonet').remove();

    var data = {
      source: url,
      date: meta.attr('content'),
      html: speech.html(),
      markdown: md(speech.html(), {inline: true}).replace(/\\/gi, '')
    };
    var image = speech.find('.a110051').find('img').attr('src');
    if(image){
      speech.find('.a110051').remove();
      image = 'http://www.stm.dk/' + image;
    }

    var linkElement = speech.find('a[onclick]');
    if(linkElement.length){
      var link = linkElement.attr('onclick').split('\'')[1];
      linkElement.attr('href', link);

      data.video = link;

      speech.children().last().remove();
      speech.children().last().remove();
      speech.children().last().remove();
    }

    callback(null, data)
  });
};

'use strict';

var got = require('got');
var cheerio = require('cheerio');
var md = require('html-md');

module.exports = function(id, callback) {
  var url = 'http://www.stm.dk/_p_' + id + '.html';

  got(url, function(err, data){
    var $ = cheerio.load(data);

    var meta = $('meta[name="created"]');
    var speech = $('.maininner.maininner-page');

    speech.find('h1').remove();
    speech.find('.nedtonet').remove();

    var image = speech.find('.a110051').find('img').attr('src');
    if(image){
      speech.find('.a110051').remove();
      image = 'http://www.stm.dk/' + image;
    }

    var linkElement = speech.find('a[onclick]');
    if(linkElement.length){
      var link = linkElement.attr('onclick').split('\'')[1];
      linkElement.attr('href', link);

      speech.children().last().remove();
      speech.children().last().remove();
      speech.children().last().remove();
    }

    var data = {
      source: url,
      date: meta.attr('content'),
      rawHtml: speech.html(),
      markdown: md(speech.html(), {inline: true}).replace(/\\/gi, ''),
      image: image,
      video: link
    };

    callback(null, data)
  });
};

Reorder callback data object construction


var Comments = require('./comments.js');
var config = require('./config.json');

exports.handler = function(event, context) {
  try {
    var comments = new Comments(config);
    comments.submit(event)
    .then(function(url) {
      context.succeed(url);
    })
    .catch(function(err) {
      context.fail('Server error');
    });
  } catch(err) {
    context.fail('Bad request');
  }
}

var Comments = require('./comments.js');
var config = require('./config.json');

exports.handler = function(event, context, callback) {
  try {
    var comments = new Comments(config);
    comments.submit(event)
    .then(function(url) {
      callback(null, url);
    })
    .catch(function(err) {
      callback(err);
    });
  } catch(err) {
    callback(err);
  }
}

Use callback instead of context


var fs = require('fs');

var requireDirectory = function(m, path){
  var retval = {};
  fs.readdirSync(path).forEach(function(filename){
    if(fs.statSync(path + filename).isDirectory()){
      retval[filename] = requireDirectory(m, path + filename + '/');
    }else{
      var name = filename.substring(0, filename.lastIndexOf('.'));
      retval[name] = m.require(path + filename);
    }
  });
  return retval;
};

module.exports = requireDirectory;

var fs = require('fs');
var join = require('path').join;
var resolve = require('path').resolve;

var requireDirectory = function(m, path){
  var retval = {};
  path = resolve(path);
  fs.readdirSync(path).forEach(function(filename){
    var joined = join(path, filename);
    if(fs.statSync(joined).isDirectory()){
      retval[filename] = requireDirectory(m, joined);
    }else{
      var name = filename.substring(0, filename.lastIndexOf('.'));
      retval[name] = m.require(joined);
    }
  });
  return retval;
};

module.exports = requireDirectory;

Use path.join and path.resolve to create paths


'use strict';
const os = require('os');
const path = require('path');
const alfy = require('alfy');
const dotenv = require('dotenv');
const imgur = require('imgur');
const clipboardy = require('clipboardy');

// Load config from ~/.alfred-imgur
dotenv.config({path: path.join(os.homedir(), '.alfred-imgur.conf')});

// Check for errors
if (alfy.input === 'errorNoSelection') {
	console.log(`Error: no file selected`);
} else if (alfy.input === 'errorFolder') {
	console.log(`Error: folder detected - please select a file`);
} else if (!path.extname(alfy.input).match(/(jpg|png|gif|tiff)/)) {
	console.log(`Error: no valid image file extension detected`);
} else {
	// Set client id
	imgur.setClientId(process.env.APIKEY);
	// Upload file to Imgur
	imgur.uploadFile(alfy.input).then(function (json) {
		// Copy upload URL to clipboard and write to stdout
		clipboardy.writeSync(json.data.link);
		console.log(json.data.link);
	}).catch(function (err) {
		console.error(`Error: ${err.message}`);
	});
}

'use strict';
const os = require('os');
const path = require('path');
const alfy = require('alfy');
const dotenv = require('dotenv');
const imgur = require('imgur');
const clipboardy = require('clipboardy');

// Load config from ~/.alfred-imgur
dotenv.config({path: path.join(os.homedir(), '.alfred-imgur.conf')});

// Check for errors
if (alfy.input === 'errorNoSelection') {
	console.log(`Error: no file selected`);
} else if (alfy.input === 'errorFolder') {
	console.log(`Error: folder detected - please select a file`);
// eslint-disable-next-line no-negated-condition
} else if (!path.extname(alfy.input).match(/(jpg|png|gif|tiff)/)) {
	console.log(`Error: no valid image file extension detected`);
} else {
	// Set client id
	imgur.setClientId(process.env.APIKEY);
	// Upload file to Imgur
	imgur.uploadFile(alfy.input).then(function (json) {
		// Copy upload URL to clipboard and write to stdout
		clipboardy.writeSync(json.data.link);
		console.log(json.data.link);
	}).catch(function (err) {
		console.error(`Error: ${err.message}`);
	});
}

Disable "no-negated-condition" for if condition


var port = process.env.PORT || 3000
var githubBotUserId = process.env.GITHUB_BOT_USER_ID
var giphyApiKey = process.env.GIPHY_API_KEY
var cert = fs.readFileSync('./github.pem')

var app = require('express')()
var bodyParser = require('body-parser')
app.use(bodyParser.json())

var server = require('http').Server(app)
server.listen(port)

var lollygag = require('@resmio/lollygag')

app.post('/pull_request', function (req, res) {
  if (body) {
    const {action, pull_request, label} = req.body
    switch (action) {
      case 'labeled':
        if (label.name === 'featuredeploy') {
          lollygag.makeGithubFeatureDeployComments(cert, pull_request.head.ref, 'deploying feature...', githubBotUserId, giphyApiKey)
          // RUN THE DEPLOY SCRIPT HERE
        }
        break
      case 'unlabeled':
        if (label.name === 'featuredeploy') {
          lollygag.makeGithubFeatureDeployComments(cert, pull_request.head.ref, null, githubBotUserId, giphyApiKey)
          // RUN THE DESTROY SCRIPT HERE
        }
        break
    }
  }
})

var port = process.env.PORT || 3000
var githubBotUserId = process.env.GITHUB_BOT_USER_ID
var giphyApiKey = process.env.GIPHY_API_KEY
var cert = fs.readFileSync('./github.pem')

var app = require('express')()
var bodyParser = require('body-parser')
app.use(bodyParser.json())

var server = require('http').Server(app)
server.listen(port)

var lollygag = require('@resmio/lollygag')

app.post('/pull_request', function (req, res) {
  if (body) {
    const {action, pull_request, label} = req.body
    switch (action) {
      case 'labeled':
        if (label.name === 'featuredeploy') {
          lollygag.makeGithubFeatureDeployComments(cert, pull_request.head.ref, 'deploying feature...', githubBotUserId, giphyApiKey)
          // RUN THE DEPLOY SCRIPT HERE
        }
        break
      case 'unlabeled':
        if (label.name === 'featuredeploy') {
          lollygag.makeGithubFeatureDeployComments(cert, pull_request.head.ref, null, githubBotUserId, giphyApiKey)
          // RUN THE DESTROY SCRIPT HERE
        }
        break
    }
  }
  res.send(200)
})

Return 200 so github likes it


var config = require('./config.json');

var io = require('socket.io-client');
var socket = io.connect(config.serverUrl);

 socket.on('connect', function(){
 	console.log("Connecting Device");
 	socket.emit('deviceInfo', config.device);
 	socket.on("execute",function(data){
 		console.log(data.runitem)
 		console.log("Running tests.......");
 		socket.emit("status",{runitem: data.runitem,status: 'Running'})
 	});
    socket.on('disconnect', function(){
    	console.log("Disconnected");
    });
 });

var config = require('./config.json');

var io = require('socket.io-client');
var socket = io.connect(config.serverUrl);

 socket.on('connect', function(){
 	console.log("Connecting Device");
 	socket.emit('deviceInfo', config.device);
 	socket.on("execute",function(data){
 		console.log(data.runitem)
 		console.log("Running tests.......");
 		socket.emit("status",{runitem: data.runitem,status: 'Running'})
 	});
    socket.on('disconnect', function(){
    	console.log("Disconnected");
    	process.exit(0);
    });
 });

Exit process if server disconnects


'use strict';

var got = require('got');
var cheerio = require('cheerio');
var md = require('html-md');

module.exports = function(id, callback) {
  var url = 'http://www.stm.dk/_p_' + id + '.html';

  got(url, function(err, data){
    var $ = cheerio.load(data);

    var meta = $('meta[name="created"]');
    var speech = $('.maininner.maininner-page');

    speech.find('h1').remove();
    speech.find('.nedtonet').remove();

    var linkElement = speech.find('a[onclick]');
    var link = linkElement.attr('onclick').split('\'')[1];
    linkElement.attr('href', link);

    speech.children().last().remove();
    speech.children().last().remove();
    speech.children().last().remove();

    callback(null, {
      source: url,
      video: link,
      date: meta.attr('content'),
      html: speech.html(),
      markdown: md(speech.html(), {inline: true}).replace(/\\/gi, '')
    })
  });
};

'use strict';

var got = require('got');
var cheerio = require('cheerio');
var md = require('html-md');

module.exports = function(id, callback) {
  var url = 'http://www.stm.dk/_p_' + id + '.html';

  got(url, function(err, data){
    var $ = cheerio.load(data);

    var meta = $('meta[name="created"]');
    var speech = $('.maininner.maininner-page');

    speech.find('h1').remove();
    speech.find('.nedtonet').remove();

    var data = {
      source: url,
      date: meta.attr('content'),
      html: speech.html(),
      markdown: md(speech.html(), {inline: true}).replace(/\\/gi, '')
    };

    var linkElement = speech.find('a[onclick]');
    if(linkElement.length){
      var link = linkElement.attr('onclick').split('\'')[1];
      linkElement.attr('href', link);

      data.video = link;

      speech.children().last().remove();
      speech.children().last().remove();
      speech.children().last().remove();
    }

    callback(null, data)
  });
};

Fix if no video link element in speech


/* jshint node: true */
'use strict';

const TransformFilter = require('./lib/transform-filter');
const fs = require('fs');

module.exports = {
  name: 'ember-form-for',

  included(app) {
    this._super.included.apply(this, arguments);

    var controlsDirectory = `${app.project.root}/addon/templates/components/controls`;
    var controlFileList = fs.readdirSync(controlsDirectory);

    this.options = {
      targets: [
        {
          pattern: 'components/example-component.hbs',
          transform: (content, originalPath) => {
            return buildTemplate(controlFileList);
          }
        }
      ],
      extensions: ['hbs']
    };
  },

  treeForAddonTemplates: function (tree) {
    return new TransformFilter(tree, this.options);
  }
};

function buildTemplate(controlFileList) {
  var hash = controlFileList.reduce((content, controlFileName) => {
    var controlName = controlFileName.slice(0, -4);
    var keyName = controlName.replace('-control', '');

    return `${content} ${keyName}=(component "controls/${controlName}")`;
  }, '');

  return `{{yield (hash ${hash})}}`;
}

/* jshint node: true */
'use strict';

const TransformFilter = require('./lib/transform-filter');
const fs = require('fs');

module.exports = {
  name: 'ember-form-for',

  included(app) {
    this._super.included.apply(this, arguments);

    var controlsDirectory = `${__dirname}/addon/templates/components/controls`;
    var controlFileList = fs.readdirSync(controlsDirectory);

    this.options = {
      targets: [
        {
          pattern: 'components/example-component.hbs',
          transform: (content, originalPath) => {
            return buildTemplate(controlFileList);
          }
        }
      ],
      extensions: ['hbs']
    };
  },

  treeForAddonTemplates: function (tree) {
    return new TransformFilter(tree, this.options);
  }
};

function buildTemplate(controlFileList) {
  var hash = controlFileList.reduce((content, controlFileName) => {
    var controlName = controlFileName.slice(0, -4);
    var keyName = controlName.replace('-control', '');

    return `${content} ${keyName}=(component "controls/${controlName}")`;
  }, '');

  return `{{yield (hash ${hash})}}`;
}

Use directory path in order to maintain relative path to addon templates


'use strict';

var async = require('async');
var plist = require('simple-plist');
var decompress = require('decompress-zip');
var provisioning = require('provisioning');
var entitlements = require('entitlements');

var rimraf = require('rimraf');
var tmp = require('temporary');
var glob = require("glob");

var output = new tmp.Dir();

module.exports = function (file, callback){
  var data = {};

  var unzipper = new decompress(file);
  unzipper.extract({
    path: output.path
  });

  unzipper.on('error', cleanUp);
  unzipper.on('extract', function() {
    var path = glob.sync(output.path + '/Payload/*/')[0];

    data.metadata = plist.readFileSync(path + 'Info.plist');

    var tasks = [
      async.apply(provisioning, path + 'embedded.mobileprovision')
    ];

    if(process.platform === 'darwin'){
      tasks.push(async.apply(entitlements, path));
    }

    async.parallel(tasks, function(error, results){
      if(error){
        return cleanUp(error);
      }

      data.provisioning = results[0];

      // Hard to serialize and it looks messy in output
      delete data.provisioning.DeveloperCertificates;

      // Will be undefined on non-OSX platforms
      data.entitlements = results[1];

      return cleanUp();
    });
  });

  function cleanUp(error){
    rimraf.sync(output.path);
    return callback(error, data);
  }
};

'use strict';

var async = require('async');
var plist = require('simple-plist');
var decompress = require('decompress-zip');
var provisioning = require('provisioning');
var entitlements = require('entitlements');

var rimraf = require('rimraf');
var tmp = require('temporary');
var glob = require("glob");

var output = new tmp.Dir();

module.exports = function (file, callback){
  var data = {};

  var unzipper = new decompress(file);
  unzipper.extract({
    path: output.path
  });

  unzipper.on('error', cleanUp);
  unzipper.on('extract', function() {
    var path = glob.sync(output.path + '/Payload/*/')[0];

    data.metadata = plist.readFileSync(path + 'Info.plist');

    var tasks = [
      async.apply(provisioning, path + 'embedded.mobileprovision')
    ];

    // `entitlements` relies on a OS X only CLI tool called `codesign`
    if(process.platform === 'darwin'){
      tasks.push(async.apply(entitlements, path));
    }

    async.parallel(tasks, function(error, results){
      if(error){
        return cleanUp(error);
      }

      data.provisioning = results[0];

      // Hard to serialize and it looks messy in output
      delete data.provisioning.DeveloperCertificates;

      // Will be undefined on non-OSX platforms
      data.entitlements = results[1];

      return cleanUp();
    });
  });

  function cleanUp(error){
    rimraf.sync(output.path);
    return callback(error, data);
  }
};

Add comment about running entitlements on OS X


'use strict';
var cheerio = require('cheerio');
var he = require('he');
var hl = require('highlight.js');
var highlightAuto = hl.highlightAuto;
var highlight = hl.highlight;

module.exports = function(input) {
    this.cacheable();

    var $ = cheerio.load(input);

    $('code').replaceWith(function(i, e) {
        var $e = $(e);
        var text = $e.text();

        if(text.split('\n').length < 2) {
          return $('<code>' + he.encode(text) + '</code>');
        }

        var text = $e.text();
        var klass = $e.attr('class') || '';
        var lang = klass.split('lang-').filter(id);
        lang = lang && lang[0];

        if(lang) {
            return highlight(lang, text).value;
        }

        return highlightAuto(text).value;
    });

    return $.html();
};

function id(a) {return a;}

'use strict';
var cheerio = require('cheerio');
var he = require('he');
var hl = require('highlight.js');
var highlightAuto = hl.highlightAuto;
var highlight = hl.highlight;

module.exports = function(input) {
    this.cacheable();

    var $ = cheerio.load(input);

    $('code').replaceWith(function(i, e) {
        var $e = $(e);
        var text = $e.text();

        if(text.split('\n').length < 2) {
          return $('<code>' + he.encode(text) + '</code>');
        }

        var text = $e.text();
        var klass = $e.attr('class') || '';
        var lang = klass.split('lang-').filter(id);
        lang = lang && lang[0];

        if(lang) {
            return highlight(lang, text).value;
        }

        return highlightAuto(text).value;
    });

    $('pre').addClass('hljs');

    return $.html();
};

function id(a) {return a;}

Add the 'hljs' class to the pre tag


var express = require('express');
var app = express();
var dominos = require('dominos');

app.use(require('body-parser').json());

app.get('/v1/stores', function(req, res) {
    var address = req.query.address;
    if (!address) {
        res.status(400).json({
            code: 'MISSING_ADDRESS',
            title: 'Missing Address',
            detail: 'Cannot order pizza without an address'
        });
    } else {
        console.log('returning stores for ' + address);
        dominos.store.find(
            address,
            function(storeData){
                res.status(200).json(storeData.result.Stores);
            }
        );
    }
});

var port = process.env.PORT || 5000;
app.listen(port);
console.log("Now listening on " + port);

var express = require('express');
var app = express();
var dominos = require('dominos');

app.use(require('body-parser').json());

app.get('/v1/stores', function(req, res) {
    var address = req.query.address;
    if (!address) {
        res.status(400).json({
            code: 'MISSING_ADDRESS',
            title: 'Missing Address',
            detail: 'Cannot order pizza without an address'
        });
    } else {
        console.log('returning stores for ' + address);
        dominos.store.find(address, function(storeData) {
            res.status(200).json(storeData.result.Stores);
        });
    }
});

app.get('/v1/stores/:store_id', function(req, res) {
    var store_id = req.params.store_id;
    console.log('returning info for store ' + store_id);
    dominos.store.info(store_id, function(storeData) {
        if (storeData.success === false) {
            res.status(400).json({
                code: 'INVALID_STORE',
                title: 'Invalid Store',
                detail: 'Cannot retrieve the menu for a store with id `' + store_id + '`'
            });
        } else {
            res.status(200).json(storeData);
        }
    });
});

app.get('/v1/stores/:store_id/menu', function(req, res) {
    var store_id = req.params.store_id;
    console.log('returning info for store ' + store_id);
    dominos.store.menu(store_id, function(storeData) {
        if (storeData.success === false) {
            res.status(400).json({
                code: 'INVALID_STORE',
                title: 'Invalid Store',
                detail: 'Cannot retrieve the menu for a store with id `' + store_id + '`'
            });
        } else {
            res.status(200).json(storeData);
        }
    });
});

var port = process.env.PORT || 5000;
app.listen(port);
console.log("Now listening on " + port);

Add store info and menue


function addRediSearchModule(redis) {
  redis.addCommand('ft.create');
  redis.addCommand('ft.add');
  redis.addCommand('ft.addhash');
  redis.addCommand('ft.info');
  redis.addCommand('ft.search');
  redis.addCommand('ft.explain');
  redis.addCommand('ft.del');
  redis.addCommand('ft.drop');
  redis.addCommand('ft.optimize');
  redis.addCommand('ft.suggadd');
  redis.addCommand('ft.sugget');
  redis.addCommand('ft.sugdel');
  redis.addCommand('ft.suglen');
  redis.addCommand('ft.get');
  redis.addCommand('ft.mget');
  redis.addCommand('ft.aggregate');
}
module.exports = addRediSearchModule;

function addRediSearchModule(redis) {
  redis.addCommand('ft.create');
  redis.addCommand('ft.add');
  redis.addCommand('ft.addhash');
  redis.addCommand('ft.info');
  redis.addCommand('ft.search');
  redis.addCommand('ft.explain');
  redis.addCommand('ft.del');
  redis.addCommand('ft.drop');
  redis.addCommand('ft.optimize');
  redis.addCommand('ft.sugadd');
  redis.addCommand('ft.sugget');
  redis.addCommand('ft.sugdel');
  redis.addCommand('ft.suglen');
  redis.addCommand('ft.get');
  redis.addCommand('ft.mget');
  redis.addCommand('ft.aggregate');
}
module.exports = addRediSearchModule;

Correct typo in SUGADD command


/* jshint node: true */
'use strict';

var EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
var Funnel = require('broccoli-funnel');

module.exports = {
  name: 'ember-welcome-page',

  included: function(app) {
    this._super.included(app);

    if (this._isProduction()) { return; }

    app.import('vendor/welcome-page.css');
  },

  treeForPublic: function() {
    if (this._isProduction()) { return false; }

    var tree = this._super.treeForPublic.apply(this, arguments);

    return tree;
  },

  treeForAddon: function() {
    if (this._isProduction()) { return false; }

    var tree = this._super.treeForAddon.apply(this, arguments);

    return tree;
  },

  _isProduction: function() {
    return EmberAddon.env() === 'production';
  }
};

/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-welcome-page',

  included: function(app) {
    this._super.included(app);

    if (this._isProduction()) { return; }

    app.import('vendor/welcome-page.css');
  },

  treeForPublic: function() {
    if (this._isProduction()) { return false; }

    var tree = this._super.treeForPublic.apply(this, arguments);

    return tree;
  },

  treeForAddon: function() {
    if (this._isProduction()) { return false; }

    var tree = this._super.treeForAddon.apply(this, arguments);

    return tree;
  },

  _isProduction: function() {
    return process.env.EMBER_ENV === 'production';
  }
};

Remove eager requires when unneeded.


/* @flow */

type GiftCategory =
  'Electronics' |
  'Games' |
  'Home Decoration';

type GiftWish = string | Array<GiftCategory>;

type User = {
  firstName: string,
  lastName?: string,
  giftWish?: GiftWish,
};

export type Selection = {
  giver: User,
  receiver: User,
};

const selectSecretSanta = (
  users: Array<User>,
  // TODO: Think of adding restrictions as a parameter, such as:
  // - User X cannot give to User Y
  // - User A must give to User B
  // - User N only receives, doesn't give
): Array<Selection> => {
  const givers = [...users];

  return users.map((receiver) => {
    // Possible givers only for this receiver (receiver cannot be his own giver)
    const receiverGivers = givers.filter(g => g !== receiver);

    const giver = receiverGivers[
      Math.floor(Math.random() * receiverGivers.length)
    ];

    // Take the selected giver out of the givers array
    givers.splice(givers.findIndex(g => g === giver), 1);

    return {
      giver,
      receiver,
    };
  });
};

export default selectSecretSanta;

/* @flow */

type GiftCategory =
  'Electronics' |
  'Games' |
  'Home Decoration';

type GiftWish = string | Array<GiftCategory>;

type User = {
  firstName: string,
  lastName?: string,
  giftWish?: GiftWish,
};

export type Selection = {
  giver: User,
  receiver: User,
};

// TODO: Add function to create a selection group (in the SDK?)
//
// function createSelectionGroup({
//  title = '',
//  description = '',
//  suggestions = {
//   currency: 'Euro',
//   minLimit: 10,
//   maxLimit: 50
// }}) { }
//
// ? Question: What is its relation to `selectSecretSanta`?
// How does it get called, etc.

const selectSecretSanta = (
  users: Array<User>,
  // TODO: Think of adding restrictions as a parameter, such as:
  // - User X cannot give to User Y
  // - User A must give to User B
  // - User N only receives, doesn't give
): Array<Selection> => {
  const givers = [...users];

  return users.map((receiver) => {
    // Possible givers only for this receiver (receiver cannot be his own giver)
    const receiverGivers = givers.filter(g => g !== receiver);

    const giver = receiverGivers[
      Math.floor(Math.random() * receiverGivers.length)
    ];

    // Take the selected giver out of the givers array
    givers.splice(givers.findIndex(g => g === giver), 1);

    return {
      giver,
      receiver,
    };
  });
};

export default selectSecretSanta;

Add TODO for creation of selection group


function unsplay (items, key, parentKey) {
  var nodes = items.reduce(function (nodes, item) {
    nodes[item[key]] = {item: item, children: []};
    return nodes;
  }, {});

  var lastCount, count;
  do {
    lastCount = count;
    count = 0;
    nodes = Object.keys(nodes).reduce(function (newNodes, id) {
      var node = nodes[id];
      var parentId = node.item[parentKey];
      if (parentId in nodes) nodes[parentId].children.push(node);
      else {
        newNodes[id] = node;
        count++;
      }
      return newNodes;
    }, {});
  } while (lastCount !== count);
  return Object.keys(nodes).map(function (id) { return nodes[id]; });
}

module.exports = unsplay;

function unsplay (items, key, parentKey) {
  var nodes = items.reduce(function (nodes, item) {
    nodes[item[key]] = {item: item, children: []};
    return nodes;
  }, {});

  do {
    var reparented = false;
    nodes = Object.keys(nodes).reduce(function (newNodes, id) {
      var node = nodes[id];
      var parentId = node.item[parentKey];
      if (parentId in nodes) {
        nodes[parentId].children.push(node);
        reparented = true;
      }
      else newNodes[id] = node;
      return newNodes;
    }, {});
  } while (reparented);
  return Object.keys(nodes).map(function (id) { return nodes[id]; });
}

module.exports = unsplay;

Replace count check with more correct reparent check


/**
 * Remove initial and final spaces and tabs at the line breaks in `value`.
 * Does not trim initial and final spaces and tabs of the value itself.
 *
 * @param {string} value
 *   Value to trim.
 * @returns {string}
 *   Trimmed value.
 */
export function trimLines(value) {
  return String(value).replace(/[ \t]*(\r?\n|\r)[ \t]*/g, '$1')
}

/**
 * Remove initial and final spaces and tabs at the line breaks in `value`.
 * Does not trim initial and final spaces and tabs of the value itself.
 *
 * @param {string} value
 *   Value to trim.
 * @returns {string}
 *   Trimmed value.
 */
export function trimLines(value) {
  const source = String(value)
  const search = /\r?\n|\r/g
  let match = search.exec(source)
  let last = 0
  /** @type {Array<string>} */
  const lines = []

  while (match) {
    lines.push(
      trimLine(source.slice(last, match.index), last === 0, false),
      match[0]
    )

    last = match.index + match[0].length
    match = search.exec(source)
  }

  lines.push(trimLine(source.slice(last), last === 0, true))

  return lines.join('')
}

/**
 * @param {string} value
 * @param {boolean} start
 * @param {boolean} end
 * @returns {string}
 */
function trimLine(value, start, end) {
  if (!start) {
    value = value.replace(/^[ \t]+/, '')
  }

  if (!end) {
    value = value.replace(/[ \t]+$/, '')
  }

  return value
}

Fix to much improve performance


import moment from 'moment';

let state = window.state = {
  currentTime: moment('2013-01-12 16:30'),
  alarmRinging: true,
  bathroomTowel: "clean",
  garbageOutside: false,
  garageDoorOpen: false,
  inventory: [],
  wearing: "pajamas",
  luck: 10,
  confidence: 10,
  car: {
    running: false,
    atWork: false
  },
  wet: false,
  showered: false,
  wetUniform: false,
  wetPajamas: false,
  nastyBreath: true,
  unreadTexts: 3,
  fridgeInventory: [
    "beer",
    "milk",
  ],
  cupboardsInventory: [
    "granolaBar",
  ]
};

export default state;

import moment from 'moment';

let state = window.state = {
  currentTime: moment('2013-01-12 16:30'),
  alarmRinging: true,
  bathroomTowel: "clean",
  garbageOutside: false,
  garageDoorOpen: false,
  inventory: [],
  wearing: "pajamas",
  luck: 10,
  confidence: 10,
  car: {
    running: false,
    atWork: false
  },
  wet: false,
  showered: false,
  wetUniform: false,
  wetPajamas: false,
  nastyBreath: true,
  unreadTexts: 3,
  fridgeInventory: [
    "beer",
    "milk",
  ],
  cupboardsInventory: [
    "granolaBar",
  ]
};

export function demerits() {
  let demerits = [];

  function a(string) { demerits.push(string); }

  if (state.nastyBreath) {
    a("Your breath reeks. Try brushing your teeth next time.");
  }

  if (state.alarmRinging) {
    a("You left your alarm ringing! Your landlord says this is the last straw.");
  }

  if (!state.garbageOutside) {
    a("You didn't take out the trash. A small flock of seagulls has moved into your kitchen.");
  }

  if (state.wetUniform) {
    a("Your work uniform is wet. Your boss wasn't too pleased with that");
  }

  if (!state.showered) {
    a("You didn't shower before going to work.");
  }

  if (state.car.running) {
    a("You left your car running. It was subsequently stolen. Good luck getting home!");
  }

  return demerits;
}

export default state;

Add demerits() function for calculating report card


var Cell = require('./Cell');

function PlayerCell() {
    Cell.apply(this, Array.prototype.slice.call(arguments));
    this.cellType = 0;
    this._canRemerge = false;
}

module.exports = PlayerCell;
PlayerCell.prototype = new Cell();

// Main Functions

PlayerCell.prototype.canEat = function (cell) {
    return true; // player cell can eat anyone
};

PlayerCell.prototype.getSpeed = function (dist) {
    var speed = 2.2 * Math.pow(this._size, -0.439);
    speed *= 40 * this.gameServer.config.playerSpeed;
    return Math.min(dist, speed) / dist;
};

PlayerCell.prototype.onAdd = function (gameServer) {
    // Add to player nodes list
    this.gameServer.nodesPlayer.push(this);
};

PlayerCell.prototype.onRemove = function (gameServer) {
    // Remove from player cell list
    var index = this.owner.cells.indexOf(this);
    if (index != -1) this.owner.cells.splice(index, 1);

    index = this.gameServer.nodesPlayer.indexOf(this);
    if (index != -1) this.gameServer.nodesPlayer.splice(index, 1);
};

var Cell = require('./Cell');

function PlayerCell() {
    Cell.apply(this, Array.prototype.slice.call(arguments));
    this.cellType = 0;
    this._canRemerge = false;
}

module.exports = PlayerCell;
PlayerCell.prototype = new Cell();

// Main Functions

PlayerCell.prototype.canEat = function (cell) {
    return true; // player cell can eat anyone
};

PlayerCell.prototype.getSpeed = function (dist) {
    var speed = 2.2 * Math.pow(this._size, -0.439);
    speed *= 40 * this.gameServer.config.playerSpeed;
    return Math.min(dist, speed) / dist;
};

PlayerCell.prototype.onAdd = function (gameServer) {
    // Add to player nodes list
    this.gameServer.nodesPlayer.unshift(this);
};

PlayerCell.prototype.onRemove = function (gameServer) {
    // Remove from player cell list
    var index = this.owner.cells.indexOf(this);
    if (index != -1) this.owner.cells.splice(index, 1);

    index = this.gameServer.nodesPlayer.indexOf(this);
    if (index != -1) this.gameServer.nodesPlayer.splice(index, 1);
};

Fix cells switching order on doublesplit


import React from 'react';
import {connect} from 'react-redux';
import socksend from './websocket';

export default connect()(class Property extends React.Component {
	update(e) {
		e.preventDefault();
		socksend("bid", {name: this.props.name, value: this.refs.bid.value});
	}

	render() {
		let minbid = this.props.bidder ? ((this.props.highbid|0) + 10) : (this.props.facevalue|0);
		if (this.refs.bid && (this.refs.bid.value|0) < minbid) this.refs.bid.value = minbid;
		return <form onSubmit={this.update.bind(this)}>

{this.props.name}

				Current high bid:

				{this.props.bidder || "(nobody)"} {this.props.highbid || this.props.facevalue}

				<input type="number" ref="bid" defaultValue={minbid} />
				<input type="submit" value="Bid" />

		</form>;
	}
})

import React from 'react';
import {connect} from 'react-redux';
import socksend from './websocket';

export default connect()(class Property extends React.Component {
	update(e) {
		e.preventDefault();
		socksend("bid", {name: this.props.name, value: this.refs.bid.value});
	}

	render() {
		let minbid = this.props.bidder ? ((this.props.highbid|0) + 10) : (this.props.facevalue|0);
		//If you've been outbid, blank the field.
		if (this.refs.bid && (this.refs.bid.value|0) < minbid) this.refs.bid.value = "";
		return <form onSubmit={this.update.bind(this)}>

{this.props.name}

				Current high bid:

				{this.props.bidder || "(nobody)"} {this.props.highbid || this.props.facevalue}

				<input type="number" ref="bid" defaultValue={this.props.bidder ? "" : this.props.facevalue} />
				<input type="submit" value="Bid" />

{this.props.bidder ? <input type="submit" value={"Bid " + minbid} /> : "\xa0"}

		</form>;
	}
})

Tidy up the bidding when you're outbid


'use strict';

const koa = require('koa');
const passport = require('./config/passport');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config');
const compiler = webpack(webpackConfig);
const logger = require('koa-logger');
const serve = require('koa-static');
const routes = require('./config/routes');
const bodyParser = require('koa-bodyparser');
const session = require('koa-generic-session');

const app = koa();

app.use(logger());
app.use(bodyParser());
app.keys = require('./config/salt');
app.use(session());

passport(app);

app.use(require('koa-webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
  noInfo: true
}));

app.use(require('koa-webpack-hot-middleware')(compiler, {
  path: '/__webpack_hmr',
  noInfo: true,
  heartbeat: 10 * 1000
}));

routes(app);

app.use(serve('./public'));

app.listen(3000);

module.exports = app;

'use strict';

const koa = require('koa');
const passport = require('./config/passport');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config');
const compiler = webpack(webpackConfig);
const logger = require('koa-logger');
const serve = require('koa-static');
const routes = require('./config/routes');
const bodyParser = require('koa-bodyparser');
const session = require('koa-generic-session');
const json = require('koa-json');

const app = koa();

app.use(logger());
app.use(bodyParser());
app.keys = require('./config/salt');
app.use(session());
app.use(json());

passport(app);
require('koa-qs')(app);

app.use(require('koa-webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
  noInfo: true
}));

app.use(require('koa-webpack-hot-middleware')(compiler, {
  path: '/__webpack_hmr',
  noInfo: true,
  heartbeat: 10 * 1000
}));

app.use(serve('./public'));

routes(app);

app.listen(3000);

module.exports = app;

Add koa-json module and koa-qs module


// setup transform definition aliases
import {definition} from 'vega-dataflow';
definition('Sort', definition('Collect'));
definition('Formula', definition('Apply'));

export {default as parse} from './src/parse';

export {default as selector} from './src/parsers/event-selector';
export {default as signal} from './src/parsers/signal';
export {default as signalUpdates} from './src/parsers/signal-updates';
export {default as stream} from './src/parsers/stream';

export {
  MarkRole,
  FrameRole,
  ScopeRole,
  AxisRole,
  AxisDomainRole,
  AxisGridRole,
  AxisLabelRole,
  AxisTickRole,
  AxisTitleRole,
  LegendRole,
  LegendEntryRole,
  LegendLabelRole,
  LegendSymbolRole,
  LegendTitleRole
} from './src/parsers/marks/roles';
export {marktypes, isMarkType} from './src/parsers/marks/marktypes';

export {default as Scope} from './src/Scope';
export {default as DataScope} from './src/DataScope';

// setup transform definition aliases
import {definition} from 'vega-dataflow';
definition('Formula', definition('Apply'));

export {default as parse} from './src/parse';

export {default as selector} from './src/parsers/event-selector';
export {default as signal} from './src/parsers/signal';
export {default as signalUpdates} from './src/parsers/signal-updates';
export {default as stream} from './src/parsers/stream';

export {
  MarkRole,
  FrameRole,
  ScopeRole,
  AxisRole,
  AxisDomainRole,
  AxisGridRole,
  AxisLabelRole,
  AxisTickRole,
  AxisTitleRole,
  LegendRole,
  LegendEntryRole,
  LegendLabelRole,
  LegendSymbolRole,
  LegendTitleRole
} from './src/parsers/marks/roles';
export {marktypes, isMarkType} from './src/parsers/marks/marktypes';

export {default as Scope} from './src/Scope';
export {default as DataScope} from './src/DataScope';

Drop Sort alias for Collect.


var exec = require('child_process').exec

function _command (cmd, cb) {
  exec(cmd, { cwd: __dirname }, function (err, stdout, stderr) {
    cb(stdout.split('\n').join(''))
  })
}

module.exports = {
    short : function (cb) {
      _command('git rev-parse --short HEAD', cb)
    }
  , long : function (cb) {
      _command('git rev-parse HEAD', cb)
    }
  , branch : function (cb) {
      _command('git rev-parse --abbrev-ref HEAD', cb)
    }
  , tag : function (cb) {
      _command('git describe --always --tag --abbrev=0', cb)
    }
  , log : function (cb) {
      _command('git log --no-color --pretty=format:\'[ "%H", "%s", "%cr", "%an" ],\' --abbrev-commit', function (str) {
        str = str.substr(0, str.length-1)
        cb(JSON.parse('[' + str + ']'))
      })
    }
}

var exec = require('child_process').exec

function _command (cmd, dir, cb) {
  if (typeof dir === 'function') cb = dir, dir = __dirname
  exec(cmd, { cwd: dir }, function (err, stdout, stderr) {
    cb(stdout.split('\n').join(''))
  })
}

module.exports = {
    short : function (cb) {
      _command('git rev-parse --short HEAD', cb)
    }
  , long : function (cb) {
      _command('git rev-parse HEAD', cb)
    }
  , branch : function (cb) {
      _command('git rev-parse --abbrev-ref HEAD', cb)
    }
  , tag : function (cb) {
      _command('git describe --always --tag --abbrev=0', cb)
    }
  , log : function (cb) {
      _command('git log --no-color --pretty=format:\'[ "%H", "%s", "%cr", "%an" ],\' --abbrev-commit', function (str) {
        str = str.substr(0, str.length-1)
        cb(JSON.parse('[' + str + ']'))
      })
    }
}

Allow passing in a custom directory.


var mustache = require('mustache')
mustache.tags = '% %'

function render (template, view) {
  var KEYWORD_REGEX = /%(asset_name_linked|asset_short_name_linked)\b/g

  var _template = template.replace(KEYWORD_REGEX, '%&$1')
  var _view = {
    asset_name_linked: function nameLinked () {
      if (view.name && view.href) {
        return '' + view.name + ''
      }
    },
    asset_short_name_linked: function shortNameLinked () {
      if (view.short_name && view.href) {
        return '' + view.short_name + ''
      }
    }
  }

  var keys = Object.keys(view)

  for (var i = 0, key; i < keys.length; i++) {
    key = keys[i]
    _view['asset_' + key] = view[key]
  }

  return mustache.render(_template, _view)
}

exports.render = render

var mustache = require('mustache')
var defaultWriter = new mustache.Writer()

mustache.tags = '% %'

function unescapeKeywords (template) {
  var KEYWORD_REGEX = /%(asset_name_linked|asset_short_name_linked)\b/g
  return template.replace(KEYWORD_REGEX, '%&$1')
}

exports.clearCache = function clearCache () {
  return defaultWriter.clearCache()
}

exports.parse = function parse (template, tags) {
  return defaultWriter.parse(unescapeKeywords(template), tags)
}

exports.render = function render (template, view, partials) {
  var _view = {
    asset_name_linked: function nameLinked () {
      if (view.name && view.href) {
        return '' + view.name + ''
      }
    },
    asset_short_name_linked: function shortNameLinked () {
      if (view.short_name && view.href) {
        return '' + view.short_name + ''
      }
    }
  }

  var keys = Object.keys(view)

  for (var i = 0, key; i < keys.length; i++) {
    key = keys[i]
    _view['asset_' + key] = view[key]
  }

  return defaultWriter.render(unescapeKeywords(template), _view, partials)
}

Update API to expose: render, parse, and clearCache methods


(function ($) {
    var slice = Array.prototype.slice;
    $.defer = function (func, delay) {
        var args = slice.call(arguments, 2),
            cancel = function (reject /* = true */) {
                clearTimeout(timerId);
                if ((!arguments.length || reject) && deferred.state() === "pending") {
                    deferred.reject(null, promise, args);
                }
            },
            deferred = $.Deferred(),
            timerId = setTimeout(function () {
                deferred.notify(promise, args);
                // if they cancel inside the progress call-back...
                if (deferred.state() === "rejected") {
                    return;
                }
                try {
                    var result = func.apply(this, args);
                    deferred.resolve(result, promise, args);
                } catch (e) {
                    deferred.reject(e, promise, args);
                }
            }, delay),
            promise = deferred.promise();

        promise.cancel = cancel;
        return promise;
    };
})(jQuery);

(function ($) {
    var slice = Array.prototype.slice;
    $.defer = function (func, delay) {
        var args = slice.call(arguments, 2),
            isCancelled = false,
            cancel = function (reject /* = true */) {
                clearTimeout(timerId);
                isCancelled = true;
                if ((!arguments.length || reject) && deferred.state() === "pending") {
                    deferred.reject(null, promise, args);
                }
            },
            deferred = $.Deferred(),
            timerId = setTimeout(function () {
                deferred.notify(promise, args);
                if (isCancelled) {
                    return;
                }
                try {
                    var result = func.apply(this, args);
                    deferred.resolve(result, promise, args);
                } catch (e) {
                    deferred.reject(e, promise, args);
                }
            }, delay),
            promise = deferred.promise();

        promise.cancel = cancel;
        return promise;
    };
})(jQuery);

Fix the initial cancel bug


module.exports = function(handler) {
  if (!(handler instanceof Function || handler instanceof RegExp))
    throw new Error('Unsupported param handler. Either function or Regexp expected')

  return function(req, res, next, val, name) {

    if (handler instanceof Function) {
      var newVal = handler(val)
      if (!newVal)
        return next('route'); // bypass current route
      req.params[name] = newVal

    } else if (handler instanceof RegExp) {
      if (!handler.test(val))
        return next('route') // bypass current route
      req.params[name] = val

    } else {
      throw new Error('Should not reach here')
    }

    return next();
  }
}

module.exports = function(handler) {
  if (!(handler instanceof Function || handler instanceof RegExp))
    throw new Error('Unsupported param handler. Either function or Regexp expected')

  return function(req, res, next, val, name) {
    val = req.params[name]

    if (handler instanceof Function) {
      var newVal = handler(val)
      if (!newVal)
        return next('route'); // bypass current route
      req.params[name] = newVal

    } else if (handler instanceof RegExp) {
      if (!handler.test(val))
        return next('route') // bypass current route

    } else {
      throw new Error('Should not reach here')
    }

    return next();
  }
}

Use value from req.params rather than from fn arg


module.exports = Ready

function Ready() {
    var listeners = []
    var args

    onready.emit = onready

    return onready

    function onready(callback) {
        if (typeof callback !== "function" && listeners) {
            args = arguments
            var list = listeners
            listeners = undefined
            list.forEach(call)
            return;
        } else if (!listeners) {
            return callback && call(callback)
        }

        listeners.push(callback)
    }

    function call(cb) {
        cb.apply(null, args)
    }
}

module.exports = Ready

function Ready() {
    var ready = false
    var listeners = []
    var args

    onready.emit = onready

    return onready

    function onready(callback) {
        if (typeof callback !== "function" && !ready) {
            ready = true
            args = arguments
            listeners.forEach(call)
            return (listeners = [])
        } else if (ready) {
            return callback && call(callback)
        }

        listeners.push(callback)
    }

    function call(cb) {
        cb.apply(null, args)
    }
}

Revert "refactor to remove ready variable"


module.exports = function shallowEqual(objA, objB, compare, compareContext) {

    let ret = compare ? compare.call(compareContext, objA, objB) : void 0;

    if(ret !== void 0) {
        return !!ret;
    }

    if(objA === objB) {
        return true;
    }

    if(typeof objA !== 'object' || !objA ||
       typeof objB !== 'object' || !objB) {
        return false;
    }

    const keysA = Object.keys(objA);
    const keysB = Object.keys(objB);

    if(keysA.length !== keysB.length) {
        return false;
    }

    const bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);

    // Test for A's keys different from B.
    for(let idx = 0; idx < keysA.length; idx++) {

        const key = keysA[idx];

        if(!bHasOwnProperty(key)) {
            return false;
        }

        const valueA = objA[key];
        const valueB = objB[key];

        ret = compare ? compare.call(compareContext, valueA, valueB, key) : void 0;

        if(ret === false ||
           ret === void 0 && valueA !== valueB) {
            return false;
        }

    }

    return true;

};

module.exports = function shallowEqual(objA, objB, compare, compareContext) {

    var ret = compare ? compare.call(compareContext, objA, objB) : void 0;

    if(ret !== void 0) {
        return !!ret;
    }

    if(objA === objB) {
        return true;
    }

    if(typeof objA !== 'object' || !objA ||
       typeof objB !== 'object' || !objB) {
        return false;
    }

    var keysA = Object.keys(objA);
    var keysB = Object.keys(objB);

    if(keysA.length !== keysB.length) {
        return false;
    }

    var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);

    // Test for A's keys different from B.
    for(var idx = 0; idx < keysA.length; idx++) {

        var key = keysA[idx];

        if(!bHasOwnProperty(key)) {
            return false;
        }

        var valueA = objA[key];
        var valueB = objB[key];

        ret = compare ? compare.call(compareContext, valueA, valueB, key) : void 0;

        if(ret === false ||
           ret === void 0 && valueA !== valueB) {
            return false;
        }

    }

    return true;

};

Use var in favour of let and const.


'use strict';

module.exports = {
  name: require('./package.json').name,
  version: require('./package.json').version,
  register: function (plugin, options, next) {

    plugin.ext('onPreResponse', function (request, reply) {
      var Hapi = plugin.hapi,
      response = request.response;

      if (response.variety === 'plain' && typeof response.source.then === 'function') {
        return response.source.then(function (res) {
          return reply(res);
        }, function (err) {
          if (!err.isBoom) {
            err = Hapi.error.internal(err.message, err);
          }
          return reply(err);
        });
      }

      reply();
    });

    next();
  }
};

'use strict';

module.exports = {
  name: require('./package.json').name,
  version: require('./package.json').version,
  register: function (plugin, options, next) {

    plugin.ext('onPreResponse', function (request, next) {
      var Hapi = plugin.hapi,
      response = request.response;

      if (response.variety === 'plain' && typeof response.source.then === 'function') {
        return response.source.then(function (res) {
          return next(res);
        }, function (err) {
          if (!err.isBoom) {
            err = Hapi.error.internal(err.message, err);
          }
          return next(err);
        });
      }

      next();
    });

    next();
  }
};

Switch request for next -- clearer terminology


var chai = require('chai');
var should = chai.should();

describe('Number', function(){
  it('should return number');
  it('should be between 1 and 3999');
  it('should not be null');
  it('should not return an error');
});

describe('Roman Numeral', function(){
  it('should return roman numeral');
  it('should be between 1 and 3999');
  it('should not be null');
  it('should not return an error');
});

var chai = require('chai');
var should = chai.should();
var expect = chai.expect;

describe('Number', function(){
  it('should return number', function()
  {
    var number = RomanNumber(20);
    expect(number.toInt()).to.equal(20);
  });
  it('should be between 1 and 3999');
  it('should not be null');
  it('should not return an error');
});

describe('Roman Numeral', function(){
  it('should return roman numeral');
  it('should be between 1 and 3999');
  it('should not be null');
  it('should not return an error');
});

function RomanNumber(pNumber)
{

	if(pNumber !== undefined)
	{
	this.number = pNumber;
	}
	else
	{
		throw new Error("Please enter number");
	}

	this.toInt = function()
	{
		if (Number.isInteger(this.number)) {
		return this.number;
		}
		else
		{
			console.log("This is a string");
			return this.number;
		}
	};

	this.toString = function()
	{
		if (Number.isInteger(this.number)) {
		return this.number;
		}

	};
}

Create basic roman numeral class


module.exports = {
  parser: 'babel-eslint',
  env: {
    browser: true,
    node: true,
    es6: true
  },
  ecmaFeatures: {
    modules: true
  },

  globals: {},
  rules: {}
};

module.exports = {
  parser: 'babel-eslint',
  env: {
    browser: true,
    node: true,
    es6: true
  },
  ecmaFeatures: {
    modules: true
  },

  globals: {},
  rules: {
    //
    // Possible Errors
    //
    // disallow or enforce trailing commas
    'comma-dangle': 1,
    // disallow assignment in conditional expressions
    'no-cond-assign': 1,
    // disallow use of console in the node environment
    'no-console': 1,
    // disallow use of constant expressions in conditions
    'no-constant-condition': 1,
    // disallow control characters in regular expressions
    'no-control-regex': 1,
    // disallow use of debugger
    'no-debugger': 1,
    // disallow duplicate arguments in functions
    'no-dupe-args': 1,
    // disallow duplicate keys when creating object literals
    'no-dupe-keys': 1,
    // disallow a duplicate case label.
    'no-duplicate-case': 1,
    // disallow the use of empty character classes in regular expressions
    'no-empty-character-class': 1,
    // disallow empty statements
    'no-empty': 1,
    // disallow assigning to the exception in a catch block
    'no-ex-assign': 1,
    // disallow double-negation boolean casts in a boolean context
    'no-extra-boolean-cast': 1,
    // disallow unnecessary parentheses
    'no-extra-parens': 1,
    // disallow unnecessary semicolons
    'no-extra-semi': 1,
    // disallow overwriting functions written as function declarations
    'no-func-assign': 1,
    // disallow function or variable declarations in nested blocks
    'no-inner-declarations': [1, 'both'],
    // disallow invalid regular expression strings in the RegExp constructor
    'no-invalid-regexp': 1,
    // disallow irregular whitespace outside of strings and comments
    'no-irregular-whitespace': 1,
    // disallow negation of the left operand of an in expression
    'no-negated-in-lhs': 1,
    // disallow the use of object properties of the global object (Math and JSON) as functions
    'no-obj-calls': 1,
    // disallow multiple spaces in a regular expression literal
    'no-regex-spaces': 1,
    // disallow sparse arrays
    'no-sparse-arrays': 1,
    // Avoid code that looks like two expressions but is actually one
    'no-unexpected-multiline': 1,
    // disallow unreachable statements after a return, throw, continue, or break statement
    'no-unreachable': 1,
    // disallow comparisons with the value NaN
    'use-isnan': 1,
    // Ensure JSDoc comments are valid
    'valid-jsdoc': 1,
    // Ensure that the results of typeof are compared against a valid string
    'valid-typeof': 1,
  }
};

Add rules for possible errors


#!/usr/bin/env node
const inquirer = require('inquirer')
const Listr = require('listr')

const steps = [{
  type: 'input',
  name: 'userName',
  message: 'Whats your name?'
}]

const tasks = [{
  title: 'Preparing',
  task: (context, task) => new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 1000)
  })
},{
  title: 'Ask for name',
  task: (context, task) => new Promise((resolve, reject) => {
    task.output = 'Starting'

    setTimeout(() => {
      task.output = 'Calculating'
      resolve()
    }, 500)

    // setTimeout(() => {
    // }, 2000)
  })
}]

// Test change for release

const listrObject = new Listr(tasks)

listrObject.run().then(res => {
  inquirer
    .prompt(steps).then(output => {
    console.log(
      'Hello',
      output.userName
    )
  }).catch(err => console.log(err))
})

#!/usr/bin/env node
const inquirer = require('inquirer')
const Listr = require('listr')

const steps = [{
  type: 'input',
  name: 'userName',
  message: 'Whats your name?'
}]

const tasks = [{
  title: 'Preparing',
  task: (context, task) => new Promise((resolve, reject) => {
    setTimeout(() => resolve(), 1000)
  })
},{
  title: 'Ask for name',
  task: (context, task) => new Promise((resolve, reject) => {
    task.output = 'Starting'

    setTimeout(() => {
      task.output = 'Calculating'
      resolve()
    }, 500)

    // setTimeout(() => {
    // }, 2000)
  })
}]

// Test change for release
// Test change for release

const listrObject = new Listr(tasks)

listrObject.run().then(res => {
  inquirer
    .prompt(steps).then(output => {
    console.log(
      'Hello',
      output.userName
    )
  }).catch(err => console.log(err))
})

Add test change for release


var DtsCreator = require('typed-css-modules');
var loaderUtils = require('loader-utils');

module.exports = function(source, map) {
  this.cacheable && this.cacheable();
  this.addDependency(this.resourcePath);
  var callback = this.async();

  // Pass on query parameters as an options object to the DtsCreator. This lets
  // you change the default options of the DtsCreator and e.g. use a different
  // output folder.
  var queryOptions = loaderUtils.getOptions(this);
  var options;
  if (queryOptions) {
    options = Object.assign({}, queryOptions);
  }

  var creator = new DtsCreator(options);

  // creator.create(..., source) tells the module to operate on the
  // source variable. Check API for more details.
  creator.create(this.resourcePath, source).then(content => {
    // Emit the created content as well
    this.emitFile(content.outputFilePath, content.contents || [''], map);
    content.writeFile().then(_ => {
      callback(null, source, map);
    });
  });
};

var path = require('path');
var DtsCreator = require('typed-css-modules');
var loaderUtils = require('loader-utils');

module.exports = function(source, map) {
  this.cacheable && this.cacheable();
  this.addDependency(this.resourcePath);
  var callback = this.async();

  // Pass on query parameters as an options object to the DtsCreator. This lets
  // you change the default options of the DtsCreator and e.g. use a different
  // output folder.
  var queryOptions = loaderUtils.getOptions(this);
  var options;
  if (queryOptions) {
    options = Object.assign({}, queryOptions);
  }

  var creator = new DtsCreator(options);

  // creator.create(..., source) tells the module to operate on the
  // source variable. Check API for more details.
  creator.create(this.resourcePath, source).then(content => {
    // Emit the created content as well
    this.emitFile(path.relative(this.options.context, content.outputFilePath), content.contents || [''], map);
    content.writeFile().then(_ => {
      callback(null, source, map);
    });
  });
};

Use relative paths for emitted files


#!/usr/bin/env node
var colors = require('colors');
var ghlint = require('./index');

function printResults(repo, results) {
  console.log(repo + ':');
  results.forEach(function (result) {
    var color = result.result ? 'green' : 'red';
    var mark = result.result ? '✓' : '✖';
    console.log('  %s %s'[color], mark, result.message);
  });
}

var repo = process.argv[2];
if (repo) {
  ghlint.lintAll(repo, function (err, linters) {
    if (err) {
      console.error(err);
    } else {
      printResults(repo, linters);
    }
  });
} else {
  console.error('Usage: ghlint <repo>');
}

#!/usr/bin/env node
var colors = require('colors');
var ghlint = require('./index');
var util = require('util');

function printResults(repo, results) {
  console.log(repo + ':');
  results.forEach(function (result) {
    var mark = result.result ? '✓' : '✖';
    var output = util.format('  %s %s', mark, result.message);
    if (colors.enabled) {
      output = output[result.result ? 'green' : 'red'];
    }
    console.log(output);
  });
}

// Remove --no-color from the args if it is there.
process.argv = process.argv.filter(function (arg) {
  return arg !== '--no-color';
});

var repo = process.argv[2];
if (repo) {
  ghlint.lintAll(repo, function (err, linters) {
    if (err) {
      console.error(err);
    } else {
      printResults(repo, linters);
    }
  });
} else {
  console.error('Usage: ghlint <repo>');
}

Add support for the --no-color option


#!/usr/bin/env node
var tool = require('./')
var through = require('through2')
var split = require('split')
var minimist = require('minimist')

var argv = minimist(process.argv.slice(2))
var method = argv._[0]
var params = argv._.slice(1)

var operation = tool[method].apply(this, params)

process.stdin.setEncoding('utf8');

if (!process.stdin.isTTY) {
  process.stdin
  .pipe(split())
  .pipe(JSONparse())
  .pipe(operation)
  .on('data', function(data) {
    console.log(JSON.stringify(data))
  })
  .on('error', console.log)
}

function JSONparse() {
  var stream = through.obj(transform)
  return stream
  function transform(obj, enc, next) {
    try { obj = JSON.parse(obj) }
    catch(e) {}
    if (obj !== '') { this.push(obj) }
    next()
  }
}

#!/usr/bin/env node
var tool = require('./')
var through = require('through2')
var split = require('split')
var minimist = require('minimist')

var argv = minimist(process.argv.slice(2))
var method = argv._[0]
var params = argv._.slice(1)

var operation = tool[method].apply(this, params)

process.stdin.setEncoding('utf8');

if (!process.stdin.isTTY) {
  process.stdin
  .pipe(split())
  .pipe(JSONparse())
  .pipe(operation)
  .on('data', function(data) {
    if (typeof data === 'object') {
      data = JSON.stringify(data)
    }
    console.log(data)
  })
  .on('error', console.log)
}

function JSONparse() {
  var stream = through.obj(transform)
  return stream
  function transform(obj, enc, next) {
    try { obj = JSON.parse(obj) }
    catch(e) {}
    if (obj !== '') { this.push(obj) }
    next()
  }
}

Fix only JSON stringify objects, not strings


module.exports = function (string, preserve) {
  if (!preserve) {
    string = string.toLowerCase();
  }
  return string.charAt(0).toUpperCase() + string.substring(1);
}

module.exports.words = function (string, preserve) {
  if (!preserve) {
    string = string.toLowerCase();
  }
  return string.replace(/(?!^[0-9])(^|[^a-zA-Z\u00C0-\u017F\u0400-\u04FF'])([a-zA-Z\u00C0-\u017F\u0400-\u04FF])/g, function (m) {
    return m.toUpperCase()
  })
}

function capitalize (string, opts) {
  opts = normalizeOptions(opts)
  if (!opts.preserve) {
    string = string.toLowerCase();
  }
  return string.charAt(0).toUpperCase() + string.substring(1);
}

capitalize.words = function (string, opts = {}) {
  opts = normalizeOptions(opts)
  if (!opts.preserve) {
    string = string.toLowerCase();
  }
  return string.replace(/(?!^[0-9])(^|[^a-zA-Z\u00C0-\u017F\u0400-\u04FF'])([a-zA-Z\u00C0-\u017F\u0400-\u04FF])/g, function (m) {
    return m.toUpperCase()
  })
}

function normalizeOptions(opts) {
  if (!opts) {
    return { preserve: false }
  }
  if (typeof opts === 'boolean') {
    return { preserve: opts }
  }
  return opts || {}
}

module.exports = capitalize

Allow capitalize.words to accept an options object


var debug = require('diagnostics')('artsy');
var Mana = require('mana');

Mana.extend({
  /**
   * Do constructor things
   *
   * @constructor
   * @api public
   *
   **/
  initialise: function initialise (options) {
    options = options || {};

    this.api = options.url || 'https://api.artsy.net/api/v1/';
    // TODO: Make this conditional because it can be X-Access-Token as well
    this.authHeader = 'X-XAPP-Token';
    this.authorization = options.token;

    if (!this.authorization) {
      throw new Error('Token required to make api requests, please generate one');
    }
  },
  options: function (opts, params) {
    opts = opts || {}
    opts.params = opts.params || params || [];

    var defaults = { page: 1, size: 100 };
    Object.keys(defaults).forEach(function (key) {
      if (Array.isArray(opts.params)) {
        if (!~opts.params.indexOf(key)) opts.params.push(key);
        if (!opts[key]) opts[key] = defaults[key];
      }
      else {
        if (!(key in opts.params)) opts.params[key] = defaults[key];
      }
    });

    return opts;
  }
}).drink(module);

var debug = require('diagnostics')('artsy');
var Mana = require('mana');

Mana.extend({
  /**
   * Do constructor things
   *
   * @constructor
   * @api public
   *
   **/
  initialise: function initialise (options) {
    options = options || {};

    this.api           = options.url    || 'https://api.artsy.net/api/v1/';
    this.authHeader    = options.header || 'X-XAPP-Token';
    this.authorization = options.token;

    if (!this.authorization) {
      throw new Error('Token required to make api requests, please generate one');
    }
  },
  options: function (opts, params) {
    opts = opts || {}
    opts.params = opts.params || params || [];

    var defaults = { page: 1, size: 100 };
    Object.keys(defaults).forEach(function (key) {
      if (Array.isArray(opts.params)) {
        if (!~opts.params.indexOf(key)) opts.params.push(key);
        if (!opts[key]) opts[key] = defaults[key];
      }
      else {
        if (!(key in opts.params)) opts.params[key] = defaults[key];
      }
    });

    return opts;
  }
}).drink(module);

Allow for multiple auth header types.


#!/usr/bin/env node

const program = require('commander')

const { initCommand, runCommand, deployCommand } = require('./lib/index')

const optionsFilePath = `${process.env.HOME}/.configfiles`

program
  .version('1.0.0')
  .description('Config files manager')

program
  .command('init')
  .alias('i')
  .description('activate configfiles on user session.')
  .option('-f, --force', 'force parameters file overwrite.')
  .action(initCommand(optionsFilePath))

program
  .command('run <name>')
  .alias('r')
  .description('run custom configuration scripts.')
  .action(runCommand(optionsFilePath))

program
  .command('deploy [modules...]')
  .alias('d')
  .description('deploy configuration files.')
  .action(deployCommand(optionsFilePath))

program.parse(process.argv)

#!/usr/bin/env node

const program = require('commander')
const fs = require('fs')
const path = require('path')

const { initCommand, runCommand, deployCommand } = require('./lib/index')

const optionsFilePath = `${process.env.HOME}/.configfiles`
const packageData = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json')))

program
  .version(packageData.version)
  .description('Config files manager')

program
  .command('init')
  .alias('i')
  .description('activate configfiles on user session.')
  .option('-f, --force', 'force parameters file overwrite.')
  .action(initCommand(optionsFilePath))

program
  .command('run <name>')
  .alias('r')
  .description('run custom configuration scripts.')
  .action(runCommand(optionsFilePath))

program
  .command('deploy [modules...]')
  .alias('d')
  .description('deploy configuration files.')
  .action(deployCommand(optionsFilePath))

program.parse(process.argv)

Use version of package.json for -v


'use strict';

// Module dependencies
var path = require('path');

// Set module root directory
process.rootPublish = __dirname;
process.requirePublish = function(filePath) {
  return require(path.normalize(process.rootPublish + '/' + filePath));
};

module.exports = process.requirePublish('app/server/PublishPlugin.js');

'use strict';

// Module dependencies
var path = require('path');

// Set module root directory
process.rootPublish = __dirname;
process.requirePublish = function(filePath) {
  return require(path.join(process.rootPublish, filePath));
};

module.exports = process.requirePublish('app/server/PublishPlugin.js');

Replace wrong use of path.normalize


'use strict'

// Defer function using native promises
const defer = function() {
  let result = {}
  result.promise = new Promise(function(resolve, reject) {
    result.resolve = resolve
    result.reject  = reject
  })
  return result
}

// Make callback function
const prepareCallback = function(deferred, withoutErrorAttr) {

  // By default start with a second attribute
  let base = 2

  // But if it's not node style callback switch to the first one
  if (withoutErrorAttr)
    --base

  return function () {
    // If node style function return an error
    if (arguments[0] && !withoutErrorAttr) {
      deferred.reject(arguments[0])
    }

    else if (arguments.length < base) {
      deferred.resolve()
    }

    else if (arguments.length === base) {
      deferred.resolve(arguments[--base])
    }

    else {
      deferred.resolve(Array.prototype.slice.call(arguments, --base))
    }
  }
}

// Transform function with callback to generator
const generatorify = module.exports = function(fn, context, withoutErrorAttr) {
  return function() {
    const deferred = defer(),
          callback = prepareCallback(deferred, withoutErrorAttr),
          args     = Array.prototype.slice.call(arguments).concat(callback)

    fn.apply(context, args)
    return deferred.promise
  };
}

'use strict'

// Make callback function
const prepare = function(resolve, reject, withoutErrorAttr) {

  // By default start with a second attribute
  let base = 2

  // But if it's not node style callback switch to the first one
  if (withoutErrorAttr)
    --base

  return function () {
    // If node style function return an error
    if (arguments[0] && !withoutErrorAttr) {
      reject(arguments[0])
    }

    else if (arguments.length < base) {
      resolve()
    }

    else if (arguments.length === base) {
      resolve(arguments[--base])
    }

    else {
      resolve(Array.prototype.slice.call(arguments, --base))
    }
  }
}

// Transform function with callback to generator
const generatorify = module.exports = function(fn, context, withoutErrorAttr) {
  return function() {

    let fnArgs = arguments

    return new Promise(function(resolve, reject) {
      let args     = Array.prototype.slice.call(fnArgs)
                          .concat(prepare(resolve, reject, withoutErrorAttr))

      return fn.apply(context, args)
    })
  }
}

Remove deffered and simplify script.


function forIn(object, callback) {
  for (const key in object) {
    if (!object.hasOwnProperty(key)) {
      continue;
    }

    callback(key);
  }
}

function normalize(metaInformation) {
  const normalized = {};

  forIn(metaInformation, function cb(key) {
    if (typeof metaInformation[key] === 'object') {
      // Normalize nested objects
      if (key === 'flowType') {
        // Replace 'flowType' with 'type'
        normalized.type = normalize(metaInformation[key]);
        return;
      }

      normalized[key] = normalize(metaInformation[key]);
      return;
    } else if (Array.isArray(metaInformation[key])) {
      // Normalize nested arrays
      for (let i = 0; i < metaInformation[key].length; i++) {
        normalized[key][i] = normalize(metaInformation[key][i]);
      }
    }

    normalized[key] = metaInformation[key];
  });

  return normalized;
}

module.exports = normalize;

function forIn(object, callback) {
  for (const key in object) {
    if (!object.hasOwnProperty(key)) {
      continue;
    }

    callback(key);
  }
}

function normalize(metaInformation) {
  const normalized = {};

  forIn(metaInformation, function cb(key) {
    if (Array.isArray(metaInformation[key])) {
      // Normalize nested arrays
      normalized[key] = [];
      for (let i = 0; i < metaInformation[key].length; i++) {
        normalized[key][i] = normalize(metaInformation[key][i]);
      }
    } else if (typeof metaInformation[key] === 'object') {
      // Normalize nested objects
      if (key === 'flowType') {
        // Replace 'flowType' with 'type'
        normalized.type = normalize(metaInformation[key]);
        return;
      }

      normalized[key] = normalize(metaInformation[key]);
      return;
    }

    normalized[key] = metaInformation[key];
  });

  return normalized;
}

module.exports = normalize;

Fix arrays being converted to objects


module.exports = {
  dataSource: "prs",
  prefix: "",
  onlyMilestones: false,
  ignoreTagsWith: ["v0.32.0", "0.0.3"],
  tags: "all",
  groupBy: false,
  changelogFilename: "CHANGELOG.md",
  template: {
    release: function (placeholders, body) {
      let dateParts = placeholders.date.split("/");
      let placeholdersDate = new Date(
        Number(dateParts[2]),
        Number(dateParts[1]) - 1,
        Number(dateParts[0])
      );
      let isoDateString = placeholdersDate.toISOString().split("T")[0];
      return `## ${placeholders.release} (${isoDateString})\n${placeholders.body}`;
    },
  },
};

module.exports = {
  dataSource: "prs",
  prefix: "",
  onlyMilestones: false,
  ignoreTagsWith: ["v0.32.0", "0.0.3"],
  tags: "all",
  groupBy: false,
  changelogFilename: "CHANGELOG.md",
  template: {
    release: function (placeholders) {
      let dateParts = placeholders.date.split("/");
      let placeholdersDate = new Date(
        Number(dateParts[2]),
        Number(dateParts[1]) - 1,
        Number(dateParts[0])
      );
      let isoDateString = placeholdersDate.toISOString().split("T")[0];
      return `## ${placeholders.release} (${isoDateString})\n${placeholders.body}`;
    },
  },
};

Use correct function argument list


var path = require('path'),
    rootPath = path.normalize(__dirname + '/..'),
    fs = require('fs'),
    env = process.env.NODE_ENV || 'development';

var db_path = path.join( process.env['UU_PATH'] ||
      process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'],
      ".uu/");

var db_file = path.join(db_path, "paste_db");
var db_binary = path.join(db_path, "binary_files");

[db_path, db_binary].forEach(function(folder) {
  if(!fs.existsSync(folder)) {
    console.log("Creating folder %s...", folder);
    fs.mkdirSync(folder, "0700");
  }
});

var config = {
  development: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 3000
  },

  test: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 3000
  },

  production: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 3000
  }
};

module.exports = config[env];

config[env].db_path = db_path;
config[env].db_file = db_file;
config[env].db_binary_directory = db_binary;

var path = require('path'),
    rootPath = path.normalize(__dirname + '/..'),
    fs = require('fs'),
    env = process.env.NODE_ENV || 'development';

var db_path = path.join( process.env['UU_PATH'] ||
      process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME'],
      ".uu/");

var db_file = path.join(db_path, "paste_db");
var db_binary = path.join(db_path, "binary_files");

[db_path, db_binary].forEach(function(folder) {
  if(!fs.existsSync(folder)) {
    console.log("Creating folder %s...", folder);
    fs.mkdirSync(folder, "0700");
  }
});

var config = {
  development: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 3000
  },

  test: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 3000
  },

  production: {
    root: rootPath,
    app: {
      name: 'uu.js'
    },
    port: 8080
  }
};

module.exports = config[env];

config[env].db_path = db_path;
config[env].db_file = db_file;
config[env].db_binary_directory = db_binary;

Use alternate port in production


/*
 * Author: CM
 */

(function(global) {

  var storage = {};

  /**
   * @param {String} name
   * @param {Promise} promise
   * @returns {Promise}
   */
  function promiseThrottler(name, promise) {
    if (!storage[name]) {
      storage[name] = promise.finally(function() {
        delete storage[name];
      });
    }
    return storage[name];
  }

  global.promiseThrottler = promiseThrottler;

})(window);

/*
 * Author: CM
 */

(function(global) {

  var storage = {};

  /**
   * @callback PromiseThrottled
   * @param {...Object|String|Number} any number of optional params
   * @return {Promise}
   */

  /**
   * @param {PromiseThrottled} fn
   * @param {Boolean} cancel
   * @returns {PromiseThrottled}
   */
  function promiseThrottler(fn, cancel) {
    var promise;
    return function() {
      if (cancel && promise && promise.isPending()) {
        promise.cancel();
      }
      if (!promise || !promise.isPending()) {
        promise = fn.apply(null, arguments);
      }
      return promise;
    };
  }

  global.promiseThrottler = promiseThrottler;

})(window);

Update promiseThrottler for PromiseThrottled param.


var rfr = require('rfr');

var Utility = rfr('app/util/Utility');
var Storage = rfr('app/models/Storage');

var logger = Utility.createLogger(__filename);

function UserService() {
}

var Class = UserService.prototype;

Class.createNewUser = function(particulars) {
  logger.debug('Creating new user: %j', particulars);
  return Storage.createUser(particulars)
  .then(function receiveResult(result) {
    if (result) {
      return result.dataValues;
    }

    return null;
  });
};

Class.getUserByPlatform = function(platformType, platformId) {
  // TODO: Call Storage's API
  return new Promise(function (resolve, reject) {
    resolve(false);
  });
};

module.exports = new UserService();

var rfr = require('rfr');

var Utility = rfr('app/util/Utility');
var Storage = rfr('app/models/Storage');

var logger = Utility.createLogger(__filename);

function UserService() {
}

var Class = UserService.prototype;

Class.createNewUser = function(particulars) {
  logger.debug('Creating new user: %j', particulars);

  return Storage.createUser(particulars)
  .then(function receiveResult(result) {
    if (result) {
      return result.dataValues;
    }

    return null;
  });
};

Class.getUserByPlatform = function(platformType, platformId) {
  logger.debug('Getting user by platform: %s %s', platformType, platformId);

  return Storage.getUserByPlatformId(platformType, platformId)
  .then(function receiveResult(result) {
    if (result) {
      return result.dataValues;
    }

    return null;
  });
};

module.exports = new UserService();

Implement get user by platform in service


import * as settings from './settings.js';
import {
  createView,
  getFrameRenderer,
} from './view.js';
import {
  separateBodies,
  simulateFrame,
} from './simulation.js';
import {
  getRandomBody,
} from './meebas/bodies.js';
import {
  range,
} from './utils/arrays.js';

const { width, height } = settings.tank;

const view = createView(width, height);
const renderFrame = getFrameRenderer(view);

/** @type {Object<string, any>} */
const anyWindow = window;
const MeebaFarm = {};
anyWindow.MeebaFarm = MeebaFarm;

MeebaFarm.bodies = range(settings.simulation.bodies).map(getRandomBody);
separateBodies(MeebaFarm.bodies);

/** @param {number} lastTick */
const simulate = (lastTick) => {
  const thisTick = performance.now();
  MeebaFarm.bodies = simulateFrame(MeebaFarm.bodies, lastTick, thisTick);
  setTimeout(() => simulate(thisTick), 8);
};
const render = () => {
  renderFrame(MeebaFarm.bodies);
  requestAnimationFrame(render);
};

// eslint-disable-next-line no-console
console.log('Simulating with seed:', settings.seed);
simulate(performance.now());
requestAnimationFrame(render);

import * as settings from './settings.js';
import {
  createView,
  getFrameRenderer,
} from './view.js';
import {
  separateBodies,
  simulateFrame,
} from './simulation.js';
import {
  getRandomBody,
} from './meebas/bodies.js';
import {
  range,
} from './utils/arrays.js';

const { width, height } = settings.tank;

const view = createView(width, height);
const renderFrame = getFrameRenderer(view);

/** @type {Object<string, any>} */
const anyWindow = window;
const MeebaFarm = {};
anyWindow.MeebaFarm = MeebaFarm;

MeebaFarm.bodies = range(settings.simulation.bodies).map(getRandomBody);
separateBodies(MeebaFarm.bodies);

/** @type {boolean} */
let isRunning;

/** @param {number} lastTick */
const simulate = (lastTick) => {
  if (isRunning) {
    const thisTick = performance.now();
    MeebaFarm.bodies = simulateFrame(MeebaFarm.bodies, lastTick, thisTick);
    setTimeout(() => simulate(thisTick), 8);
  }
};
const render = () => {
  if (isRunning) {
    renderFrame(MeebaFarm.bodies);
    requestAnimationFrame(render);
  }
};

MeebaFarm.pause = () => {
  isRunning = false;
};

MeebaFarm.resume = () => {
  isRunning = true;
  simulate(performance.now());
  requestAnimationFrame(render);
};

// eslint-disable-next-line no-console
console.log('Simulating with seed:', settings.seed);
MeebaFarm.resume();

Add global methods to pause and resume simulation


import { connect } from 'react-redux';
import Matches from '../components/Matches.jsx';
import { unmountMatch, removeMatch, incrementOffset, addMatches } from '../actions/index.js';

const mapStateToProps = (state) => (
  {
    matches: state.matches.values,
    offset: state.matches.offset,
    selfId: state.profile.id,
  }
);

const mapDispatchToProps = (dispatch) => (
  {
    onConnectClick: (id) => {
      dispatch(unmountMatch(id));
      setTimeout(
        () => {
          dispatch(removeMatch(id));
        },
        120
      );
    },
    onHideClick: (id) => {
      dispatch(unmountMatch(id));
      setTimeout(
        () => {
          dispatch(removeMatch(id));
        },
        120
      );
    },
    onLoadMoreClick: (selfId, offset) => {
      //use the offset to get additional matches from db, then
      dispatch(addMatches([{firstName: 'Velvet', lastName: 'Underground', canTeach: [['English', 'native']], willLearn: [['German', 'advanced']], description: 'hi there'}]));
      dispatch(incrementOffset(20));
    },
  }
);

export default connect(mapStateToProps, mapDispatchToProps)(Matches);

import { connect } from 'react-redux';
import Matches from '../components/Matches.jsx';
import { unmountMatch, removeMatch, incrementOffset, addMatches } from '../actions/index.js';

const mapStateToProps = (state) => (
  {
    matches: state.matches.values,
    offset: state.matches.offset,
    selfId: state.profile.id,
  }
);

const mapDispatchToProps = (dispatch) => (
  {
    onConnectClick: (id) => {
      dispatch(unmountMatch(id));
      setTimeout(
        () => {
          dispatch(removeMatch(id));
        },
        120
      );
    },
    onHideClick: (id) => {
      dispatch(unmountMatch(id));
      setTimeout(
        () => {
          dispatch(removeMatch(id));
        },
        120
      );
    },
    onLoadMoreClick: (selfId, offset) => {
      //use the offset to get additional matches from db, then
      dispatch(addMatches([{firstName: 'Velvet', lastName: 'Underground', canTeach: [['English', 'native']], willLearn: [['German', 'advanced']], description: 'hi there', photoUrl: 'http://watchmojo.com/uploads/blipthumbs/M-RR-Top10-Velvet-Underground-Songs-480p30_480.jpg'}]));
      dispatch(incrementOffset(20));
    },
  }
);

export default connect(mapStateToProps, mapDispatchToProps)(Matches);

Add photoUrl to sample data


const RearError = require('../rear-error');

it('Should have code, errno and other props', () => {
  const errMessage = 'Test error message';
  const errProps = {
    code: 'ETEST',
    errno: 400,
    extras: ['rear-core', 'rear-logger']
  };
  const expectedErrProps = { extras: errProps.extras }

  const err = new RearError(errMessage, errProps);

  expect(err.message).toBe(errMessage);
  expect(err.code).toEqual(errProps.code);
  expect(err.errno).toEqual(errProps.errno);
  expect(err.props).toEqual(expectedErrProps);
});

const RearError = require('../rear-error');

describe('rear-error', () => {
  it('Should have message, code, errno and other props', () => {
    const message = 'Test error message';
    const props = { code: 'ETEST', errno: 400, extras: ['rear-core'] };
    const expectedProps = { extras: props.extras }

    const err = new RearError(message, props);

    expect(err.message).toBe(message);
    expect(err.code).toEqual(props.code);
    expect(err.errno).toEqual(props.errno);
    expect(err.props).toEqual(expectedProps);
  });

  it('Should include the error message in the stack trace', () => {
    const message = 'Test error message';
    const props = { code: 'ETEST', errno: 500 };
    const err = new RearError(message, props);

    expect(err.stack).toBeDefined();
    expect(err.stack.split('\n')[0].indexOf(message) !== -1).toBeTruthy();
  });
})

Add rear-error stack trace test


'use strict';

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  afterInstall: function() {
    return this.addBowerPackageToProject('pretender', '~0.6.0');
    return this.addBowerPackageToProject('ember-inflector', '~1.4.0');
  }
};

'use strict';

module.exports = {
  normalizeEntityName: function() {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  },

  afterInstall: function() {
    return this.addBowerPackageToProject('pretender', '~0.6.0');
    return this.addBowerPackageToProject('ember-inflector', '~1.3.1');
  }
};

Revert "Revert "Updates `ember-inflector` version""


/* global legacy, legacyConvert */

module.exports = function(grunt) {
	grunt.registerTask('convertLegacy', function(task) {
		var dest = legacyConvert[task],
			css = grunt.file.read(dest);

		// Convert rem units to px
		var rootSize = legacy.rootSize,
			rootValue = 10;

		// Determine root value for unit conversion
		if (rootSize.indexOf('%') !== -1) {
			rootValue = (rootSize.replace('%', '') / 100) * 16;
		} else if (rootSize.indexOf('px') !== -1) {
			rootValue = rootSize.replace('px', '');
		} else if (rootSize.indexOf('em') !== -1) {
			rootValue = rootSize.replace('em', '');
		} else if (rootSize.indexOf('pt') !== -1) {
			rootValue = rootSize.replace('pt', '');
		}

		var output = css.replace(/(-?[.\d]+)rem/gi, function(str, match) {
			return (match * rootValue) + 'px';
		});

		// Convert opacity to filter
		output = output.replace(/(-?[.\d]+)rem/gi, function(str, match) {
			return 'filter:alpha(opacity=' + Math.round((match * 100) * 100 / 100) + ');';
		});

		grunt.file.write(dest, output);
	});
};

/* global legacy, legacyConvert */

module.exports = function(grunt) {
	grunt.registerTask('convertLegacy', function(task) {
		var dest = legacyConvert[task],
			css = grunt.file.read(dest);

		// Convert rem units to px
		var rootSize = legacy.rootSize,
			rootValue = 10;

		// Determine root value for unit conversion
		if (rootSize.indexOf('%') !== -1) {
			rootValue = (rootSize.replace('%', '') / 100) * 16;
		} else if (rootSize.indexOf('px') !== -1) {
			rootValue = rootSize.replace('px', '');
		} else if (rootSize.indexOf('em') !== -1) {
			rootValue = rootSize.replace('em', '');
		} else if (rootSize.indexOf('pt') !== -1) {
			rootValue = rootSize.replace('pt', '');
		}

		var output = css.replace(/(-?[.\d]+)rem/gi, function(str, match) {
			return (match * rootValue) + 'px';
		});

		// Convert opacity to filter
		output = output.replace(/opacity:([.\d]+)/gi, function(str, match) {
			return 'filter:alpha(opacity=' + Math.round((match * 100) * 100 / 100) + ');';
		});

		grunt.file.write(dest, output);
	});
};

Fix legacy converter with proper regex to match opacity


var path = require('path'),
  rootPath = path.normalize(__dirname + '/..'),
  env = process.env.NODE_ENV || 'development';

var config = {
  development: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: 3000,
    db: 'mongodb://localhost/tweb-development'
  },

  test: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: 3000,
    db: 'mongodb://localhost/tweb-test'
  },

  production: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: 3000,
    db: 'mongodb://localhost/tweb-production'
  }
};

module.exports = config[env];

var path = require('path'),
  rootPath = path.normalize(__dirname + '/..'),
  env = process.env.NODE_ENV || 'development';

var config = {
  development: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: process.env.PORT || 3000,
    db: 'mongodb://localhost/tweb-development'
  },

  test: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: process.env.PORT || 3000,
    db: 'mongodb://localhost/tweb-test'
  },

  production: {
    root: rootPath,
    app: {
      name: 'tweb'
    },
    port: process.env.PORT || 3000,
    db: 'mongodb://localhost/tweb-production'
  }
};

module.exports = config[env];

Modify listening port (for heroku)


module.exports = function(server) {

  server.get('/', function(req, res) {

    res.render('home', {
        title: "Title"
    });

  });

  server.get('/inbound/:mailgun_key', function(req, res) {
    console.log(req.body);
    if (process.env["MAILGUN_KEY"] === req.params["mailgun_key"]) {
      res.send("Email received!");
    } else {
      res.send(403, "Unauthorized");
    }
  });

};

module.exports = function(server) {

  server.get('/', function(req, res) {

    res.render('home', {
        title: "Title"
    });

  });

  server.post('/inbound/:mailgun_key', function(req, res) {
    console.log(req.body);
    if (process.env["MAILGUN_KEY"] === req.params["mailgun_key"]) {
      res.send("Email received!");
    } else {
      res.send(403, "Unauthorized");
    }
  });

};

Change mailgun route to POST


import Component from '@ember/component';
import { computed } from '@ember/object';
import { isEqual } from '@ember/utils';
import { run } from '@ember/runloop';

export default Component.extend({
  tagName: 'input',
  type: 'radio',

  // value - required
  // groupValue - required

  // autofocus - boolean
  // disabled - optional
  // name - optional
  // required - optional
  // radioClass - string
  // radioId - string
  // tabindex - number
  // ariaLabelledby - string
  // ariaDescribedby - string

  defaultLayout: null, // ie8 support

  attributeBindings: [
    'autofocus',
    'checked',
    'disabled',
    'name',
    'required',
    'tabindex',
    'type',
    'value',
    'ariaLabelledby:aria-labelledby',
    'ariaDescribedby:aria-describedby'
  ],

  checked: computed('groupValue', 'value', function() {
    return isEqual(this.get('groupValue'), this.get('value'));
  }).readOnly(),

  sendChangedAction() {
    this.sendAction('changed', this.get('value'));
  },

  change() {
    let value = this.get('value');
    let groupValue = this.get('groupValue');

    if (groupValue !== value) {
      this.set('groupValue', value); // violates DDAU
      run.once(this, 'sendChangedAction');
    }
  }
});

import Component from '@ember/component';
import { computed } from '@ember/object';
import { isEqual } from '@ember/utils';
import { run } from '@ember/runloop';

export default Component.extend({
  tagName: 'input',
  type: 'radio',

  // value - required
  // groupValue - required

  // autofocus - boolean
  // disabled - optional
  // name - optional
  // required - optional
  // radioClass - string
  // radioId - string
  // tabindex - number
  // ariaLabelledby - string
  // ariaDescribedby - string

  defaultLayout: null, // ie8 support

  attributeBindings: [
    'autofocus',
    'checked',
    'disabled',
    'name',
    'required',
    'tabindex',
    'type',
    'value',
    'ariaLabelledby:aria-labelledby',
    'ariaDescribedby:aria-describedby',
    'checked:aria-checked'
  ],

  checked: computed('groupValue', 'value', function() {
    return isEqual(this.get('groupValue'), this.get('value'));
  }).readOnly(),

  sendChangedAction() {
    this.sendAction('changed', this.get('value'));
  },

  change() {
    let value = this.get('value');
    let groupValue = this.get('groupValue');

    if (groupValue !== value) {
      this.set('groupValue', value); // violates DDAU
      run.once(this, 'sendChangedAction');
    }
  }
});

Add Aria checked attribute binding


import TextDisplay from "../src/text";

import { richestMimetype, transforms } from "../src";

describe("richestMimetype", () => {
  it("picks the richest of the mimetypes from a bundle with defaults", () => {
    const mimeBundle = { "text/plain": "Hello World" };

    expect(richestMimetype(mimeBundle)).toEqual("text/plain");

    expect(
      richestMimetype({ "text/plain": "Hello World", "image/png": "imageData" })
    ).toEqual("image/png");
  });
  it("falls back to a simpler mimetype if a transform is not available", () => {
    const mimeBundle = {
      "text/plain": "Hello World",
      "text/html": "NIY"
    };

    const order = ["text/html", "text/plain"];
    const myTransforms = { "text/plain": TextDisplay };

    const mimetype = richestMimetype(mimeBundle, order, myTransforms);
    expect(mimetype).toEqual("text/plain");
  });
});

describe("transforms", () => {
  it("is a collection of default transforms that provide React components", () => {
    const mimeBundle = {
      "text/plain": "Hello World",
      "text/html": "NIY"
    };

    const mimetype = richestMimetype(mimeBundle, ["text/plain"]);
    const Element = transforms[mimetype];

    expect(Element).toEqual(TextDisplay);
  });
});

import TextDisplay from "../src/text";

import { richestMimetype, transforms } from "../src";

describe("richestMimetype", () => {
  it("picks the richest of the mimetypes from a bundle with defaults", () => {
    const singleMimeBundle = { "text/plain": "Hello World" };
    const mimeBundle = {
      "text/plain": "Hello World",
      "image/png": "imageData"
    };

    expect(richestMimetype(singleMimeBundle)).toEqual("text/plain");
    expect(richestMimetype(Object.freeze(singleMimeBundle))).toEqual(
      "text/plain"
    );

    expect(richestMimetype(Object.freeze(mimeBundle))).toEqual("image/png");
  });
  it("falls back to a simpler mimetype if a transform is not available", () => {
    const mimeBundle = {
      "text/plain": "Hello World",
      "text/html": "NIY"
    };

    const order = ["text/html", "text/plain"];
    const myTransforms = { "text/plain": TextDisplay };

    const mimetype = richestMimetype(mimeBundle, order, myTransforms);
    expect(mimetype).toEqual("text/plain");
  });
});

describe("transforms", () => {
  it("is a collection of default transforms that provide React components", () => {
    const mimeBundle = {
      "text/plain": "Hello World",
      "text/html": "NIY"
    };

    const mimetype = richestMimetype(mimeBundle, ["text/plain"]);
    const Element = transforms[mimetype];

    expect(Element).toEqual(TextDisplay);
  });
});

Add tests to make sure transforms accept frozen objects


module.exports = {

  updateInfo: function (req, res) {
    var result = {}

    /*
    Format for result:
    result = {
      type: 'force',  // can be 'force' or 'suggest'
      title: 'A new version of the app is available',
      message: 'You can go to the App Store now to update',
      iTunesItemIdentifier: '1002185140'
    }
    */

    switch (req.headers['ios-version']) {
      case '1.6':
      case '1.65':
        result = {
          type: 'force',  // can be 'force' or 'suggest'
          title: 'A new version of the app is available',
          message: 'The version you are using is no longer compatible with the site. Please go to the App Store now to update',
          iTunesItemIdentifier: '1002185140'
        }
        break
      case undefined:
        break
    }

    switch (req.headers['android-version']) {
      case undefined:
        break
    }

    res.ok(result)
  }
}

module.exports = {

  updateInfo: function (req, res) {
    var result = {}
    var iTunesItemIdentifier = '1002185140'
    var forceUpdate = {
      type: 'force',
      title: 'A new version of the app is available',
      iTunesItemIdentifier
    }
    var suggestUpdate = {
      type: 'suggest',
      title: 'An update is available',
      iTunesItemIdentifier
    }

    /*
    Format for result:
    result = {
      type: 'force',  // can be 'force' or 'suggest'
      title: 'A new version of the app is available',
      message: 'You can go to the App Store now to update',
      iTunesItemIdentifier: '1002185140'
    }
    */
    // console.log('req.headers', req.headers)
    var version = req.param('ios-version') || req.param('android-version')
    switch (version) {
      case '1.6':
        result = Object.assign(
          suggestUpdate,
          { message: 'The version you are using is not longer up to date. Please go to the App Store to update.' }
        )
        break
      case '1.65':
        result = Object.assign(
          forceUpdate,
          { message: 'The version you are using is no longer compatible with the site. Please go to the App Store now to update' }
        )
        break
      case undefined:
        break
      default:
        result = Object.assign(
          forceUpdate,
          { message: 'The version you are using is no longer compatible with the site. Please go to the App Store now to update' }
        )
    }
    res.ok(result)
  }
}

Return object based on mobile version


var path = require("path");
var webpack = require("webpack");

module.exports = {
  entry: "./src/main.ts",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist")
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: ["babel-loader", "ts-loader"]
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    })
  ]
};

var path = require("path");
var webpack = require("webpack");

module.exports = {
  entry: "./src/main.ts",
  output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    libraryTarget: "commonjs2"
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: ["babel-loader", "ts-loader"]
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js'],
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
    })
  ]
};

Make library importable using CommonJS and ES6 module system