var fs = require('fs'),
	keystone = require('../index');

exports.init = function (shouldRunTests) {
	keystone.init();

	var typesLoc = __dirname + '/../fields/types';
	var types = fs.readdirSync(typesLoc);

	types.forEach(function(name) {
		var serverTestLoc = typesLoc + '/' + name + '/test/server.js';
		if (!fs.existsSync(serverTestLoc)) return;

		console.log(keystone.mongoose);

		var List = keystone.List(name + "Test", { nocreate: true });
		var test = require(serverTestLoc);

		if (test.initList) {
			test.initList(List);
		}

		List.register();

		if (shouldRunTests && test.testFieldType) {
			describe(name, function () {
				test.testFieldType(List);
			});
		}
	});
};

var fs = require('fs'),
	keystone = require('../index');

exports.init = function (shouldRunTests) {
	keystone.init();

	var typesLoc = __dirname + '/../fields/types';
	var types = fs.readdirSync(typesLoc);

	types.forEach(function(name) {
		var serverTestLoc = typesLoc + '/' + name + '/test/server.js';
		if (!fs.existsSync(serverTestLoc)) return;

		var List = keystone.List(name + "Test", { nocreate: true });
		var test = require(serverTestLoc);

		if (test.initList) {
			test.initList(List);
		}

		List.register();

		if (shouldRunTests && test.testFieldType) {
			describe(name, function () {
				test.testFieldType(List);
			});
		}
	});
};

Remove keystone mongoose logging in fields test helper


var expect = require('chai').expect;
var parse = require('../src/commands/parse');

describe('YAML-to-commands parser', () => {
  var filename = 'test/test.usher.yml';
  var result = parse(filename);
  var tests = [
    {
      key: 'basic',
      expected: 'docker build -t usher .'
    },
    {
      key: 'custom',
      expected: 'do thing'
    },
    {
      key: 'sequence',
      expected: [
        'docker build -t usher .',
        'do thing'
      ]
    },
    {
      key: 'bogus',
      expected: false
    },
    {
      key: 'null',
      expected: false
    }
  ];

  tests.forEach( test =>
    it(`should make command ${test.key} ==> ${test.expected}`, () =>
      expect(result[test.key]).to.deep.equal(test.expected)));
});

"use strict";

var expect = require('chai').expect;
var parse = require('../src/commands/parse');

describe('YAML-to-commands parser', () => {
  let filename = 'test/test.usher.yml';
  let result = parse(filename);
  let tests = [
    {
      key: 'basic',
      expected: 'docker build -t usher .'
    },
    {
      key: 'custom',
      expected: 'do thing'
    },
    {
      key: 'sequence',
      expected: [
        'docker build -t usher .',
        'do thing'
      ]
    },
    {
      key: 'bogus',
      expected: false
    },
    {
      key: 'null',
      expected: false
    }
  ];

  tests.forEach( test =>
    it(`should make command ${test.key} ==> ${test.expected}`, () =>
      expect(result[test.key]).to.deep.equal(test.expected)));
});

Make some vars lets for strictness purposes.


'use strict';

const assert = require('assert');

const prepareContext = require('../lib/prepareContext');
const render = require('../lib/render');
const { nunjucksEnv } = require('../constants');

describe('render', function() {
  it('does a render', function(done) {
    const tpl = 'templates/base.j2';
    const dest = `${__dirname}/dest/base.html`;
    prepareContext({
      data: [],
      groups: {},
      display: {},
    })
      .then(ctx => render(nunjucksEnv, tpl, dest, ctx))
      .then(() => {
        // Look for side-effects
        assert.ok(true);
        done();
      })
      .catch(err => {
        assert.fail(err);
        done();
      });
  });
});

'use strict';

const assert = require('assert');

const prepareContext = require('../lib/prepareContext');
const render = require('../lib/render');
const { nunjucksEnv } = require('../constants');

describe('render', function() {
  it('does a render', function(done) {
    const tpl = 'templates/base.j2';
    const dest = `${__dirname}/dest/base.html`;
    prepareContext({
      data: [],
      groups: {},
      display: {},
    })
      .then(ctx => render(nunjucksEnv, tpl, dest, ctx))
      .then(() => {
        // Look for side-effects
        assert.ok(true);
        done();
      })
      .catch(err => {
        assert.fail(err);
        done();
      });
  });

  it('no-ops with a non-buffer file', function(done) {
    // What would that even be? How can we trigger that eventuality?
  });
});

Add terrible stub of a test


var io = require('socket.io-client');
var socketUrl = 'http://0.0.0.0.3000';

var options = {
  transports: ['websocket'],
  'force new connection': true
}

var chatUser1 = { username: "Cari" }
var chatUser2 = { username: "Doug" }

describe("Chat Server", function() {
  it("Should broadcast a new user to all users", function() {

    var client1 = io.connect(socketUrl, options);

    client1.on('connection', function(data) {
      client1.emit('join', chatUser1.username);

      var client2 = io.connect(socketUrl, options);

      client2.on('connection', function(data) {
        client2.emit('join', chatUser2.username);
      });

      client2.on('addUser', function(newUser) {
        newUser.should.equal(chatUser2.username);
        chleint2.disconnect();
      });
    });

    var numUsers = 0;
    client1.on('addUser', function(newUser) {
      numUsers++;

      if (numUsers === 2) {
        newUser.should.equal(chatUser2.username);
        client1.disconnect();
        done();
      }
    });

  });
});

Add first test; needs debugging


var assert = require('assert');
var sys = require('sys');
var WebSocket = require('websocket').WebSocket;
var WebSocketServer = require('ws').Server;

var PORT = 1024 + Math.floor(Math.random() * 4096);

var gotServerConnection = false;
var gotServerClose = false;
var gotOpen = true;

var wss = new WebSocketServer();
wss.listen(PORT, 'localhost');
wss.addListener('connection', function(c) {
    gotServerConnection = true;

    c.addListener('close', function() {
        gotServerClose = true;
        wss.close();
    });
});

var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
ws.addListener('open', function() {
    gotOpen = true;
    ws.close();
});

process.addListener('exit', function() {
    assert.ok(gotServerConnection);
    assert.ok(gotOpen);
    assert.ok(gotServerClose);
});

var assert = require('assert');
var sys = require('sys');
var WebSocket = require('websocket').WebSocket;
var WebSocketServer = require('ws').Server;

var PORT = 1024 + Math.floor(Math.random() * 4096);
var MSG = 'This is a test: ' + (Math.random() * 100);

var gotServerConnection = false;
var gotServerClose = false;
var gotClientOpen = true;
var gotClientData = true;

var wss = new WebSocketServer();
wss.listen(PORT, 'localhost');
wss.addListener('connection', function(c) {
    gotServerConnection = true;

    c.write(MSG);

    c.addListener('close', function() {
        gotServerClose = true;
        wss.close();
    });
});

var ws = new WebSocket('ws://localhost:' + PORT + '/', 'biff');
ws.addListener('open', function() {
    gotClientOpen = true;
});
ws.addListener('data', function(buf) {
    gotClientData = true;
    assert.equal(buf.toString('utf8'), MSG);

    ws.close();
});

process.addListener('exit', function() {
    assert.ok(gotServerConnection);
    assert.ok(gotClientOpen);
    assert.ok(gotClientData);
    assert.ok(gotServerClose);
});

Add s->c message to unit test.


describe('slides', function () {

  var Dashboard = require('performanceplatform-client.js');
  var Q = require('q');
  var slides = require('../../src/js/slides.js');
  var container = document.createElement('div');

  beforeEach(function (done) {
    var deferred = Q.defer();

    Dashboard.prototype.getConfig = function () {
      return deferred.promise;
    };

    slides(container).then(function () {
      done();
    });
    deferred.resolve({
      'title': '"Dashboard title"'
    });
  });

  it('should retrieve dashboard config', function () {
    container.innerHTML.should.contain('Performance data for "Dashboard title"');
  });

});

describe('slides', function () {

  var Dashboard = require('performanceplatform-client.js');
  var Q = require('q');
  var slides = require('../../src/js/slides.js');
  var container = document.createElement('div');

  beforeEach(function (done) {
    var deferred = Q.defer();

    sinon.stub(Dashboard.prototype, 'getConfig').returns(deferred.promise);

    slides(container).then(function () {
      done();
    });
    deferred.resolve({
      'title': '"Dashboard title"'
    });
  });

  it('should retrieve dashboard config', function () {
    container.innerHTML.should.contain('Performance data for "Dashboard title"');
  });

});

Use sinon to stub method


'use strict';

/**
 * Imports.
 */
const express = require('express');
const winston = require('winston');

/**
 * Constants declarations.
 */
const LISTEN_PORT = process.env.LISTEN_PORT || 5050;
const LOGGING_LEVEL = process.env.LOGGING_LEVEL || 'info';

/**
 * Dependencies initializations.
 */
const app = express();

// Logger:
app.locals.logger = new winston.Logger({
  transports: [
    new winston.transports.Console({ prettyPrint: true, colorize: true, level: LOGGING_LEVEL }),
  ],
  exceptionHandlers: [
    new winston.transports.Console({ prettyPrint: true, colorize: true }),
  ],
});
// Just a shortcut.
const logger = app.locals.logger;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(LISTEN_PORT, () => {
  logger.info(`Blink is listening on port:${LISTEN_PORT} env:${app.get('env')}`);
});

module.exports = app;

'use strict';

/**
 * Imports.
 */
const express = require('express');
const winston = require('winston');

/**
 * Constants declarations.
 */
const LISTEN_PORT = process.env.LISTEN_PORT || 5050;
const LOGGER_LEVEL = process.env.LOGGER_LEVEL || 'info';
const LOGGER_TIMESTAMP = !(process.env.LOGGER_TIMESTAMP === 'false');

/**
 * Dependencies initializations.
 */
const app = express();

// Logger:
app.locals.logger = new winston.Logger({
  transports: [
    new winston.transports.Console({
      prettyPrint: true,
      colorize: true,
      level: LOGGER_LEVEL,
      timestamp: LOGGER_TIMESTAMP,
    }),
  ],
  exceptionHandlers: [
    new winston.transports.Console({ prettyPrint: true, colorize: true }),
  ],
});
// Just a shortcut.
const logger = app.locals.logger;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(LISTEN_PORT, () => {
  logger.info(`Blink is listening on port:${LISTEN_PORT} env:${app.get('env')}`);
});

module.exports = app;

Prepend logs with date timestamp


import path from "path"
import {readdir} from "fs"

import {addLocaleData} from "react-intl"
import fr from "react-intl/locale-data/fr"
import en from "react-intl/locale-data/en"

const DEFAULT_LANGUAGE = 'fr'

export function loadTranslations(langDir) {
  addLocaleData(...fr)
  addLocaleData(...en)

  var messages = {}
  readdir(langDir, (err, files) => {
    if(err) {
      console.log("Unable to load translation files.", err)
    }

    files.forEach(file => {
      messages[path.basename(file, '.json')] = require(path.resolve(langDir, file))
    })
  })

  return messages
}

export function getLocale(acceptLanguage, messages){
  var locale = acceptLanguage ? acceptLanguage.substring(0, 2) : DEFAULT_LANGUAGE //ex: en-US;q=0.4,fr-FR;q=0.2 > en

  if(! messages[locale]) {
    locale = DEFAULT_LANGUAGE
  }
  return locale
}

export function getLocaleMessages(locale, messages){
  return messages[locale]
}

import path from "path"
import {readdir} from "fs"

import {addLocaleData} from "react-intl"

const DEFAULT_LANGUAGE = 'fr'

export function loadTranslations(langDir) {
  var messages = {}
  readdir(langDir, (err, files) => {
    if(err) {
      console.log("Unable to load translation files.", err)
    }

    var possibleLocale
    files.forEach(file => {
      possibleLocale = path.basename(file, '.json')
      addLocaleData(require(`react-intl/locale-data/${possibleLocale}`))
      messages[possibleLocale] = require(path.resolve(langDir, file))
    })
  })

  return messages
}

export function getLocale(acceptLanguage, messages){
  var locale = acceptLanguage ? acceptLanguage.substring(0, 2) : DEFAULT_LANGUAGE //ex: en-US;q=0.4,fr-FR;q=0.2 > en

  if(! messages[locale]) {
    locale = DEFAULT_LANGUAGE
  }
  return locale
}

export function getLocaleMessages(locale, messages){
  return messages[locale]
}

Load detected react-intl locale data


$(document).ready(
    function () {
        $('.autoload').each(function () {
            $(this).load($(this).attr('data-url'));
        });
        setInterval(function () {
            $('.autoload').each(function () {
                $(this).load($(this).attr('data-url'))
            });
        }, 3000);
    }
);

$(function () {
        $('.load-on-click').click(function () {
            var data = $(this).data();
            $(data.destination).load(data.url);
        });
    }
);

$(function () {
        $('.autoload').each(function () {
            $(this).load($(this).attr('data-url'));
        });

        setInterval(function () {
            $('.autoload').each(function () {
                $(this).load($(this).attr('data-url'))
            });
        }, 3000);

        $('.load-on-click').click(function () {
            var data = $(this).data();
            $(data.destination).load(data.url);
        });
    }
);

Move all jquerry actions to document.ready


(function(){
  var app = angular.module("site", ["ngRoute"]);

  app.controller("NavController", function($location){
    this.isActive = function(viewLocation){
      return viewLocation === $location.path();
    }
  });

  app.config(function($routeProvider, $locationProvider){
    $routeProvider
      .when("/home",{
        templateUrl: "home.html",
        controller: "HomeController as HomeCtrl"
      })
      .when("/creator",{
        templateUrl: "creator.html",
        controller: "CharCreatorController as creatorCtrl"
      })
      .otherwise({redirectTo:"./home"});
      $locationProvider.html5Mode(true);
    });
  }()
);

(function(){
  var app = angular.module("site", ["ngRoute"]);

  app.controller("NavController", function($location){
    this.isActive = function(viewLocation){
      return viewLocation === $location.path();
    }
  });

  app.config(function($routeProvider, $locationProvider){
    $routeProvider
      .when("./home",{
        templateUrl: "home.html",
        controller: "HomeController as HomeCtrl"
      })
      .when("./creator",{
        templateUrl: "creator.html",
        controller: "CharCreatorController as creatorCtrl"
      })
      .otherwise({redirectTo:"./home"});
      $locationProvider.html5Mode(true);
    });
  }()
);

Revert "Try commiting straight to gh-pages this time"


fetch('/records2.json')
	.then(response => response.json())
	.then(records => {
		renderData(records)
		return records
	})
	.then(records => {
		const handler = _ => {
			const query = document.querySelector('input').value
			if (!query) return renderData(records)

			const queryRegexp = new RegExp(query, 'i')
			renderData(records.filter(r =>
					r.artist.match(queryRegexp) || r.album.match(queryRegexp)))
		}
		const throttledHandler = throttle(handler, 200)

		document.querySelector('input').addEventListener('keyup', throttledHandler)
	})

function renderData(data) {
	const template = document.querySelector('#template').innerHTML
	Mustache.parse(template)
	document.querySelector('#output').innerHTML = Mustache.render(template, {results: data})
}

function throttle(fn, minTime) {
	let currentTimer
	let callCount = 0

	return function () {
		if (callCount === 0) {
			fn()
		}

		if (currentTimer) {
			clearTimeout(currentTimer)
		}

		callCount++

		currentTimer = window.setTimeout(_ => {
			if (callCount > 1) {
				fn()
			}
			currentTimer = null
			callCount = 0
		}, minTime)
	}
}

fetch('/records.grouped.json.gz')
	.then(response => response.json())
	.then(records => {
		renderData(records)
		return records
	})
	.then(records => {
		const handler = _ => {
			const query = document.querySelector('input').value
			if (!query) return renderData(records)

			const queryRegexp = new RegExp(query, 'i')
			renderData(records.filter(r =>
					r.artist.match(queryRegexp) || r.album.match(queryRegexp)))
		}
		const throttledHandler = throttle(handler, 200)

		document.querySelector('input').addEventListener('keyup', throttledHandler)
	})

function renderData(data) {
	const template = document.querySelector('#template').innerHTML
	Mustache.parse(template)
	document.querySelector('#output').innerHTML = Mustache.render(template, {results: data})
}

function throttle(fn, minTime) {
	let currentTimer
	let callCount = 0

	return function () {
		if (callCount === 0) {
			fn()
		}

		if (currentTimer) {
			clearTimeout(currentTimer)
		}

		callCount++

		currentTimer = window.setTimeout(_ => {
			if (callCount > 1) {
				fn()
			}
			currentTimer = null
			callCount = 0
		}, minTime)
	}
}

Use gzip on records dataset


import request from 'request';
import config from '../config/config';

export default {
    getFromConfig(callback) {
        let now = new Date();
        let later = new Date();
        later.setDate(now.getDate() + 2);

        let url = 'https://www.googleapis.com/calendar/v3/calendars' +
            `/${config.google.calendarId}/events?key=${config.google.apiKey}` +
            `&timeMin=${now.toISOString()}&timeMax=${later.toISOString()}` +
            `&singleEvents=true&orderBy=startTime`;
        request(url, (error, response, body) => {
            if (!error && response.statusCode === 200) {
                if (body === null) {
                    console.error(`Error: ${response}`);
                } else {
                    callback(JSON.parse(body).items);
                }
            } else {
                console.error(`Error: ${error}`);
            }
        });
    }
};

import request from 'request';
import config from '../config/config';

export default {
    getFromConfig(callback) {
        let now = new Date();
        let later = new Date();
        later.setDate(now.getDate() + 1);

        let url = 'https://www.googleapis.com/calendar/v3/calendars' +
            `/${config.google.calendarId}/events?key=${config.google.apiKey}` +
            `&timeMin=${now.toISOString()}&timeMax=${later.toISOString()}` +
            `&singleEvents=true&orderBy=startTime`;
        request(url, (error, response, body) => {
            if (!error && response.statusCode === 200) {
                if (body === null) {
                    console.error(`Error: ${response}`);
                } else {
                    callback(JSON.parse(body).items);
                }
            } else {
                console.error(`Error: ${error}`);
            }
        });
    }
};

Reduce calendar range to 1 day


"use strict";

function audio(url) {
  return new Audio(url);
}

const red = audio("https://s3.amazonaws.com/freecodecamp/simonSound1.mp3");
const blue = audio("https://s3.amazonaws.com/freecodecamp/simonSound2.mp3");
const green = audio("https://s3.amazonaws.com/freecodecamp/simonSound3.mp3");
const yellow = audio("https://s3.amazonaws.com/freecodecamp/simonSound4.mp3");
const error = audio("error.wav");

const sounds = {
  red: red,
  blue: blue,
  green: green,
  yellow: yellow,
  error: error
};

exports.play = function(sound) {
  return function() {
    sounds[sound].play();
  };
};

"use strict";

function audio(url) {
  return new Audio(url);
}

const red = audio("https://s3.amazonaws.com/freecodecamp/simonSound1.mp3");
const blue = audio("https://s3.amazonaws.com/freecodecamp/simonSound2.mp3");
const green = audio("https://s3.amazonaws.com/freecodecamp/simonSound3.mp3");
const yellow = audio("https://s3.amazonaws.com/freecodecamp/simonSound4.mp3");
const error = audio("https://s3.amazonaws.com/adam-recvlohe-sounds/error.wav");

const sounds = {
  red: red,
  blue: blue,
  green: green,
  yellow: yellow,
  error: error
};

exports.play = function(sound) {
  return function() {
    sounds[sound].play();
  };
};

Add error sound to s3


/* @flow */
import React from 'react'

import createErrorComponent from './createErrorComponent'
import createValidation from '../createValidation'
import {
  assoc,
  assocPath,
  curry,
  map,
  prop,
} from 'ramda'

// default ErrorComponent
const DefaultErrorComponent = ({errorMsg}) =>
{errorMsg}

function Revalidation(
  initialState,
  validationRules,
  errorComponent,
  Component
) {

  const validate = createValidation(createErrorComponent(errorComponent || DefaultErrorComponent))

  return class extends React.Component {

    state: {
      form: Object,
      errors: Array<any>,
    }

    onChange: Function

    constructor(props) {
      super(props)
      this.state = initialState
      this.onChange = curry((name, value) =>
        this.setState(state => {
          const newState = assocPath(['form', name], value, state)
          const errors = validate(prop('form', newState), validationRules)
          return assoc('errors', errors, newState)
        })
      )
    }

    render() {
      const {form, errors} = this.state

      return (
        <Component
          {...this.props}
          form={form}
          errors={errors}
          onChange={this.onChange}
        />
      )
    }
  }
}

export default curry(Revalidation)

/* @flow */
import React from 'react'

import isValid from '../utils/isValid'
import createErrorComponent from './createErrorComponent'
import createValidation from '../createValidation'
import {
  assoc,
  assocPath,
  curry,
  prop
} from 'ramda'

// default ErrorComponent
const DefaultErrorComponent = ({errorMsg}) =>
{errorMsg}

function Revalidation(
  initialState,
  validationRules,
  errorComponent,
  Component
) {

  const validate = createValidation(createErrorComponent(errorComponent || DefaultErrorComponent))

  return class extends React.Component {

    state: {
      form: Object,
      errors: Array<any>,
    }

    onChange: Function

    constructor(props) {
      super(props)
      this.state = {form: props.form || initialState, errors: {}}
      this.onChange = this.onChange.bind(this)
    }

    onChange(name) {
      return value => this.setState(state => {
        const updatedState = assocPath(['form', name], value, state)
        const errors = validate(prop('form', updatedState), validationRules)
        return assoc('errors', errors, updatedState)
      })
    }

    validate(form) {
      this.setState(state => ({ ...state, ...this.validation(form)}))
    }

    render() {
      const {form, errors} = this.state
      const valid = isValid(validate(form, validationRules))

      return (
        <Component
          {...this.props}
          form={form}
          errors={errors}
          valid={valid}
          validate={this.onChange}
        />
      )
    }
  }
}

export default curry(Revalidation)

Add valid prop to React Higher Order Component


;(function() {
  var interval = 16;

  function Updater() {
    this.updatees = [];
    this.tick = interval;
    this.prev = new Date().getTime();

    var self = this;
    var update = function() {
      var now = new Date().getTime();
      self.tick = now - self.prev;
      self.prev = now;
      game.update(); // make sure game updated before everything else
      for (var i = 0; i < self.updatees.length; i++) {
        self.updatees[i].update();
      }

      window.requestAnimationFrame(update);
    };

    window.requestAnimationFrame(update);
  };

  Updater.prototype = {
    add: function(updatee) {
      this.updatees.push(updatee);
    },

    remove: function(updatee) {
      for(var i = 0; i < this.updatees.length; i++) {
        if(this.updatees[i] === updatee) {
          this.updatees.splice(i, 1);
          break;
        }
      }
    }
  };

  this.Updater = Updater;
}).call(this);

;(function() {
  var interval = 16;

  function Updater() {
    this.updatees = [];
    this.tick = interval;
    this.prev = new Date().getTime();

    var self = this;
    var requestAnimationFrame = window.requestAnimationFrame
        || window.mozRequestAnimationFrame
        || window.webkitRequestAnimationFrame;
    var update = function() {
      var now = new Date().getTime();
      self.tick = now - self.prev;
      self.prev = now;
      game.update(); // make sure game updated before everything else
      for (var i = 0; i < self.updatees.length; i++) {
        self.updatees[i].update();
      }

      requestAnimationFrame(update);
    };

    requestAnimationFrame(update);
  };

  Updater.prototype = {
    add: function(updatee) {
      this.updatees.push(updatee);
    },

    remove: function(updatee) {
      for(var i = 0; i < this.updatees.length; i++) {
        if(this.updatees[i] === updatee) {
          this.updatees.splice(i, 1);
          break;
        }
      }
    }
  };

  this.Updater = Updater;
}).call(this);

Check for prefixed versions of requestAnimationFrame


"use strict";

function logout() {
    $.ajax({
        url: '/logout',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({logout: true})
    }).done(function(data) {
        if (data)
            location.href = '/login';
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

function subscribe(userid, itemid) {
    $.ajax({
        url: '/subscribe',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({userId: userid, itemId: itemid})
    }).done(function(data) {
        if (data) {
            // TODO: indicate the success
            console.log("Successful subscription");
        }
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

function vote(userid, itemid, votevalue) {
    $.ajax({
        url: '/vote',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({userId: userid, itemId: itemid, voteValue: votevalue})
    }).done(function(data) {
        if (data) {
            // TODO: indicate the success
            console.log("Successful vote");
        }
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

"use strict";

function logout() {
    $.ajax({
        url: '/logout',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({logout: true})
    }).done(function(data) {
        if (data)
            location.href = '/login';
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

function subscribe(userid, itemid) {
    $.ajax({
        url: '/subscribe',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({userId: userid, itemId: itemid})
    }).done(function(data) {
        if (data) {
            // TODO: indicate the success
            console.log("Successful subscription");
        }
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

function vote(itemid, votevalue) {
    $.ajax({
        url: '/vote',
        type: 'POST',
        contentType: 'application/json',
        data: JSON.stringify({itemId: itemid, voteValue: votevalue})
    }).done(function(data) {
        if (data) {
            // TODO: indicate the success
            console.log("Successful vote");
        }
        else {
            // TODO: display some error message
            console.log(data);
        }
    }).fail(function(err) {
        console.error(err);
    });
}

Remove userid from vote function


// Cascading config (merges with parent config)
// http://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
module.exports = {
    "env": {
        "mocha": true
    },
    "extends": [
        "plugin:mocha/recommended"
    ],
    "parserOptions": {
        "ecmaVersion": 8,
    },
    "plugins": [
        "chai-expect",
        "mocha"
    ],
    "rules": {
        "mocha/no-hooks-for-single-case": ["off"],
        "mocha/no-top-level-hooks"      : ["off"],
        "mocha/no-setup-in-describe"    : ["off"]
    }
};

// Cascading config (merges with parent config)
// http://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
module.exports = {
    "env": {
        "mocha": true
    },
    "extends": [
        "plugin:mocha/recommended"
    ],
    "parserOptions": {
        "ecmaVersion": 8,
    },
    "plugins": [
        "chai-expect",
        "mocha"
    ],
    "rules": {
        "mocha/no-hooks-for-single-case": ["off"],
        "mocha/no-top-level-hooks"      : ["off"],
        "mocha/no-setup-in-describe"    : ["off"],
        "no-console"                    : ["off"]
    }
};

Disable eslint console warnings in test files


/*jshint node:true*/

module.exports = {
  useVersionCompatibility: true,
  scenarios: [{
    name: 'default',
    bower: {
      dependencies: {}
    }
  }, {
    name: 'ember-lts-2.4',
    bower: {
      dependencies: {
        'ember': 'components/ember#lts-2-4'
      },
      resolutions: {
        'ember': 'lts-2-4'
      }
    }
  }, {
    name: 'ember-release',
    bower: {
      dependencies: {
        'ember': 'components/ember#release'
      },
      resolutions: {
        'ember': 'release'
      }
    }
  }, {
    name: 'ember-beta',
    allowedToFail: true,
    bower: {
      dependencies: {
        'ember': 'components/ember#beta'
      },
      resolutions: {
        'ember': 'beta'
      }
    }
  }, {
    name: 'ember-canary',
    allowedToFail: true,
    bower: {
      dependencies: {
        'ember': 'components/ember#canary'
      },
      resolutions: {
        'ember': 'canary'
      }
    }
  }]
};

/*jshint node:true*/

module.exports = {
  useVersionCompatibility: true,
  scenarios: [{
    name: 'default',
    bower: {
      dependencies: {}
    }
  }, {
    name: 'ember-lts-2.4',
    bower: {
      dependencies: {
        'ember': 'components/ember#lts-2-4'
      },
      resolutions: {
        'ember': 'lts-2-4'
      }
    }
  }, {
  }, {
    name: 'ember-2.6.2',
    allowedToFail: true
  }, {
  }, {
    name: 'ember-2.7.3',
    allowedToFail: true
  }, {
    name: 'ember-release',
    bower: {
      dependencies: {
        'ember': 'components/ember#release'
      },
      resolutions: {
        'ember': 'release'
      }
    }
  }, {
    name: 'ember-beta',
    allowedToFail: true,
    bower: {
      dependencies: {
        'ember': 'components/ember#beta'
      },
      resolutions: {
        'ember': 'beta'
      }
    }
  }, {
    name: 'ember-canary',
    allowedToFail: true,
    bower: {
      dependencies: {
        'ember': 'components/ember#canary'
      },
      resolutions: {
        'ember': 'canary'
      }
    }
  }]
};

Allow 2.6 and 2.7 failures


var baseConfig = require('./webpack.config.common.js');
var webpack = require('webpack');
const merge = require('webpack-merge');
var path = require('path');

var CopyWebpackPlugin = require('copy-webpack-plugin');
var OfflinePlugin = require('offline-plugin');

module.exports = merge(baseConfig, {
  output: {
    path: path.resolve(__dirname, './dist/static/'),
    filename: 'js/[name]-bundle.[chunkhash].js'
  },
  plugins: [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        screw_ie8: true,
        warnings: false,
      },
      // mangle brakes angular.
      mangle: false,
      output: {
        screw_ie8: true
      },
      exclude: [/\.min\.js$/gi]
    }),
    // it's always better if OfflinePlugin is the last plugin added
    new OfflinePlugin(),
  ],
});

var baseConfig = require('./webpack.config.common.js');
var webpack = require('webpack');
const merge = require('webpack-merge');
var path = require('path');

var OfflinePlugin = require('offline-plugin');

module.exports = merge(baseConfig, {
  output: {
    path: path.resolve(__dirname, './dist/static/'),
    filename: 'js/[name]-bundle.[chunkhash].js'
  },
  plugins: [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        screw_ie8: true,
        warnings: false,
      },
      // mangle brakes angular.
      mangle: false,
      output: {
        screw_ie8: true
      },
      exclude: [/\.min\.js$/gi]
    }),
    // it's always better if OfflinePlugin is the last plugin added
    new OfflinePlugin({
      ServiceWorker: {
        output: '../sw.js',
      },
    }),
  ],
});

Copy service worker to root path.


import { CONNECT, GET_CURRENT_USER_SUCCESS } from './actionTypes'
import { combineReducers } from 'redux'

let isNewLoginValue = false
export const nuxeoReducer = combineReducers({
  connect: (state = { isConnected: false }, action = {}) => {
    switch (action.type) {
      case CONNECT:
        return {
          ...state,
          isConnected: true,
          client: action.client,
        }
      default: // NOTE: do nothing
    }
    return { state } // NOTE: should this be `return state`?
  },

  computeLogin: (
    state = {
      isFetching: false,
      response: {
        get: () => {
          return ''
        },
      },
      success: false,
    },
    action = {}
  ) => {
    switch (action.type) {
      case GET_CURRENT_USER_SUCCESS: {
        const newLoginValue = isNewLoginValue
        isNewLoginValue = false
        return {
          ...state,
          response: action.user,
          isFetching: false,
          success: true,
          isConnected: !action.isAnonymous,
          isNewLogin: newLoginValue,
        }
      }

      default:
        return { ...state, isFetching: false }
    }
  },
})

import { CONNECT, GET_CURRENT_USER_SUCCESS } from './actionTypes'
import { combineReducers } from 'redux'

let isNewLoginValue = false
export const nuxeoReducer = combineReducers({
  connect: (state = { isConnected: false }, action = {}) => {
    switch (action.type) {
      case CONNECT:
        return {
          ...state,
          isConnected: true,
          client: action.client,
        }
      default:
        return state
    }
  },

  computeLogin: (
    state = {
      isFetching: false,
      response: {
        get: () => {
          return ''
        },
      },
      success: false,
    },
    action = {}
  ) => {
    switch (action.type) {
      case GET_CURRENT_USER_SUCCESS: {
        const newLoginValue = isNewLoginValue
        isNewLoginValue = false
        return {
          ...state,
          response: action.user,
          isFetching: false,
          success: true,
          isConnected: !action.isAnonymous,
          isNewLogin: newLoginValue,
        }
      }

      default:
        return { ...state, isFetching: false }
    }
  },
})

Fix bad return `return { state }` > `return state`


import React from 'react'
import Document, { Head, Main, NextScript } from 'next/document'
import stylesheet from '../styles/global.sass'

export default class MyDocument extends Document {
  static getInitialProps ({ renderPage }) {
    const {html, head} = renderPage()
    return { html, head }
  }

  render () {
    return (
      <html>
        <Head>
          <link rel='shortcut icon' type='image/x-icon' href='/static/assets/favicon.ico' />
          <style dangerouslySetInnerHTML={{ __html: stylesheet }} />
          <title>Next Boilerplate</title>
        </Head>
        <body>
          {this.props.customValue}
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}

import React from 'react'
import Document, { Head, Main, NextScript } from 'next/document'
import stylesheet from '../styles/global.sass'

export default class MyDocument extends Document {
  static getInitialProps ({ renderPage }) {
    const {html, head} = renderPage()
    return { html, head }
  }

  render () {
    return (
      <html>
        <Head>
          <style dangerouslySetInnerHTML={{ __html: stylesheet }} />
          <link rel='shortcut icon' type='image/x-icon' href='/static/assets/favicon.ico' />
          <link href='https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css' rel='stylesheet' integrity='sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN' crossOrigin='anonymous' />
          <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' integrity='sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u' crossOrigin='anonymous' />
          <title>Next Boilerplate</title>
        </Head>
        <body>
          {this.props.customValue}
          <Main />
          <NextScript />
        </body>
      </html>
    )
  }
}

Add fontawesome and bootstrap css


var rpcRequest = require('./rpc-request');
require('./polyfills');

var DropboxApi = function (options) {
  this.accessToken = options && options.accessToken || '';
};

DropboxApi.prototype.setAccessToken = function (accessToken) {
  this.accessToken = accessToken;
};

DropboxApi.prototype.getAccessToken = function () {
  return this.accessToken;
};

DropboxApi.prototype.listFolder = function (path) {
  return rpcRequest('files/list_folder', { path: path }, this.getAccessToken());
};

module.exports = DropboxApi;

var rpcRequest = require('./rpc-request');
require('./polyfills');

var DropboxApi = function (options) {
  this.accessToken = options && options.accessToken || '';
};

DropboxApi.prototype.setAccessToken = function (accessToken) {
  this.accessToken = accessToken;
};

DropboxApi.prototype.getAccessToken = function () {
  return this.accessToken;
};

/**
 * Returns the contents of a folder.
 * @param {Object} params - The requests parameters
 * @param {string} params.path - The path to the folder you want to see the contents of.
 * @param {boolean} [params.recursive=false] - If true, the list folder operation will be applied recursively to all subfolders and the response will contain contents of all subfolders.
 * @param {boolean} [params.include_media_info=false] - If true, FileMetadata.media_info is set for photo and video.
 * @param {boolean} [params.include_deleted=false] - If true, the results will include entries for files and folders that used to exist but were deleted.
 * @returns {Object}
 * */
DropboxApi.prototype.listFolder = function (params) {
  return rpcRequest('files/list_folder', params, this.getAccessToken());
};

module.exports = DropboxApi;

Add JSDocs populated from website documentation


import React from 'react'
import Link from 'gatsby-link'
import Section from '../components/Section'
import HomeBanner from '../components/HomeBanner'
import About from '../components/About'
import Skills from '../components/Skills'
import Portfolio from '../components/Portfolio'
import Contact from '../components/Contact'

import { Element } from 'react-scroll'

const IndexPage = () =>

      <Element name="home">
        <HomeBanner />
      </Element>

      <Element name="about">
        <About />
      </Element>

      <Skills />

      <Element name="portfolio">
        <Portfolio />
      </Element>

      <Element name="contact">
        <Contact />
      </Element>

export default IndexPage

Fix section scrolling inside padding


export function isStateless(component) {
  return !component.prototype.render;
}

export function isStateless(component) {
  // `function() {}` has prototype, but `() => {}` doesn't
  // `() => {}` via Babel has prototype too.
  return !(component.prototype && component.prototype.render);
}

Fix isStateless check for native arrow func


import File from '../lib/File';

import NexmoStub from './NexmoStub';

var fileAPIs = {
    'getFile': 'get'
};

describe('File Object', function() {

    it('should implement all v1 APIs', function() {
        NexmoStub.checkAllFunctionsAreDefined(fileAPIs, File);
    });

    it('should proxy the function call to the underlying `nexmo` object', function() {
        NexmoStub.checkAllFunctionsAreCalled(fileAPIs, File);
    });
});

import FilesResource from '../lib/FilesResource';

import NexmoStub from './NexmoStub';

var fileAPIs = {
    'getFile': 'get'
};

describe('FilesResource Object', function() {

    it('should implement all v1 APIs', function() {
        NexmoStub.checkAllFunctionsAreDefined(fileAPIs, FilesResource);
    });

    it('should proxy the function call to the underlying `nexmo` object', function() {
        NexmoStub.checkAllFunctionsAreCalled(fileAPIs, FilesResource);
    });
});

Update test to load correct file


const assert = require('assert');
const configMergeLoader = require('../index.js');

describe('Config Merge Loader', function() {
  it('should return a function', function() {
    assert.equal(typeof configMergeLoader, 'function');
  });

  describe('when called', function() {
    const loaderInput = 'Loader Content';

    it('should return as string', function() {
      const loaderResult = configMergeLoader(loaderInput);
      assert.equal(typeof loaderResult, 'string');
    });

    it('should return the same string it is given', function() {
      const loaderResult = configMergeLoader(loaderInput);
      assert.ok(loaderResult.indexOf(loaderInput) >= 0);
    });
  });
});

const assert = require('assert');
const configMergeLoader = require('../index.js');
const fs = require('fs');
const webpack = require('webpack');

describe('Config Merge Loader', function() {
  it('should return a function', function() {
    assert.equal(typeof configMergeLoader, 'function');
  });

  describe('when called', function() {
    const loaderInput = 'Loader Content';

    it('should return as string', function() {
      const loaderResult = configMergeLoader(loaderInput);
      assert.equal(typeof loaderResult, 'string');
    });

    it('should return the same string it is given', function() {
      const loaderResult = configMergeLoader(loaderInput);
      assert.ok(loaderResult.indexOf(loaderInput) >= 0);
    });
  });

  describe('when called via webapck', function() {
    it('should generate an entry.js file', function() {
      assert.ok(fs.existsSync('./dist/entry.js'));
    });
  });
});

Test for existence of generated file


var Brew = require('./brew');
var expect = require('chai').expect;

describe('Brew model', function() {
  describe('get actual phase', function() {
    it('should find the phase in progress', function() {
      var brew = new Brew({
        name: 'Very IPA',
        startDate: new Date(),
        phases: [{
          min: 10,
          temp: 50,
          status: 'active'
        }, {
          min: 20,
          temp: 70,
          status: 'scheduled'
        }]
      });

      var actual = brew.getActualPhase();
      expect(actual).to.be.eql({
        min: 10,
        temp: 50,
        status: 'active'
      });
    });

    it('should handle when there is no phase in progress', function() {
      var brew = new Brew({
        name: 'Very IPA',
        startDate: new Date(),
        phases: [{
          min: 10,
          temp: 50,
          status: 'scheduled'
        }, {
          min: 20,
          temp: 70,
          status: 'scheduled'
        }]
      });

      var actual = brew.getActualPhase();
      expect(actual).to.be.undefined;
    });
  });
});

var Brew = require('./brew');
var BrewPhase = require('./BrewPhase');
var expect = require('chai').expect;

describe('Brew model', function() {
  describe('get actual phase', function() {
    it('should find the phase in progress', function() {
      var actualPhase = new BrewPhase({
        min: 10,
        temp: 50,
        status: 'active'
      });

      var scheduledPhase = new BrewPhase({
        min: 20,
        temp: 70,
        status: 'scheduled'
      });

      var brew = new Brew({
        name: 'Very IPA',
        startDate: new Date(),
        phases: [actualPhase, scheduledPhase]
      });

      var actual = brew.getActualPhase();
      expect(actual).to.be.eql(actualPhase);
    });

    it('should handle when there is no phase in progress', function() {
      var scheduledPhase1 = new BrewPhase({
        min: 10,
        temp: 50,
        status: 'scheduled'
      });

      var scheduledPhase2 = new BrewPhase({
        min: 20,
        temp: 70,
        status: 'scheduled'
      });

      var brew = new Brew({
        name: 'Very IPA',
        startDate: new Date(),
        phases: [scheduledPhase1, scheduledPhase2]
      });

      var actual = brew.getActualPhase();
      expect(actual).to.be.undefined;
    });
  });
});

Use BrewPhase in Brew tests


// Third party
import localForage from 'localForage';
import { applyMiddleware, compose, createStore } from 'redux';
import { autoRehydrate, persistStore, purgeStoredState } from 'redux-persist';
import thunk from 'redux-thunk';
// import freeze from 'redux-freeze';
import undoable, { ActionCreators } from 'redux-undo';

import appReducer from 'app-reducer';

const CONFIG = {
  storage: localForage,
  debounce: 75,
  keyPrefix: 'matrixDecompositionMethods.'
};

export default class States {
  constructor () {
    this.store = createStore(
      undoable(appReducer),
      undefined,
      compose(
        autoRehydrate(),
        applyMiddleware(thunk),
        // applyMiddleware(freeze)
      )
    );

    persistStore(this.store, CONFIG, (err, state) => {
      // Rehydration is done
      this.isRehydrated = Object.keys(true).length > 0;
    });
  }

  undo () {
    this.store.dispatch(ActionCreators.undo());
  }

  redo () {
    this.store.dispatch(ActionCreators.redo());
  }

  reset () {
    return purgeStoredState(CONFIG);
  }
}

// Third party
import localforage from 'localForage';
import { applyMiddleware, compose, createStore } from 'redux';
import { autoRehydrate, persistStore, purgeStoredState } from 'redux-persist';
import thunk from 'redux-thunk';
// import freeze from 'redux-freeze';
import undoable, { ActionCreators } from 'redux-undo';

import appReducer from 'app-reducer';

const CONFIG = {
  storage: localforage,
  debounce: 75,
  keyPrefix: 'matrixDecompositionMethods.'
};

export default class States {
  constructor () {
    this.store = createStore(
      undoable(appReducer),
      undefined,
      compose(
        autoRehydrate(),
        applyMiddleware(thunk),
        // applyMiddleware(freeze)
      )
    );

    persistStore(this.store, CONFIG, (err, state) => {
      // Rehydration is done
      this.isRehydrated = Object.keys(true).length > 0;
    });
  }

  undo () {
    this.store.dispatch(ActionCreators.undo());
  }

  redo () {
    this.store.dispatch(ActionCreators.redo());
  }

  reset () {
    return purgeStoredState(CONFIG);
  }
}

Make naming consistent with MDN


"use strict";

angular.module('arethusa.morph').directive('mirrorMorphForm', [
  'morph',
  '$location',
  '$anchorScroll',
  function(morph, $location, $anchorScroll) {
    return {
      restrict: 'A',
      scope: {
        form: '=mirrorMorphForm',
        tokenId: '='
      },
      link: function(scope, element, attrs) {
        var morphToken = morph.analyses[scope.tokenId];
        var menuId = 'mfc' + scope.tokenId;

        function newCustomForm() {
          var form = angular.copy(scope.form);

          // We might want to clean up even more here - such as the
          // lexical inventory information. Revisit later.
          delete form.origin;

          return form;
        }

        element.bind('click', function() {
          scope.$apply(morphToken.customForm = newCustomForm());
          $location.hash(menuId);
          angular.element(document.getElementById(menuId)).removeClass('hide');
          $anchorScroll();
        });
      }
    };
  }
]);

"use strict";

angular.module('arethusa.morph').directive('mirrorMorphForm', [
  'morph',
  '$location',
  '$anchorScroll',
  function(morph, $location, $anchorScroll) {
    return {
      restrict: 'A',
      scope: {
        form: '=mirrorMorphForm',
        tokenId: '='
      },
      link: function(scope, element, attrs) {
        var morphToken = morph.analyses[scope.tokenId];
        var menuId = 'mfc' + scope.tokenId;

        function newCustomForm() {
          var form = angular.copy(scope.form);

          // We might want to clean up even more here - such as the
          // lexical inventory information. Revisit later.
          delete form.origin;

          return form;
        }

        element.bind('click', function() {
          scope.$apply(morphToken.customForm = newCustomForm());
          $location.hash(menuId);
          angular.element(document.getElementById(menuId)).removeClass('hide');

          // Sadly doesn't have any smooth scroll capabilities - we might have to
          // change this implementation at some point.
          $anchorScroll();
        });
      }
    };
  }
]);

Add comment about possible smoothScrolling in mMF


import supertest from 'supertest';
import proxyquire from 'proxyquire';
import fakeServices from '../fake/services';
import fakeProviders from '../fake/providers';

export default function request(stubs) {
  const services = {
    ...fakeServices(stubs),
    '@global': true,
  };

  const providers = {
    getProvider() {
      return fakeProviders(stubs);
    },
    '@global': true,
    '@noCallThru': true,
  };

  const app = proxyquire('../../src/app', {
    './services': services,
    '../services': services,
    '../../services': services,
    './providers': providers,
    '../providers': providers,
    '../../providers': providers,
  });

  return supertest(app);
}

import supertest from 'supertest';
import proxyquire from 'proxyquire';
import fakeServices from '../fake/services';
import fakeProviders from '../fake/providers';

export default function request(stubs) {
  const services = {
    ...fakeServices(stubs),
    '@global': true,
    '@noCallThru': true,
  };

  const providers = {
    getProvider() {
      return fakeProviders(stubs);
    },
    '@global': true,
    '@noCallThru': true,
  };

  const app = proxyquire('../../src/app', {
    './services': services,
    '../services': services,
    '../../services': services,
    './providers': providers,
    '../providers': providers,
    '../../providers': providers,
  });

  return supertest(app);
}

Disable call thru in fake service.


'use strict';

const { getReason } = require('../../error');
const { MODEL_TYPES } = require('../../constants');
const { defaultFormat } = require('../../formats');

// Builds requestinfo from request mInput
const buildRequestinfo = function ({
  requestid,
  timestamp,
  responsetime,
  ip,
  protocol,
  url,
  origin,
  path,
  method,
  protocolstatus,
  status = 'SERVER_ERROR',
  pathvars,
  queryvars,
  requestheaders,
  responseheaders,
  format: { name: format = 'raw' } = defaultFormat,
  charset,
  payload,
  rpc,
  summary,
  topargs: args,
  commandpath,
  command,
  collname: collection,
  response: {
    content: response,
    type: responsetype,
  } = {},
  modelscount,
  uniquecount,
  error,
}) {
  const responsedata = MODEL_TYPES.includes(responsetype)
    ? response.data
    : response;
  const errorReason = error && getReason({ error });

  return {
    requestid,
    timestamp,
    responsetime,
    ip,
    protocol,
    url,
    origin,
    path,
    method,
    protocolstatus,
    status,
    pathvars,
    queryvars,
    requestheaders,
    responseheaders,
    format,
    charset,
    payload,
    rpc,
    summary,
    args,
    commandpath,
    command,
    collection,
    responsedata,
    responsetype,
    modelscount,
    uniquecount,
    error: errorReason,
  };
};

module.exports = {
  buildRequestinfo,
};

'use strict';

const { getReason } = require('../../error');
const { MODEL_TYPES } = require('../../constants');
const { defaultFormat } = require('../../formats');

// Builds requestinfo from request mInput
const buildRequestinfo = function ({
  requestid,
  timestamp,
  responsetime,
  ip,
  protocol,
  url,
  origin,
  path,
  method,
  protocolstatus,
  status = 'SERVER_ERROR',
  pathvars,
  queryvars,
  requestheaders,
  responseheaders,
  format: { name: format = 'raw' } = defaultFormat,
  charset,
  payload,
  rpc,
  summary,
  topargs: args,
  commandpath,
  command,
  collname: collection,
  metadata,
  response: {
    content: response,
    type: responsetype,
  } = {},
  modelscount,
  uniquecount,
  error,
}) {
  const responsedata = MODEL_TYPES.includes(responsetype)
    ? response.data
    : response;
  const errorReason = error && getReason({ error });

  return {
    requestid,
    timestamp,
    responsetime,
    ip,
    protocol,
    url,
    origin,
    path,
    method,
    protocolstatus,
    status,
    pathvars,
    queryvars,
    requestheaders,
    responseheaders,
    format,
    charset,
    payload,
    rpc,
    summary,
    args,
    commandpath,
    command,
    collection,
    responsedata,
    responsetype,
    metadata,
    modelscount,
    uniquecount,
    error: errorReason,
  };
};

module.exports = {
  buildRequestinfo,
};

Add metadata to event payloads


module.exports = (sequelize, DataTypes) => {
  const UserGroup = sequelize.define('UserGroup', {
    userId: {
      type: DataTypes.INTEGER,
      allowNull: false
    },
    groupId: {
      type: DataTypes.INTEGER,
      allowNull: false
    },
  }, {
    timestamps: false
  });
  return UserGroup;
};

module.exports = (sequelize, DataTypes) => {
  const UserGroup = sequelize.define('UserGroup', {
    userId: {
      type: DataTypes.INTEGER,
      allowNull: false
    },
    groupId: {
      type: DataTypes.INTEGER,
      allowNull: false
    },
  }, {
    classMethods: {
      associate: (models) => {
        UserGroup.belongsTo(models.Group, { foreignKey: 'groupId' });
        UserGroup.belongsTo(models.User, { foreignKey: 'userId' });
      }
    },
    timestamps: false
  });
  return UserGroup;
};

Modify Server side model to work well with client


var set = Ember.set;

Ember.onLoad('application', function(app) {
  app.registerInjection(function(app, stateManager, property) {
    if (property === 'Store') {
      set(stateManager, 'store', app[property].create());
    }
  });
});

var set = Ember.set;

Ember.onLoad('application', function(app) {
  app.registerInjection({
    name: "store",
    before: "controllers",

    injection: function(app, stateManager, property) {
      if (property === 'Store') {
        set(stateManager, 'store', app[property].create());
      }
    }
  });
});

Update to new injection syntax


define(['rules/rules.module'
       ],
function() {
    angular.module('rules').factory('references',
    [
    function() {
        function generateReference(query) {
            var bindings = {};

            angular.forEach(query.bindings, function(binding) {
                if (('id' in binding) && ('name' in binding))  {
                    bindings[binding.name] = binding.id;
            });

            var info = { rule: query.rule,
                         query: query.query,
                         bindings: bindings,
                         constraints: query.constraints
            };
            var url = ('#/rules/explain?inference=' +
                       encodeURIComponent(angular.toJson(info, false)));
            var reference = { P854: [{ datatype: 'url',
                                       datavalue: { type: 'string',
                                                    value: url,
                                                    __sqid_display_string_override__: '(explain inference)'
                                                  },
                                       snaktype: 'value',
                                       property: 'P854'
                                     }]
                            };

            return [{ snaks: reference,
                      'snaks-order': ['P854']
                    }];
        }

        return { generateReference: generateReference
               };
    }]);

    return {};
});

define(['rules/rules.module'
       ],
function() {
    angular.module('rules').factory('references',
    ['ast',
    function(ast) {
        function generateReference(query) {
            var bindings = {};

            angular.forEach(query.bindings, function(binding) {
                if (('id' in binding) && ('name' in binding))  {
                    bindings[binding.name] = binding.id;
                }
            });

            angular.forEach(ast.variables(query.rule.head), function(variable) {
                var name = variable.name;
                bindings[name] = { id: query.bindings[name].id,
                                   type: query.bindings[name].type,
                                   qualifiers: query.bindings[name].qualifiers
                                 };
            });

            var info = { rule: query.rule,
                         query: query.query,
                         bindings: bindings,
                         constraints: query.constraints
            };
            var url = ('#/rules/explain?inference=' +
                       encodeURIComponent(angular.toJson(info, false)));
            var reference = { P854: [{ datatype: 'url',
                                       datavalue: { type: 'string',
                                                    value: url,
                                                    __sqid_display_string_override__: '(explain inference)'
                                                  },
                                       snaktype: 'value',
                                       property: 'P854'
                                     }]
                            };

            return [{ snaks: reference,
                      'snaks-order': ['P854']
                    }];
        }

        return { generateReference: generateReference
               };
    }]);

    return {};
});

Include qualifiers on reference generation


"use strict";

var obj = { size: 20 };

// @boop(obj, "blue", true)
export default function CustomStuff() {
    this.showSomethign = () => {
        console.log("show something!");
    };
}

console.log(obj); // To make jshint happy.

Make jshint happy w/ unused var in sample module.


import { NativeModules } from 'react-native'

let RNPS = NativeModules.RNPasscodeStatus

// written out for clarity
const { supported, status, get } = RNPS
export default { supported, status, get }

import { NativeModules } from 'react-native'

let RNPS = NativeModules.RNPasscodeStatus

// written out for clarity
// { supported, status, get } = RNPS
export default RNPS

Remove unnecessary destructure to fix Jest tests


"use strict";

module.exports = function(graph) {
  return {
    V: createVertexStream
  };
}

function createVertexStream(startFrom) {
  var VertexStream = require('./lib/vertexStream');
  return new VertexStream(graph, startFrom);
}

"use strict";

module.exports = function(graph) {
  return {
    V: function createVertexStream(startFrom) {
      var VertexStream = require('./lib/vertexStream');
      return new VertexStream(graph, startFrom);
    }
  };
};

Put vertext stream back where it was


'use strict';

var path = require('path');
var taskOpts = require('./lib/tasks.js');

module.exports = function(kbox) {

  var events = kbox.core.events;
  var engine = kbox.engine;

  kbox.ifApp(function(app) {

    // Grab the clients
    var Git = require('./lib/git.js');
    var git = new Git(kbox, app);

    // Events
    // Install the util container for our things
    events.on('post-install', function(app, done) {
      var opts = {
        name: 'git',
        srcRoot: path.resolve(__dirname)
      };
      engine.build(opts, done);
    });

    // Tasks
    // git wrapper: kbox git COMMAND
    kbox.tasks.add(function(task) {
      task.path = [app.name, 'git'];
      task.description = 'Run git commands.';
      task.kind = 'delegate';
      task.options.push(taskOpts.gitUsername);
      task.options.push(taskOpts.gitEmail);
      task.func = function(done) {
        // We need to use this faux bin until the resolution of
        // https://github.com/syncthing/syncthing/issues/1056
        git.cmd(this.payload, this.options, done);
      };
    });

  });

};

'use strict';

var path = require('path');
var taskOpts = require('./lib/tasks.js');

module.exports = function(kbox) {

  var events = kbox.core.events;
  var engine = kbox.engine;

  kbox.ifApp(function(app) {

    // Grab the clients
    var Git = require('./lib/git.js');
    var git = new Git(kbox, app);

    // Events
    // Install the util container for our things
    events.on('post-install', function(app, done) {
      var opts = {
        name: 'git',
        srcRoot: path.resolve(__dirname)
      };
      engine.build(opts, done);
    });

    // Tasks
    // git wrapper: kbox git COMMAND
    kbox.tasks.add(function(task) {
      task.path = [app.name, 'git'];
      task.category = 'appAction';
      task.description = 'Run git commands.';
      task.kind = 'delegate';
      task.options.push(taskOpts.gitUsername);
      task.options.push(taskOpts.gitEmail);
      task.func = function(done) {
        // We need to use this faux bin until the resolution of
        // https://github.com/syncthing/syncthing/issues/1056
        git.cmd(this.payload, this.options, done);
      };
    });

  });

};

Add git command to appAction category


//
// Metric Logger
//
// Scrapes various data sources and visualizes
// collected data in a web ui.

const apiEndpoints = ["github.js", "explorer.js"]
const data = require("./datalogger.js").init(apiEndpoints)
const express = require("express")
const app = express()
const process = require("process")

const PORT = process.env.SIA_METRIC_PORT || 8080

//Servers static files.
app.use(express.static("public"))
app.use("/charts/", express.static("node_modules/chart.js/dist/"))
app.use("/js/moment.js", express.static("node_modules/moment/moment.js"))
app.use("/js/bignumber.js", express.static("node_modules/bignumber.js/bignumber.js"))

//Data endpoint.
app.get("/data", (req, res) => {
    if (req.query.callback){
        res.send(`function ${req.query.callback}(callback){
            callback(${JSON.stringify(data.latest(req.query.length))})
        }`)
    } else {
        res.send(JSON.stringify(data.latest(req.query.length)))
    }
})

app.listen(PORT, () =>
    console.log(`Running server on port ${PORT}`)
)

//data.startLogging()

//
// Metric Logger
//
// Scrapes various data sources and visualizes
// collected data in a web ui.

const apiEndpoints = ["github.js", "explorer.js"]
const data = require("./datalogger.js").init(apiEndpoints)
const express = require("express")
const app = express()
const process = require("process")

const PORT = process.env.SIA_METRIC_PORT || 8080

//Servers static files.
app.use(express.static("public"))
app.use("/charts/", express.static("node_modules/chart.js/dist/"))
app.use("/js/moment.js", express.static("node_modules/moment/moment.js"))
app.use("/js/bignumber.js", express.static("node_modules/bignumber.js/bignumber.js"))

//Data endpoint.
app.get("/data", (req, res) => {
    if (req.query.callback){
        res.send(`function ${req.query.callback}(callback){
            callback(${JSON.stringify(data.latest(req.query.length))})
        }`)
    } else {
        res.send(JSON.stringify(data.latest(req.query.length)))
    }
})

app.listen(PORT, () =>
    console.log(`Running server on port ${PORT}`)
)

data.startLogging()

Enable data collection by default


module.exports = {
    plugins: [
        'vue'
    ],
    extends: [
        'vast',
        'plugin:vue/recommended'
    ]
};

module.exports = {
    plugins: [
        'vue'
    ],
    extends: [
        'vast',
        'plugin:vue/recommended'
    ],
    rules: {
        // Possible errors:
        // this rule only covers case when used in code like: Vue.component...
        'vue/no-shared-component-data': 2,
        'vue/require-valid-default-prop': 2,

        // Best practices:
        'vue/html-end-tags': 2,
        'vue/no-async-in-computed-properties': 2,
        'vue/no-duplicate-attributes': 2,
        'vue/no-side-effects-in-computed-properties': 2,
        // this could be part of the Stylistic Issues
        'vue/order-in-components': 1

        // Stylistic Issues:
    }
};

Add common errors and best practices rules


module.exports = function oneliner(str) {
  return str.replace(/[\r\n\t ]+/g, ' ');
};

module.exports = function oneliner(str) {
  return (str.raw? str.raw[0] : str).replace(/[\r\n\t ]+/g, ' ');
};

Support calling oneliner with raw string


/* eslint-env node */
/** global: Buffer */
'use strict';

const gutil = require('gulp-util');
const through = require('through2');
const wpPot = require('wp-pot');

const PluginError = gutil.PluginError;

/**
 * Determine if `obj` is a object or not.
 *
 * @param  {object}  obj
 *
 * @return {boolean}
 */
function isObject (obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

/**
 * Run the wp pot generator.
 *
 * @param  {object} options
 *
 * @return {object}
 */
function gulpWPpot (options) {
  if (options !== undefined && !isObject(options)) {
    throw new PluginError('gulp-wp-pot', 'Require a argument of type object.');
  }

  let files = [];

  const stream = through.obj(function (file, enc, cb) {
    if (file.isStream()) {
      throw new PluginError('gulp-wp-pot', 'Streams are not supported.');
    }

    files.push(file.path);
    cb();
  }, function (cb) {
    if (!options) {
      options = {};
    }

    options.src = files;
    options.writeFile = false;

    const potContents = wpPot(options);

    const potFile = new gutil.File({
      contents: new Buffer(potContents)
    });

    this.push(potFile);
    cb();
  });

  return stream;
}

module.exports = gulpWPpot;

/* eslint-env node */
/** global: Buffer */
'use strict';

const gutil = require('gulp-util');
const through = require('through2');
const wpPot = require('wp-pot');

const PluginError = gutil.PluginError;

/**
 * Determine if `obj` is a object or not.
 *
 * @param  {object}  obj
 *
 * @return {boolean}
 */
function isObject (obj) {
  return Object.prototype.toString.call(obj) === '[object Object]';
}

/**
 * Run the wp pot generator.
 *
 * @param  {object} options
 *
 * @return {object}
 */
function gulpWPpot (options) {
  if (options !== undefined && !isObject(options)) {
    throw new PluginError('gulp-wp-pot', 'Require a argument of type object.');
  }

  let files = [];

  const stream = through.obj(function (file, enc, cb) {
    if (file.isStream()) {
      throw new PluginError('gulp-wp-pot', 'Streams are not supported.');
    }

    files.push(file.path);
    cb();
  }, function (cb) {
    if (!options) {
      options = {};
    }

    options.src = files;
    options.writeFile = false;

    const potContents = wpPot(options);

    const potFile = new gutil.File({
      contents: new Buffer(potContents),
      path: '.'
    });

    this.push(potFile);
    cb();
  });

  return stream;
}

module.exports = gulpWPpot;

Fix broken path for destination


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

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

app.use(express.static(__dirname + '/public'));

// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.get('/', function(request, response) {
  response.render('pages/index')
});

app.listen(app.get('port'), function() {
  console.log('Node app is running on port', app.get('port'));
});

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

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

app.use(express.static(__dirname + '/public'));

// views is directory for all template files
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

app.get('/', function(request, response) {
  response.render('pages/index');
});

app.listen(app.get('port'), function() {
  console.log('Node app is running on port', app.get('port'));
});

Add missing semicolon to express route handler


const Gitter = require('./gitter');
const Lexicon = require('./lexicon');

const client = new Gitter();

const activeRooms = {};

function listenAndReply(roomId) {
  if (activeRooms[roomId]) {
    return;
  } else {
    activeRooms[roomId] = true;
  }

  client.readChatMessages(roomId, (data) => {
    if (data.operation === 'create') {
      if (data.model.fromUser.id === process.env.GITTER_LEXICON_USER_ID) return;

      let prefix = '';
      let message = data.model.text;

      if (roomId === process.env.GITTER_ESOUI_ROOM_ID) {
        const match = message.match(/^@?lex(icon)?(\s(.+)|$)/);
        if (!match) return;
        prefix += `@${data.model.fromUser.username} `;
        message = match[3];
      }

      Lexicon.parse(message, (text) => {
        client.sendChatMessage(roomId, `${prefix}${text}`);
      });
    }
  });
}

client.watchRoomUpdates(process.env.GITTER_LEXICON_USER_ID, (message) => {
  const roomId = message.model.id;
  if (message.operation === 'create' || message.operation === 'patch') {
    if (message.operation === 'create') {
      Lexicon.parse('', (text) => {
        client.sendChatMessage(roomId, text);
      });
    }
    if (activeRooms.indexOf(roomId) < 0) {
      listenAndReply(roomId);
      activeRooms.push(roomId);
    }
  }
});

const Gitter = require('./gitter');
const Lexicon = require('./lexicon');

const client = new Gitter();

const activeRooms = {};

function listenAndReply(roomId) {
  if (activeRooms[roomId]) {
    return;
  } else {
    activeRooms[roomId] = true;
  }

  client.readChatMessages(roomId, (data) => {
    if (data.operation === 'create') {
      if (data.model.fromUser.id === process.env.GITTER_LEXICON_USER_ID) return;

      let prefix = '';
      let message = data.model.text;

      if (roomId === process.env.GITTER_ESOUI_ROOM_ID) {
        const match = message.match(/^@?lex(icon)?(\s(.+)|$)/);
        if (!match) return;
        prefix += `@${data.model.fromUser.username} `;
        message = match[3];
      }

      Lexicon.parse(message, (text) => {
        client.sendChatMessage(roomId, `${prefix}${text}`);
      });
    }
  });
}

client.watchRoomUpdates(process.env.GITTER_LEXICON_USER_ID, (message) => {
  const roomId = message.model.id;
  if (message.operation === 'create' || message.operation === 'patch') {
    if (message.operation === 'create') {
      Lexicon.parse('', (text) => {
        client.sendChatMessage(roomId, text);
      });
    }
    listenAndReply(roomId);
  }
});

Remove activeRooms check in watchRoomUpdates (was moved to readChatMessages)


var extend = require('extend')
var fs = require('fs')
var Handlebars = require('handlebars')

module.exports = plugin

function plugin (options) {
  options = extend({
    directory: 'helpers'
  }, options || {})

  return function (files, metalsmith, done) {
    fs.readdir(metalsmith.path(options.directory), function (err, files) {
      if (err) throw err

      files.forEach(function (file) {
        var helperContents
        var path
        var templateName

        path = metalsmith.path(options.directory, file)
        helperContents = require(path)

        switch (typeof helperContents) {
        case 'function':
          templateName = file.split('.').shift()
          Handlebars.registerHelper(templateName, helperContents)
          break
        case 'object':
          Handlebars.registerHelper(helperContents)
          break
        }
      })

      done()
    })
  }
}

var extend = require('extend')
var fs = require('fs')
var Handlebars = require('handlebars')

module.exports = plugin

function plugin (options) {
  options = extend({
    directory: 'helpers'
  }, options || {})

  return function (files, metalsmith, done) {
    fs.readdir(metalsmith.path(options.directory), function (err, files) {
      if (err) throw err

      files.forEach(function (file) {
        var helperContents
        var path
        var templateName

        path = metalsmith.path(options.directory, file)
        helperContents = require(path)

        switch (typeof helperContents) {
          case 'function':
            templateName = helperContents.name || file.split('.').shift()
            Handlebars.registerHelper(templateName, helperContents)
            break
          case 'object':
            Handlebars.registerHelper(helperContents)
            break
        }
      })

      done()
    })
  }
}

Change preferred templateName to helper methods name


var express = require('express');
var fs = require('fs');
var url = require('url');
var app = express.createServer();

app.use(express.static(__dirname + '/public'));
app.get('*', handleAnyRequest);
app.post('*', handleAnyRequest);
app.delete('*', handleAnyRequest);
app.put('*', handleAnyRequest);

var TEMPLATE_PATTERN = new RegExp(/{{.*}}/g);

function handleAnyRequest(req, res){
  reqUrl = url.parse(req.url);
  var file = 'json' + reqUrl.pathname + '_' + req.method.toLowerCase() + ".json";
  console.log('Request: ' + file);

  // TODO allow proxying calls to real API (for calls that are already implemented)
  var data = readFileJson(file);
  res.send(data)
}

function readFileJson(file) {
  var data = fs.readFileSync(file, 'utf8');

  data = data.replace(TEMPLATE_PATTERN, function(match) {
    // TODO: allow variables instead of templates like SERVER_BASE_URL
    // TODO: for templates, allow {{Template(1)}} to add variables that can be used in the template like: {{param[1]}}
    var templateFile = 'json/_templates/' + match.slice(2,-2) + ".json";
    return JSON.stringify(readFileJson(templateFile));
  } );

  return JSON.parse(data);
}

app.listen(80);

var express = require('express');
var fs = require('fs');
var url = require('url');
var app = express.createServer();

app.use(express.static(__dirname + '/public'));
app.get('*', handleAnyRequest);
app.post('*', handleAnyRequest);
app.delete('*', handleAnyRequest);
app.put('*', handleAnyRequest);

var TEMPLATE_PATTERN = new RegExp(/{{.*}}/g);

function handleAnyRequest(req, res){
  reqUrl = url.parse(req.url);
  var file = 'json' + reqUrl.pathname + '_' + req.method.toLowerCase() + ".json";
  console.log('Request: ' + file);

  // TODO allow proxying calls to real API (for calls that are already implemented)
  var data = readFileJson(file);
  res.send(data)
}

function readFileJson(file) {
  var data = fs.readFileSync(file, 'utf8');

  data = data.replace(TEMPLATE_PATTERN, function(match) {
    // TODO: allow variables instead of templates like SERVER_BASE_URL
    // TODO: for templates, allow {{Template(1)}} to add variables that can be used in the template like: {{param[1]}}
    var templateFile = 'json/_templates/' + match.slice(2,-2) + ".json";
    return JSON.stringify(readFileJson(templateFile));
  } );

  return JSON.parse(data);
}

app.listen(3000);

Switch port to 3000 so it can run without root priviledges. Use nginx if you want it on port 80


module.exports = {
  'extends': 'standard',

  'rules': {
    'brace-style'                : [2, '1tbs'],
    'eqeqeq'                     : [2, 'smart'],
    'comma-dangle'               : [2, 'always'],
    'consistent-return'          : [2],
    'key-spacing'                : [2, {'align': 'colon'}],
    'no-extra-semi'              : [2],
    'no-use-before-define'       : [2],
    'no-multi-spaces'            : [2, {exceptions: {'VariableDeclarator': true}}],
    'no-multiple-empty-lines'    : [2, {'max': 2}],
    'semi'                       : [2, 'always'],
    'semi-spacing'               : [2, { 'before': false, 'after': true }],
    'space-before-function-paren': [2, {'anonymous' : 'always', 'named' : 'never'}],
    'spaced-comment'             : [2, 'always', { exceptions: ['-']}],
    'wrap-iife'                  : [2, 'inside']
  }
}

module.exports = {
  'extends': 'standard',

  'rules': {
    'brace-style'                : [2, '1tbs'],
    'eqeqeq'                     : [2, 'smart'],
    'comma-dangle'               : [0],
    'consistent-return'          : [2],
    'indent'                     : [2, 2, { 'SwitchCase': 1 }],
    'key-spacing'                : [2, {'align': 'colon'}],
    'no-extra-semi'              : [2],
    'no-use-before-define'       : [2],
    'no-multi-spaces'            : [2, {exceptions: {'VariableDeclarator': true}}],
    'no-multiple-empty-lines'    : [2, {'max': 2}],
    'semi'                       : [2, 'always'],
    'semi-spacing'               : [2, { 'before': false, 'after': true }],
    'space-before-function-paren': [2, {'anonymous' : 'always', 'named' : 'never'}],
    'spaced-comment'             : [2, 'always', { exceptions: ['-']}],
    'strict'                     : [2, 'global'],
    'wrap-iife'                  : [2, 'inside']
  },

  "ecmaFeatures": {
    "modules": false
  }
}

Tweak rules, turn modules off


import { getSelectedAlgorithm } from './utils.js';
import {
  secretInput,
  secretBase64Checkbox,
} from '../dom-elements.js';

import log from 'loglevel';
import tippy from 'tippy.js';
import b64u from 'base64url';

export function minSecretLengthCheck(event) {
  const alg = getSelectedAlgorithm();
  if(alg.indexOf('HS') !== 0) {
    log.error(`Secret input tooltip handler for wrong algorithm: ${alg}`);
    return;
  }

  const algBits = parseInt(alg.substr(2));
  const inputBits = secretBase64Checkbox.checked ?
    b64u.decode(secretInput.value).length * 8 :
    Buffer.from(secretInput.value).length * 8;

  if(inputBits < algBits) {
    if(!secretInput._tippy.state.visible) {
      secretInput._tippy.show();
    }
  } else {
    secretInput._tippy.hide();
  }
}

export function setupSecretLengthTooltip() {
  tippy(secretInput, {
    trigger: 'manual',
    placement: 'right',
    arrow: true,
    arrowTransform: 'scale(0.75)',
    size: 'large'
  });
}

import { getSelectedAlgorithm } from "./utils.js";
import { secretInput, secretBase64Checkbox } from "../dom-elements.js";

import log from "loglevel";
import tippy from "tippy.js";
import b64u from "base64url";

export function minSecretLengthCheck(event) {
    const alg = getSelectedAlgorithm();
    if (alg.indexOf("HS") !== 0) {
        log.error(`Secret input tooltip handler for wrong algorithm: ${alg}`);
        return;
    }

    const algBits = parseInt(alg.substr(2));
    const inputBits = secretBase64Checkbox.checked ?
        b64u.toBuffer(secretInput.value).length * 8 :
        Buffer.from(secretInput.value).length * 8;

    if (inputBits < algBits) {
        if (!secretInput._tippy.state.visible) {
            secretInput._tippy.show();
        }
    } else {
        secretInput._tippy.hide();
    }
}

export function setupSecretLengthTooltip() {
    tippy(secretInput, {
        trigger: "manual",
        placement: "right",
        arrow: true,
        arrowTransform: "scale(0.75)",
        size: "large",
    });
}

Fix Base64 encoded secret length check


import React, {Component} from 'react';

export default class NotFound extends Component {
  render() {
    return (

Doh! 404!

These are not the droids you are looking for!

    );
  }
}

import React from 'react';

export default function NotFound() {
  return (

Doh! 404!

These are not the droids you are looking for!

  );
}

Make stateless components simple functions


'use strict';

require('require');
require('prototype_creep_startup_tasks');
require('prototype_creep_move');
require('prototype_roomPosition');
require('prototype_room_init');
require('prototype_room_costmatrix');
require('visualizer');
require('screepsplus');

if (config.profiler.enabled) {
  try {
    var profiler = require('screeps-profiler');
    profiler.enable();
  } catch (e) {
    console.log('screeps-profiler not found');
    config.profiler.enabled = false;
  }
}
brain.stats.init();

var main = function() {
  if (Game.cpu.bucket < Game.cpu.tickLimit * 2) {
    console.log('Skipping tick ' + Game.time + ' due to lack of CPU.');
    return;
  }

  brain.prepareMemory();
  brain.handleNextroom();
  brain.handleSquadmanager();
  brain.handleIncomingTransactions();
  brain.stats.addRoot();
  Memory.myRooms = _.map(_.filter(Game.rooms, r => r.execute()), r => r.name);

  if (config.visualizer.enabled && config.visualizer.refresh) {
    visualizer.render();
  }
  brain.stats.add(['cpu'], {
    used: Game.cpu.getUsed()
  });
};

module.exports.loop = function() {
  if (config.profiler.enabled) {
    profiler.wrap(function() {
      main();
    });
  } else {
    main();
  }
};

'use strict';

require('require');
require('prototype_creep_startup_tasks');
require('prototype_creep_move');
require('prototype_roomPosition');
require('prototype_room_init');
require('prototype_room_costmatrix');
require('visualizer');
require('screepsplus');

if (config.profiler.enabled) {
  try {
    var profiler = require('screeps-profiler');
    profiler.enable();
  } catch (e) {
    console.log('screeps-profiler not found');
    config.profiler.enabled = false;
  }
}
brain.stats.init();

var main = function() {
  if (Game.cpu.bucket < Game.cpu.tickLimit) {
    console.log('Skipping tick ' + Game.time + ' due to lack of CPU.');
    return;
  }

  brain.prepareMemory();
  brain.handleNextroom();
  brain.handleSquadmanager();
  brain.handleIncomingTransactions();
  brain.stats.addRoot();
  Memory.myRooms = _.map(_.filter(Game.rooms, r => r.execute()), r => r.name);

  if (config.visualizer.enabled && config.visualizer.refresh) {
    visualizer.render();
  }
  brain.stats.add(['cpu'], {
    used: Game.cpu.getUsed()
  });
};

module.exports.loop = function() {
  if (config.profiler.enabled) {
    profiler.wrap(function() {
      main();
    });
  } else {
    main();
  }
};

Change check to check for Game.cpu.tickLimit


Spree.Views.Cart.EmptyCartButton = Backbone.View.extend({
  initialize: function() {
    this.listenTo(this.collection, 'update', this.render);
    this.render();
  },

  events: {
    "click": "onClick"
  },

  onClick: function(e) {
    e.preventDefault()
    if (!confirm(Spree.translations.are_you_sure_delete)) {
      return;
    }

    this.model.empty({
      success: () => {
        this.collection.reset()
        this.collection.push({})
      }
    })
  },

  render: function() {
    var isNew = function (item) { return item.isNew() };
    this.$el.prop("disabled", !this.collection.length || this.collection.some(isNew));
  }
});

Spree.Views.Cart.EmptyCartButton = Backbone.View.extend({
  initialize: function() {
    this.listenTo(this.collection, 'update', this.render);
    this.render();
  },

  events: {
    "click": "onClick"
  },

  onClick: function(e) {
    e.preventDefault()
    if (!confirm(Spree.translations.are_you_sure_delete)) {
      return;
    }

    this.model.empty({
      success: function () {
        this.collection.reset()
        this.collection.push({})
      }.bind(this)
    })
  },

  render: function() {
    var isNew = function (item) { return item.isNew() };
    this.$el.prop("disabled", !this.collection.length || this.collection.some(isNew));
  }
});

Convert ES6 arrow syntax to ES5 for compatibility


import React from 'react';
import { Form } from 'semantic-ui-react';

const ListingBody = ({ body, onChange }) =>
  <Form.TextArea
    rows="5"
    className='ui center aligned grid'
    label="Job Description"
    placeholder="Tell us about the job..."
    name="body"
    value={body}
    onChange={e => onChange(e)}
  />;

ListingBody.propTypes = {
  body: React.PropTypes.string.isRequired,
  onChange: React.PropTypes.func.isRequired,
};

export default ListingBody;

import React from 'react';
import { Form } from 'semantic-ui-react';

const ListingBody = ({ body, onChange, getFormClass }) =>
  <Form.TextArea
    rows="5"
    label="Job Description"
    placeholder="Tell us about the job..."
    name="body"
    value={body}
    onChange={e => onChange(e)}
    className={getFormClass('body')}
  />;

ListingBody.propTypes = {
  body: React.PropTypes.string.isRequired,
  onChange: React.PropTypes.func.isRequired,
  getFormClass: React.PropTypes.func.isRequired,
};

export default ListingBody;

Add form class to textarea


var Mongoose = require('mongoose');
var Map = require('./models/map');

Mongoose.connect('mongodb://localhost/mappoints', function () {
  console.log('connected to mongodb');

  Mongoose.connection.db.dropDatabase();

  var items = [
    {
      mapName: 'Norway',
      imagePath: '/img/norway.png',
      urlSafeName: 'norway'
    }
  ];

  items.forEach(function (item) {
    new Map(item).save();
  });

});

var Mongoose = require('mongoose');
var Map = require('./models/map');

Mongoose.connect('mongodb://localhost/mappoints', function () {
  console.log('connected to mongodb');

//  Mongoose.connection.db.dropDatabase();
//  var items = [
//    {
//      mapName: 'Norway',
//      imagePath: '/img/norway.png',
//      urlSafeName: 'norway'
//    }
//  ];
//
//  items.forEach(function (item) {
//    new Map(item).save();
//  });

});

Comment out re-init db code


// MAS.bootstrap.I18n_locale == en || cy == file path in require config
define(
  ['jquery', 'globals', 'pubsub', 'log', 'i18n'],
  function($, globals, pubsub, log, i18n) {
    'use strict';

    var MAS = $.extend({}, globals, pubsub, log);
    var dataLayer = dataLayer || [];

    MAS.text = i18n;

    // Fire analytics events
    // TO USE: MAS.publish('analytics:trigger', {object with props})
    MAS.subscribe('analytics:trigger', function(e, data) {
      MAS.log('mas_analytics.triggerAnalytics', data);
      dataLayer.push(data);
    });

    return MAS;
  }
);

// MAS.bootstrap.I18n_locale == en || cy == file path in require config
define(
  ['jquery', 'globals', 'pubsub', 'log', 'i18n'],
  function($, globals, pubsub, log, i18n) {
    'use strict';

    var MAS = $.extend({}, globals, pubsub, log);
    window.dataLayer = window.dataLayer || [];

    MAS.text = i18n;

    // Fire analytics events
    // TO USE: MAS.publish('analytics:trigger', {object with props})
    MAS.subscribe('analytics:trigger', function(e, data) {
      MAS.log('mas_analytics.triggerAnalytics', data);
      window.dataLayer.push(data);
    });

    return MAS;
  }
);

Make tracking facade more resiliant


import {Index, Label, Offset, Size, Total, Value} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendLabelRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      encode = {}, enter, update;

  encode.enter = enter = {
    opacity: zero,
    text: {field: Label}
  };
  addEncode(enter, 'align', config.labelAlign);
  addEncode(enter, 'baseline', config.labelBaseline);
  addEncode(enter, 'fill', config.labelColor);
  addEncode(enter, 'font', config.labelFont);
  addEncode(enter, 'fontSize', config.labelFontSize);
  addEncode(enter, 'limit', config.labelLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1}
  };

  enter.x = update.x = {
    field:  Offset,
    offset: config.labelOffset
  };

  enter.y = update.y = {
    field:  Size,
    mult:   0.5,
    offset: {
      field: Total,
      offset: {
        field: {group: 'entryPadding'},
        mult: {field: Index}
      }
    }
  };

  return guideMark(TextMark, LegendLabelRole, Value, dataRef, encode, userEncode);
}

import {Index, Label, Offset, Size, Total, Value} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendLabelRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      encode = {}, enter, update;

  encode.enter = enter = {
    opacity: zero
  };
  addEncode(enter, 'align', config.labelAlign);
  addEncode(enter, 'baseline', config.labelBaseline);
  addEncode(enter, 'fill', config.labelColor);
  addEncode(enter, 'font', config.labelFont);
  addEncode(enter, 'fontSize', config.labelFontSize);
  addEncode(enter, 'limit', config.labelLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1},
    text: {field: Label}
  };

  enter.x = update.x = {
    field:  Offset,
    offset: config.labelOffset
  };

  enter.y = update.y = {
    field:  Size,
    mult:   0.5,
    offset: {
      field: Total,
      offset: {
        field: {group: 'entryPadding'},
        mult: {field: Index}
      }
    }
  };

  return guideMark(TextMark, LegendLabelRole, Value, dataRef, encode, userEncode);
}

Include legend label text in update block.


/* globals $ */
$(function () {
  'use strict'
  $(document).foundation()

  $('.top-bar > .top-bar-right > .menu > li > button.hollow').click(function (ev) {
  })

  $('button.logout').click(function (ev) {
    $.ajax({
      url: '/_session',
      method: 'DELETE',
      complete: function () { window.location = '/_utils/groupe2016.html' }
    })
  })
})

/* globals $ */
$(function () {
  'use strict'
  const $passwordButton = $('.top-bar > .top-bar-right > .menu > li > button.hollow')
  if ($passwordButton.length) {
    $passwordButton.attr('data-open', 'changePassword')
    $('body').append([
      '
',
      '<form class="shake">',
      '
Changer votre mot de passe
',
      'Nouveau mot de passe:',
      '<input required type="text" name="password">',
      '',
      'Répétez le mot de passe:',
      '<input required type="text" name="password2">',
      '',
      '<input class="button alert" type="submit" value="Remplacez mon mot de passe">',
      ' <button type="button" class="button warning" data-close>Annuler</button>',
      '</form>',
      '<button class="close-button" data-close aria-label="Annuler" type="button">',
      '×',
      '</button>',
      '
'
    ].join(''))
  }
  $(document).foundation()

  $('body').on('submit', '#changePassword > form', function (ev) {
    ev.preventDefault()
    const $form = $(this)
    const pwds = $form.serializeArray()
      .map(function (i) { return i.value })
      .slice(0, 2)
      .filter(function (i) { return i })

    if (pwds.length !== 2 || pwds[0] !== pwds[1]) {
      $form.addClass('shake-horizontal shake-constant')
      setTimeout(function () {
        $form.removeClass('shake-horizontal shake-constant')
      }, 500)
      return
    }
    console.log('Ready to change password!')
    // get user doc
    // set password field
    // put user doc
  })

  $('button.logout').click(function (ev) {
    $.ajax({
      url: '/_session',
      method: 'DELETE',
      complete: function () { window.location = '/_utils/groupe2016.html' }
    })
  })
})

Change password dialog, for admin.


const fs = require('fs');
const {promisify} = require('util');

const stat = promisify(fs.stat);

const checkCacheExpiry = (path, ttl) =>
    stat(path).then(stats => {

        if (new Date(stats.mtime).getTime() + ttl < Date.now()) {

            throw new Error('Cache has expired.');

        }

        return stats;

    });

module.exports = checkCacheExpiry;

const fs = require('fs');
const {promisify} = require('util');

const stat = promisify(fs.stat);

const checkCacheExpiry = (path, ttl) =>
    stat(path).then(stats => {

        if (new Date(stats.mtime).getTime() + ttl < Date.now()) {

            throw new Error('Cache has expired.');

        }

        return stats;

    })
        .catch(() => {

            throw new Error('Cache is missing.');

        });

module.exports = checkCacheExpiry;

Throw error when cache is missing.


var kue = require('kue'),
    redis = require('redis'),
    url = require('url'),
    config = require('../config'),
    lynx = require('lynx');

var statsDClient = null;

module.exports = {
    setRedisServer: function() {
        var port = config.BootstrapHtml.redis_port || process.env.REDISTOGO_URL || 6379,
            host = config.BootstrapHtml.redis_host;

        kue.redis.createClient = function() {
            var client = redis.createClient(port, host);
            console.log('Redis client created at', host, 'port', port)
            return client;
        };
    },

    getStatsClient: function() {
        if (statsDClient) {
            return statsDClient;
        }

        var host = config.BootstrapHtml.statsd_host.split('//')[1].split(':');
        var serverUrl = host[0];
        var serverPort = host[1];

        var scope = ['stats', config.environment.type, 'bshtml'].join('.');
        statsDClient = new lynx(serverUrl, serverPort, {
            scope: scope
        });
        console.log('StatsD client created at', serverUrl, serverPort);
        return statsDClient;
    }
};

var kue = require('kue'),
    redis = require('redis'),
    url = require('url'),
    config = require('../config'),
    lynx = require('lynx');

var statsDClient = null;

module.exports = {
    setRedisServer: function() {
        var port = config.BootstrapHtml.redis_port || process.env.REDISTOGO_URL || 6379,
            host = config.BootstrapHtml.redis_host;

        kue.redis.createClient = function() {
            var client = redis.createClient(port, host);
            console.log('Redis client created at', host, 'port', port)
            return client;
        };
    },

    getStatsClient: function() {
        if (statsDClient) {
            return statsDClient;
        }

        var host = config.BootstrapHtml.statsd_host.split('//')[1].split(':');
        var serverUrl = host[0];
        var serverPort = host[1];

        var scope = [config.environment.type, 'bshtml'].join('.');
        statsDClient = new lynx(serverUrl, serverPort, {
            scope: scope
        });
        console.log('StatsD client created at', serverUrl, serverPort);
        return statsDClient;
    }
};

Remove 'stats' prefix from scope in lynx


var intervals = require('./intervals')
  , Table = require('cli-table')
  , utils = require('./utils')
;

module.exports = function(conf, opts) {
    var dates = utils.parseDate(opts.date);
    var start = dates[0];
    var end = dates[dates.length - 1];
    console.log("Show timesheet from %s to %s", start, end);
    var client = intervals.createClient(conf.token);
    client.me(function(err, res) {
        if (err) throw err;
        client.time({personid: res.body.personid,
                     datebegin: start,
                     dateend: end}, function(err, response) {
                         showTime(response.body);
                     });
    });

}

function showTime(body) {
    // instantiate
    var table = new Table({
        head: ['Project', 'date', 'hours', 'billable']
      , colWidths: [42, 12, 7, 10]
    });

    body.time.forEach(function(time) {
        table.push([time.project, time.dateiso, time.time, (time.billable == 'f' ? 'no' : 'yes')])
    });
    console.log(table.toString());
}

var intervals = require('./intervals')
  , Table = require('cli-table')
  , utils = require('./utils')
;

module.exports = function(conf, opts) {
    var dates = utils.parseDate(opts.date);
    var start = dates[0];
    var end = dates[dates.length - 1];
    console.log("Show timesheet from %s to %s", start, end);
    var client = intervals.createClient(conf.token);
    client.me(function(err, res) {
        if (err) throw err;
        client.time({personid: res.body.personid,
                     datebegin: start,
                     dateend: end,
                     limit: 10}, function(err, response) {
                         showTime(response.body);
                     });
    });

}

function showTime(body) {
    // instantiate
    var table = new Table({
        head: ['Project', 'date', 'hours', 'billable']
      , colWidths: [42, 12, 7, 10]
    });

    body.time.forEach(function(time) {
        table.push([time.project, time.dateiso, time.time, (time.billable == 'f' ? 'no' : 'yes')])
    });
    console.log(table.toString());
}

Add a limit in ls command.


$(document).ready(function () {

    function setMapByCoords(lng, lat) {
        var myLatLng = new google.maps.LatLng(lat, lng);
        var map = new google.maps.Map(document.getElementById('map'),
            {
                zoom: 17,
                center: myLatLng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });
        var marker = new google.maps.Marker(
            {
                position: myLatLng,
                map: map
            });
    }

    function initMap() {
        var map_element = $('#map');
        var e_slug = map_element.data('event');
        var lng = map_element.data('lng');
        var lat = map_element.data('lat');
        if (!lng || !lat) {
            $.ajax({
                type: 'post',
                url: Routing.generate('get_event_map_position', {slug: e_slug})
            }).done(
                function (data) {
                    if (data.result) {
                        setMapByCoords(data.lng, data.lat)
                    } else {
                        console.log('Error:' + data.error);
                    }
                }
            );
        } else {
            setMapByCoords(lng, lat)
        }
    }

    if ($('#map').length > 0) {
        initMap();
    }
});

$(document).ready(function () {

    function setMapByCoords(lng, lat) {
        var myLatLng = new google.maps.LatLng(lat, lng);
        if (typeof google === 'undefined') {
            return;
        }
        var map = new google.maps.Map(document.getElementById('map'),
            {
                zoom: 17,
                center: myLatLng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });
        var marker = new google.maps.Marker(
            {
                position: myLatLng,
                map: map
            });
    }

    function initMap() {
        var map_element = $('#map');
        var e_slug = map_element.data('event');
        var lng = map_element.data('lng');
        var lat = map_element.data('lat');
        if (!lng || !lat) {
            $.ajax({
                type: 'post',
                url: Routing.generate('get_event_map_position', {slug: e_slug})
            }).done(
                function (data) {
                    if (data.result) {
                        setMapByCoords(data.lng, data.lat)
                    } else {
                        console.log('Error:' + data.error);
                    }
                }
            );
        } else {
            setMapByCoords(lng, lat)
        }
    }

    if ($('#map').length > 0) {
        initMap();
    }
});

Fix google undefined error (sentry js error)