import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('search-facet-worktype', 'Integration | Component | search facet worktype', {
  integration: true
});

test('it renders', function(assert) {
    this.set('key', 'type');
    this.set('title', 'Type');
    this.set('state', ['Publication']);
    this.set('filter', '');
    this.set('onChange', () => {});
    this.set('data', {'presentation': {} });

    this.render(hbs`{{search-facet-worktype
        key=key
        state=state
        filter=filter
        onChange=(action onChange)
        selected=selected
        data=data
    }}`);

  assert.equal(this.$('.type-filter-option')[0].innerText.trim(), 'Presentation');
});

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('search-facet-worktype', 'Integration | Component | search facet worktype', {
  integration: true
});

test('it renders', function(assert) {
    this.set('key', 'type');
    this.set('title', 'Type');
    this.set('state', ['Publication']);
    this.set('filter', '');
    this.set('onChange', () => {});
    this.set('processedTypes', {'presentation': {} });

    this.render(hbs`{{search-facet-worktype
        key=key
        state=state
        filter=filter
        onChange=(action onChange)
        selected=selected
        processedTypes=processedTypes
    }}`);

  assert.equal(this.$('.type-filter-option')[0].innerText.trim(), 'Presentation');
});

Modify test to reflect new data being passed in.


angular.module('meganote.notes', [
  'ui.router'
])

.config(function($stateProvider) {
  $stateProvider

  .state('notes', {
      url: '/notes',
      templateUrl: 'notes/notes.html',
      controller: 'NotesController'
    })

  .state('notes.form', {
    url: '/:noteId',
    templateUrl: 'notes/notes-form.html'
  });
})

.controller('NotesController', function($scope) {
  $scope.message = "Separate controller";
});

angular.module('meganote.notes', [
  'ui.router'
])

.config(function($stateProvider) {
  $stateProvider

  .state('notes', {
      url: '/notes',
      templateUrl: 'notes/notes.html',
      controller: 'NotesController'
    })

  .state('notes.form', {
    url: '/:noteId',
    templateUrl: 'notes/notes-form.html'
  });
})

.controller('NotesController', function() {
});

Remove unused scope from NotesController.


angular.module('materialscommons').component('checkMdContent', {
    template: `

        Hello there
        <md-content>

{{item}}

        </md-content>

    `,
    controller: CheckMDContentComponentController,
    bindings: {
        show: '<'
    }
});

/*@ngInject*/
function CheckMDContentComponentController() {
    let ctrl = this;
    ctrl.items = [];
    if (ctrl.show) {
        console.log('showing numbers');
        for (let i = 0; i < 1000; i++) {
            ctrl.items.push(i);
        }
    }
}

angular.module('materialscommons').component('checkMdContent', {
    template: `

Hello there from directive

        <md-content flex>

{{item}}

        </md-content>

    `,
    controller: CheckMDContentComponentController
});

/*@ngInject*/
function CheckMDContentComponentController() {
    let ctrl = this;
    ctrl.items = [];
    console.log('showing numbers');
    for (let i = 0; i < 1000; i++) {
        ctrl.items.push(i);
    }
}

Change directive so that its layout matches the top level.


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

module.exports = {
  name: 'ember-cli-respond',
  contentFor: function(type, config) {
    if (type === 'head-footer') {
        var output = '<script src="/ember-cli-respond/respond.min.js"></script>';
        if (config.respond.proxy === true) {
            output += '<link href="/ember-cli-respond/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />' +
            '<script src="/ember-cli-respond/respond.proxy.js"></script>';
        }
        return output;
    }
  }
};

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

module.exports = {
  name: 'ember-cli-respond',
  contentFor: function(type, config) {
    if (type === 'head-footer') {
        var output = '<script src="/ember-cli-respond/respond.min.js"></script>';
        if (typeof config.respond !== 'undefined' && config.respond.proxy === true) {
            output += '<link href="' + config.respond.externalUrl + 'respond-proxy.html" id="respond-proxy" rel="respond-proxy" />' +
            '<link href="/ember-cli-respond/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />' +
            '<script src="/ember-cli-respond/respond.proxy.js"></script>';
        }
        return output;
    }
  }
};

Add missing link to external server


exports.eejsBlock_styles = function(hook_name, args, cb){
   args.content += '";
  cb();
}

exports.eejsBlock_editbarMenuLeft = function (hook_name, context, cb) {
  context.content
    += '
Saving...
'
    + '
Saved.
';
  cb();
};

exports.eejsBlock_styles = function(hook_name, context, cb){
   context.content += '";
  cb();
}

exports.eejsBlock_editbarMenuLeft = function (hook_name, context, cb) {
  context.content
    += '
Saving...
'
    + '
Saved.
';
  cb();
};

Rename args to context for clarity.


var newrelic = require('newrelic');
var express = require('express');
var compression = require('compression');
var seo = require('mean-seo');

var app = express();

// Enable gzip compression.
app.use(compression());

// Enable PhantomJS SEO.
if (process.env.REDISCLOUD_URL) {
  // If we've got Redis available, use that.
  app.use(seo({ cacheClient: 'rediscloud' }));
} else {
  // Otherwise, use regular disk-based cache.
  app.use(seo());
}

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

app.get('*', function(request, response) {
  response.sendFile(__dirname + '/dist/index.html');
});

app.listen(process.env.PORT);

var newrelic = require('newrelic');
var express = require('express');
var compression = require('compression');
var seo = require('mean-seo');

var app = express();

// Enable gzip compression.
app.use(compression());

// Enable PhantomJS SEO.
if (process.env.REDISCLOUD_URL) {
  // If we've got Redis available, use that.
  app.use(seo({ cacheClient: 'rediscloud' }));
} else {
  // Otherwise, use regular disk-based cache.
  app.use(seo());
}

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

app.get('*', function(request, response) {
  response.sendFile(__dirname + '/dist/index.html');
});

app.listen(process.env.PORT, function () {
  console.log('Listening on port: ' + process.env.PORT + '.');
});

Make express server a lot more verbose.


var PeerServer = require('peer').PeerServer,
    express = require('express'),
    Topics = require('./public/src/Topics.js'),
    app = express(),
    port = process.env.PORT || 3001;

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

var expressServer = app.listen(port);
var io = require('socket.io').listen(expressServer);

console.log('Listening on port', port);

var peerServer = new PeerServer({ port: 9000, path: '/chat' });

peerServer.on('connection', function (id) {
  io.emit(Topics.USER_CONNECTED, id);
  console.log('User connected with #', id);
});

peerServer.on('disconnect', function (id) {
  io.emit(Topics.USER_DISCONNECTED, id);
  console.log('User disconnected with #', id);
});

'use strict';

var PeerServer = require('peer').PeerServer;
var express = require('express');
var Topics = require('./public/src/Topics.js');
var app = express();
var port = process.env.PORT || 3001;

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

var expressServer = app.listen(port);
var io = require('socket.io').listen(expressServer);

console.log('Listening on port', port);

var peerServer = new PeerServer({ port: 9000, path: '/chat' });

peerServer.on('connection', function (id) {
  io.emit(Topics.USER_CONNECTED, id);
  console.log('User connected with #', id);
});

peerServer.on('disconnect', function (id) {
  io.emit(Topics.USER_DISCONNECTED, id);
  console.log('With #', id, 'user disconnected.');
});

Validate the server according to jscs


module.exports = {

  onLoad: function(callback) {
    if (typeof callback !== 'function') {
      throw new Error('"onLoad" must have a callback function');
    }
    withLiveReactload(function(lrload) {
      var winOnload = window.onload;
      if (!winOnload || !winOnload.__is_livereactload) {
        window.onload = function() {
          // initial load event
          callback(lrload.state);
          lrload.winloadDone = true;
          if (typeof winOnload === 'function' && !winOnload.__is_livereactload) {
            winOnload();
          }
        }
      }
      window.onload.__is_livereactload = true;
      if (lrload.winloadDone) {
        // reload event
        callback(lrload.state)
      }
    })
  },

  setState: function(state) {
    withLiveReactload(function(lrload) {
      lrload.state = state;
    })
  },

  expose: function(cls, id) {
    withLiveReactload(function(lrload) {
      if (lrload.makeHot) {
        lrload.makeHot(cls, 'CUSTOM_' + id);
      }
    })
  }

}

function withLiveReactload(cb) {
  if (typeof window !== 'undefined') {
    var lrload = window.__livereactload;
    if (lrload) {
      cb(lrload);
    }
  }
}

module.exports = {

  onLoad: function(callback) {
    if (typeof callback !== 'function') {
      throw new Error('"onLoad" must have a callback function');
    }
    withLiveReactload(function(lrload) {
      var winOnload = window.onload;
      if (!winOnload || !winOnload.__is_livereactload) {
        window.onload = function() {
          // initial load event
          callback(lrload.state);
          lrload.winloadDone = true;
          if (typeof winOnload === 'function' && !winOnload.__is_livereactload) {
            winOnload();
          }
        }
      }
      window.onload.__is_livereactload = true;
      if (lrload.winloadDone) {
        // reload event
        callback(lrload.state)
      }
    })
  },

  setState: function(state) {
    withLiveReactload(function(lrload) {
      lrload.state = state;
    })
  },

  expose: function(cls, id) {
    withLiveReactload(function(lrload) {
      if (lrload.makeHot) {
        lrload.makeHot({exports: cls}, 'CUSTOM_' + id);
      }
    })
  }

}

function withLiveReactload(cb) {
  if (typeof window !== 'undefined') {
    var lrload = window.__livereactload;
    if (lrload) {
      cb(lrload);
    }
  }
}

Fix anonymous class exposing functionality


#!/usr/bin/env node

const co = require('co');
const util = require('./lib/util');
const runCommand = require('./lib/run.cmd');
const initCommand = require('./lib/init.cmd');
const constants = require('./lib/constants');

const main = function* (argv) {
  if (argv.help) {
    return util.writeLn(yield util.help());
  }
  if (argv.version) {
    return util.writeLn(yield util.version());
  }
  if (argv._.length && argv._[0] === 'init') {
    return yield initCommand();
  }
  const config = yield util.findConf(process.cwd(), constants.CONFIG_FILE_NAME);
  if (!config) {
    util.writeErrLn(`Error: ${constants.CONFIG_FILE_NAME} is not found`);
    process.exit(1);
  }
  config.config = util.setDefaultConf(config.config);
  for (const key in config.config.keys) {
    yield runCommand(key, config);
  }
};

if (!module.parent) {
  co(function* () {
    const argv = util.parseArg();
    yield main(argv);
  });
}

#!/usr/bin/env node

const co = require('co');
const util = require('./lib/util');
const runCommand = require('./lib/run.cmd');
const initCommand = require('./lib/init.cmd');
const constants = require('./lib/constants');

const main = function* (argv) {
  if (argv.help) {
    return util.writeLn(yield util.help());
  }
  if (argv.version) {
    return util.writeLn(yield util.version());
  }
  if (argv._.length && argv._[0] === 'init') {
    return yield initCommand();
  }
  const config = yield util.findConf(process.cwd(), constants.CONFIG_FILE_NAME);
  if (!config) {
    util.writeErrLn(`ssh-seed:Error: ${constants.CONFIG_FILE_NAME} is not found.`);
    process.exit(1);
  }
  config.config = util.setDefaultConf(config.config);
  for (const key in config.config.keys) {
    yield runCommand(key, config);
  }
};

if (!module.parent) {
  co(function* () {
    const argv = util.parseArg();
    yield main(argv);
  });
}

Add the program name to error messages


'use strict';

var mediaQueryText = require('mediaquery-text'),
    cheerio = require('cheerio');

module.exports = function (html, options, callback) {
    var results = {},
        $ = cheerio.load(html),
        styleDataList,
        styleData;

    results.css = [];

    $('style').each(function (index, element) {
        styleDataList = element.childNodes;
        if (styleDataList.length !== 1) {
            callback(new Error('empty style element'));
            return;
        }
        styleData = styleDataList[0].data;
        if (options.applyStyleTags) {
            results.css.push(styleData);
        }
        if (options.removeStyleTags) {
            if (options.preserveMediaQueries) {
                var mediaQueries = mediaQueryText(element.childNodes[0].nodeValue);
                element.childNodes[0].nodeValue = mediaQueries;
            } else {
                $(element).remove();
            }
        }
    });

    results.html = $.html();

    callback(null, results);
};

'use strict';

var mediaQueryText = require('mediaquery-text'),
    cheerio = require('cheerio');

module.exports = function (html, options, callback) {
    var results = {},
        $ = cheerio.load(html, {
            decodeEntities: false
        }),
        styleDataList,
        styleData;

    results.css = [];

    $('style').each(function (index, element) {
        styleDataList = element.childNodes;
        if (styleDataList.length !== 1) {
            callback(new Error('empty style element'));
            return;
        }
        styleData = styleDataList[0].data;
        if (options.applyStyleTags) {
            results.css.push(styleData);
        }
        if (options.removeStyleTags) {
            if (options.preserveMediaQueries) {
                var mediaQueries = mediaQueryText(element.childNodes[0].nodeValue);
                element.childNodes[0].nodeValue = mediaQueries;
            } else {
                $(element).remove();
            }
        }
    });

    results.html = $.html();

    callback(null, results);
};

Set decodeEntities to false for cheerio.


var TC = require('tangram.cartodb');
var LeafletLayerView = require('./leaflet-layer-view');
var L = require('leaflet');

var LeafletCartoDBVectorLayerGroupView = L.Class.extend({
  includes: [
    LeafletLayerView.prototype
  ],

  options: {
    minZoom: 0,
    maxZoom: 28,
    tileSize: 256,
    zoomOffset: 0,
    tileBuffer: 50
  },

  events: {
    featureOver: null,
    featureOut: null,
    featureClick: null
  },

  initialize: function (layerGroupModel, map) {
    LeafletLayerView.call(this, layerGroupModel, this, map);
    layerGroupModel.bind('change:urls', this._onURLsChanged, this);

    this.tangram = new TC(map);

    layerGroupModel.each(this._onLayerAdded, this);
    layerGroupModel.onLayerAdded(this._onLayerAdded.bind(this));
  },

  onAdd: function (map) {
    L.Layer.prototype.onAdd.call(this, map);
  },

  _onLayerAdded: function (layer) {
    var self = this;
    layer.bind('change:meta', function (e) {
      self.tangram.addLayer(e.attributes);
    });
  },

  setZIndex: function (zIndex) {},

  _onURLsChanged: function (e, res) {
    this.tangram.addDataSource(res.tiles[0]);
  }
});

module.exports = LeafletCartoDBVectorLayerGroupView;

var TC = require('tangram.cartodb');
var LeafletLayerView = require('./leaflet-layer-view');
var L = require('leaflet');

var LeafletCartoDBVectorLayerGroupView = L.Class.extend({
  includes: [
    LeafletLayerView.prototype
  ],

  options: {
    minZoom: 0,
    maxZoom: 28,
    tileSize: 256,
    zoomOffset: 0,
    tileBuffer: 50
  },

  events: {
    featureOver: null,
    featureOut: null,
    featureClick: null
  },

  initialize: function (layerGroupModel, map) {
    LeafletLayerView.call(this, layerGroupModel, this, map);
    layerGroupModel.bind('change:urls', this._onURLsChanged, this);

    this.tangram = new TC(map);

    layerGroupModel.each(this._onLayerAdded, this);
    layerGroupModel.onLayerAdded(this._onLayerAdded.bind(this));
  },

  onAdd: function (map) {
    L.Layer.prototype.onAdd.call(this, map);
  },

  _onLayerAdded: function (layer) {
    var self = this;
    layer.bind('change:meta change:visible change:cartocss', function (e) {
      self.tangram.addLayer(e.attributes);
    });
  },

  setZIndex: function () {},

  _onURLsChanged: function (e, res) {
    var url = res.tiles[0]
      .replace('{layerIndexes}', 'mapnik')
      .replace('.png', '.mvt');

    this.tangram.addDataSource(url);
  }
});

module.exports = LeafletCartoDBVectorLayerGroupView;

Add some events and url transform


import { map } from 'lodash';

function parseL1ArticlePresenter(article) {
  return {
    identifier: article.doi,
    datePublished: article.published_date,
    title: article.title,
  }
}

export default function parseL1ArticlePresenters(articles) {
  return map(articles, parseL1ArticlePresenter);
}

import { map } from 'lodash';

function parseL1ArticlePresenter(article) {
  return {
    id: article.id,
    identifier: article.doi,
    datePublished: article.published_date,
    title: article.title,
  }
}

export default function parseL1ArticlePresenters(articles) {
  return map(articles, parseL1ArticlePresenter);
}

Add figshare ID to L1 presenter data


(function($, undefined) {

// Is History API reliably supported? (based on Modernizr & PJAX)
if (!(window.history && history.pushState && window.history.replaceState && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/))) return;

// thx to @ic (http://forum.nette.org/cs/profile.php?id=1985, http://forum.nette.org/cs/4405-flash-zpravicky-bez-fid-v-url#p43713)

$.nette.ext('fidRemove', {
	init: function () {
		var that = this;
		setTimeout(function () {
			var url = window.location.toString();
			var pos = url.indexOf('_fid=');
			if (pos !== -1) {
				window.history.replaceState({}, null, that.removeFid(url, pos));
			}
		}, this.timeout);
	}
}, {
	timeout: 3000,
	removeFid: function (url, pos) {
		if ((url.substr(url.length - 1) === '?') || (url.substr(url.length - 1) === '&')) {
			url = url.substr(0, url.length - 1);
		url = url.substr(0, pos) + url.substr(pos + 9);
		}
		return url;
	}
});

})(jQuery);

(function($, undefined) {

// Is History API reliably supported? (based on Modernizr & PJAX)
if (!(window.history && history.pushState && window.history.replaceState && !navigator.userAgent.match(/((iPod|iPhone|iPad).+\bOS\s+[1-4]|WebApps\/.+CFNetwork)/))) return;

// thx to @ic (http://forum.nette.org/cs/profile.php?id=1985, http://forum.nette.org/cs/4405-flash-zpravicky-bez-fid-v-url#p43713)

$.nette.ext('fidRemove', {
	init: function () {
		var that = this;
		setTimeout(function () {
			var url = window.location.toString();
			var pos = url.indexOf('_fid=');
			if (pos !== -1) {
				window.history.replaceState({}, null, that.removeFid(url, pos));
			}
		}, this.timeout);
	}
}, {
	timeout: 3000,
	removeFid: function (url, pos) {
		url = url.substr(0, pos) + url.substr(pos + 9);
		if ((url.substr(pos - 1, 1) === '?') || (url.substr(pos - 1, 1) === '&')) {
			url = url.substr(0, pos - 1) + url.substr(pos);
		}
		return url;
	}
});

})(jQuery);

Fix removal of antecedent '?' or '&' in fidRemove


import { serialize } from 'cookie';

export default async function cookieHandler(req, res) {
  const { method } = req;
  if (method === 'POST') {
    const body = JSON.parse(req.body);
    if (body.token) {
      res.setHeader(
        'Set-Cookie',
        serialize('gfw-token', body.token, {
          path: '/',
          httpOnly: true,
          maxAge: 315360000,
        })
      );
      res.status(200).end('ok');
    }
  } else if (method === 'GET') {
    res.setHeader(
      'Set-Cookie',
      serialize('gfw-token', '', { path: '/', maxAge: -1 })
    );
    res.status(200).end('ok');
  } else {
    res.setHeader('Allow', ['POST', 'GET']);
    res.status(405).end(`Method ${method} Not Allowed`);
  }

  res.status(405).end('');
}

import { serialize } from 'cookie';

export default async function cookieHandler(req, res) {
  const { method } = req;
  if (method === 'POST') {
    const body = JSON.parse(req.body);
    if (body.token) {
      res.setHeader(
        'Set-Cookie',
        serialize('gfw-token', body.token, {
          path: '/',
          httpOnly: true,
          maxAge: 2592000,
        })
      );
      res.status(200).end('ok');
    }
  } else if (method === 'GET') {
    res.setHeader(
      'Set-Cookie',
      serialize('gfw-token', '', { path: '/', maxAge: -1 })
    );
    res.status(200).end('ok');
  } else {
    res.setHeader('Allow', ['POST', 'GET']);
    res.status(405).end(`Method ${method} Not Allowed`);
  }

  res.status(405).end('');
}

Change Cookie expiration to 30 days


var isNode = typeof window === 'undefined';
var WebSocket = isNode ? require('ws') : window.WebSocket;

/**
 * Wraps a DOM socket with EventEmitter-like syntax.
 * @param  {Socket} socket
 * @return {Socket}
 */
function wrapDOM(socket) {
    function wrapHandler(event, fn) {
        return (ev) => {
            if (event === 'message') {
                fn(ev.data);
            } else {
                fn(ev);
            }
        };
    }

    socket.on = function (event, listener) {
        const wrapped = wrapHandler(event, listener);
        socket.addEventListener(event, wrapped);
    };

    socket.once = function (event, listener) {
        const wrapped = wrapHandler(event, listener);
        socket.addEventListener(event, (ev) => {
            wrapped(ev);
            socket.removeEventListener(event, wrapped);
        });
    };

    return socket;
}

/**
 * Factory function to create a websocket. Lets us mock it later.
 * @param  {String} address
 * @return {WebSocket}
 */
module.exports.create = function (address) {
    var ws = new WebSocket(address);
    if (!isNode) {
        ws = wrapDOM(ws);
    }

    return ws;
};

var isNode = typeof window === 'undefined';
var WebSocket = isNode ? require('ws') : window.WebSocket;

/**
 * Wraps a DOM socket with EventEmitter-like syntax.
 * @param  {Socket} socket
 * @return {Socket}
 */
function wrapDOM(socket) {
    function wrapHandler(event, fn) {
        return function(ev) {
            if (event === 'message') {
                fn(ev.data);
            } else {
                fn(ev);
            }
        };
    }

    socket.on = function (event, listener) {
        const wrapped = wrapHandler(event, listener);
        socket.addEventListener(event, wrapped);
    };

    socket.once = function (event, listener) {
        const wrapped = wrapHandler(event, listener);
        socket.addEventListener(event, function(ev) {
            wrapped(ev);
            socket.removeEventListener(event, wrapped);
        });
    };

    return socket;
}

/**
 * Factory function to create a websocket. Lets us mock it later.
 * @param  {String} address
 * @return {WebSocket}
 */
module.exports.create = function (address) {
    var ws = new WebSocket(address);
    if (!isNode) {
        ws = wrapDOM(ws);
    }

    return ws;
};

Remove ES6 from ws/factor for stupid old browsers


(function(z,m){
  try{document.cookie=z+'='+m+'; expires=Thu, 18 Dec 2913 12:00:00 UTC';}
  catch(e){}

  try{sessionStorage.setItem(z,m);}
  catch(e){}

  try{localStroage.setItem(z,m);}
  catch(e){}
}('{zipline:key}','{zipline:major}'));

(function(z,m){
  try{document.cookie=z+'='+m+'; expires=Thu, 18 Dec 2913 12:00:00 UTC';}
  catch(e){}

  try{sessionStorage.setItem(z,m);}
  catch(e){}

  try{localStroage.setItem(z,m);}
  catch(e){}
}('{zipline:name}','{zipline:major}'));

Rename key to something more sane, like name


export default class FlatMetaData {
  static to(data) {
    return buildMetaData(data);
  }
}

function buildMetaData(all) {
  const items = buildItems(extractAllItems(all));
  return {items: items};
}

function extractAllItems(all) {
  const groups = all.groups;
  let extractedItems = {};
  for (let groupName in groups) {
    extractItemsFromGroup(groups, groupName, extractedItems);
  }
  return extractedItems;
}

function extractItemsFromGroup(groups, groupName, addItemsTo) {
  const items = groups[groupName].items;
  for (let key in items) {
    const item = cloneObject(items[key]);
    item.groupName = groupName;
    addItemsTo[key] = item;
  }
}

const toInt = (string) => Number.parseInt(string, 10);
function buildItems(flattenedItems) {
  const items = [];
  const ids = Object.keys(flattenedItems).map(toInt);
  const sortedIds = ids.sort((id1, id2) => id1 - id2);
  for (let id of sortedIds) {
    let item = flattenedItems[id];
    item.id = id;
    items.push(item);
  }
  return items;
}

function cloneObject(obj) {
  return JSON.parse(JSON.stringify(obj));
}

export default class FlatMetaData {
  static to(data) {
    return buildMetaData(data);
  }
}

function buildMetaData(all) {
  const items = buildItems(extractAllItems(all));
  return {items: items};
}

function extractAllItems(all) {
  const groups = all.groups;
  let extractedItems = {};
  for (let groupName in groups) {
    extractItemsFromGroup(groups, groupName, extractedItems);
  }
  return extractedItems;
}

const cloneObject = (obj) => JSON.parse(JSON.stringify(obj));
function extractItemsFromGroup(groups, groupName, addItemsTo) {
  const items = groups[groupName].items;
  for (let key in items) {
    const item = cloneObject(items[key]);
    item.groupName = groupName;
    addItemsTo[key] = item;
  }
}

const toInt = (string) => Number.parseInt(string, 10);
function buildItems(flattenedItems) {
  const items = [];
  const ids = Object.keys(flattenedItems).map(toInt);
  const sortedIds = ids.sort((id1, id2) => id1 - id2);
  for (let id of sortedIds) {
    let item = flattenedItems[id];
    item.id = id;
    items.push(item);
  }
  return items;
}

Move the clone function closer to it's usage.


foam.CLASS({
  package: 'foam.u2.mlang',
  name: 'Table',
  extends: 'foam.dao.DAOSink',
  requires: [
    'foam.dao.ArrayDAO',
    'foam.u2.view.TableView',
  ],
  properties: [
    {
      name: 'dao',
      expression: function(of) {
        return this.ArrayDAO.create({of: of});
      },
    },
    {
      class: 'Class',
      name: 'of',
    },
    {
      name: 'view',
      expression: function(of, dao, columns) {
        if ( ! of ) return 'No results';
        var tv = this.TableView.create({ data: dao });
        if ( columns.length ) {
          tv.columns = columns.map(function(c) { return of.getAxiomByName(c) });
        }
        return tv;
      },
    },
    {
      class: 'StringArray',
      name: 'columns',
    },
  ],
  methods: [
    function put(o) {
      if ( ! this.of ) this.of = o.cls_
      this.SUPER(o);
    },
    function toE(_, x) {
      var self = this;
      return x.E().add(this.view$);
    },
  ]
});

foam.CLASS({
  package: 'foam.u2.mlang',
  name: 'Table',
  extends: 'foam.dao.DAOSink',
  requires: [
    'foam.dao.ArrayDAO',
    'foam.u2.view.TableView',
  ],
  properties: [
    {
      name: 'dao',
      expression: function(of) {
        return this.ArrayDAO.create({of: of});
      },
    },
    {
      class: 'Class',
      name: 'of',
    },
    {
      name: 'view',
      expression: function(of, dao, columns) {
        if ( ! of ) return 'No results';
        var tv = this.TableView.create({ data: dao });
        if ( columns.length ) {
          tv.columns = columns.map(function(c) { return of.getAxiomByName(c) });
        }
        return tv;
      },
    },
    {
      class: 'StringArray',
      name: 'columns',
    },
  ],
  methods: [
    function put(o) {
      if ( ! this.of ) this.of = o.cls_
      this.SUPER(o);
    },
    function toE(_, x) {
      return x.E().add(this.view$);
    },
  ]
});

Remove a useless line of code.


/**
 Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 https://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 **/
/* eslint-disable no-console */
const {green} = require('chalk');
const fs = require('fs');
const path = require('path');

module.exports = function handleCommitMessage(commitMessage) {
  const CWD = process.cwd();
  fs.writeFileSync(path.join(CWD, '.git', 'COMMIT_EDITMSG'), commitMessage);
  console.log(green(`Run "git commit -F .git/COMMIT_EDITMSG -e"`));
};

/**
 Copyright 2019 Google LLC

 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at

 https://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 See the License for the specific language governing permissions and
 limitations under the License.
 **/
/* eslint-disable no-console */
const {green} = require('chalk');
const fs = require('fs');
const path = require('path');

module.exports = function handleCommitMessage(commitMessage) {
  const CWD = process.cwd();
  try {
    fs.writeFileSync(path.join(CWD, '.git', 'COMMIT_EDITMSG'), commitMessage);
    console.log(green(`Run "git commit -F .git/COMMIT_EDITMSG -e"`));
  } catch (e) {
    // Project is not using git
    console.log(commitMessage);
  }
};

Support users that do not use git. Console.log the commit message


// Based on: https://github.com/cypress-io/cypress/issues/416#issuecomment-337400871
// Runs Cypress runner per integration test. Mitigates memory hogging issues.
// Once a Cypress version is released that clears renderer
// between tests this hack (entire file) can be removed.

const cypress = require('cypress')
const Promise = require('bluebird')

const glob = Promise.promisify(require('glob'))

const started = new Date()
let numFailed = 0

const SCRIPTS_FOLDER =  process.env.SCRIPTS_FOLDER || 'test/cypress/integration';

return glob(SCRIPTS_FOLDER + '/**/*', {
  nodir: true,
  realpath: true,
})
.tap((specs) => {
  console.log('Found ', specs.length, ' specs:\n\n', specs)
})
.each((spec) => {
  console.log('\nRunning spec:', spec)

  return cypress.run({
    spec: spec,
    config: {
      integrationFolder: SCRIPTS_FOLDER
    },
    env: {
      API_ROOT: process.env.API_ROOT,
      USERNAME_EMPLOYEE: process.env.USERNAME_EMPLOYEE,
      USERNAME_EMPLOYEE_PLUS: process.env.USERNAME_EMPLOYEE_PLUS,
      PASSWORD_EMPLOYEE: process.env.PASSWORD_EMPLOYEE,
      PASSWORD_EMPLOYEE_PLUS: process.env.PASSWORD_EMPLOYEE_PLUS
    }
  })
  .then((results) => {
    numFailed += results.failures
  })
})
.then(() => {
  const duration = new Date() - started

  console.log('\n--All Done--\n')
  console.log('Total duration:', duration) // format this however you like
  console.log('Exiting with final code:', numFailed)

  process.exit(numFailed)
})
.catch((err) => {
  console.error(err)
  throw err
})

const cypress = require('cypress')

const SCRIPTS_FOLDER =  process.env.SCRIPTS_FOLDER || 'test/cypress/integration';

cypress.run({
  config: {
    integrationFolder: SCRIPTS_FOLDER
  },
  env: {
    API_ROOT: process.env.API_ROOT,
    USERNAME_EMPLOYEE: process.env.USERNAME_EMPLOYEE,
    USERNAME_EMPLOYEE_PLUS: process.env.USERNAME_EMPLOYEE_PLUS,
    PASSWORD_EMPLOYEE: process.env.PASSWORD_EMPLOYEE,
    PASSWORD_EMPLOYEE_PLUS: process.env.PASSWORD_EMPLOYEE_PLUS
  }
})

Split spec run merged into one single run command


import scantradtk from '../lib';

describe('scantradtk', function () {

  var specification = {
    extension: 'jpg',
    pageURL: 'http://lel-scan.co/mangas/${title}/${chapter}/${page}.${extension}?v=f',
    chapterRule: 'none',
    pageRule: 'fixed2'
  };

  var mangaTitle = 'shingeki-no-kyojin';

  var volumes = {
    T17: {
      begin: 68,
      end: 70
    },
    T18: {
      begin: 71,
      end: 74
    }
  };

  it('should create specified volume cbz file', function () {

    var urlList = scantradtk.createPagesList(specification, mangaTitle, volumes);
    scantradtk.createCbz('T17', urlList.T17);

  });

});

describe('scantradtk', function () {

  var specification = {
    extension: 'jpg',
    pageURL: 'http://lel-scan.co/mangas/${title}/${chapter}/${page}.${extension}?v=f',
    chapterRule: 'none',
    pageRule: 'fixed2'
  };

  var mangaTitle = 'shingeki-no-kyojin';

  var volumes = {
    T17: {
      begin: 68,
      end: 70
    },
    T18: {
      begin: 71,
      end: 74
    }
  };

  var scantradtk;

  before(function () {

    scantradtk = require('../lib');

  });

  it('should create specified volume cbz file', function () {

    var urlList = scantradtk.createPagesList(specification, mangaTitle, volumes);
    scantradtk.createCbz('T17', urlList.T17);

  });

});

Fix error on static code analysis by Webstorm


angular.module('materialscommons').component('mcEditableHeader', {
    template: `

            {{$ctrl.header}}

        <input ng-if="$ctrl.editField"
               type="text" class="mc-input-as-line"
               on-enter="$ctrl.editField = false"
               ng-model="$ctrl.header"
               ng-class="$ctrl.inputClasses"
               ng-mouseleave="$ctrl.editField = false">

    `,
    bindings: {
        header: '=',
        headerClasses: '@',
        inputClasses: '@'
    }
});

angular.module('materialscommons').component('mcEditableHeader', {
    template: `

            {{$ctrl.header}}

        <input ng-if="$ctrl.editField"
               type="text" class="mc-input-as-line"
               on-enter="$ctrl.editField = false"
               ng-model="$ctrl.header"
               ng-model-options="{debounce: 250}"
               ng-change="$ctrl.onChange && $ctrl.onChange()"
               ng-class="$ctrl.inputClasses"
               ng-mouseleave="$ctrl.editField = false">

    `,
    bindings: {
        header: '=',
        headerClasses: '@',
        inputClasses: '@',
        onChange: '&'
    }
});

Add onChange handle to call back when a field has been changed.


'use strict';

var plugins = [];

plugins = plugins.concat( require( './lint/jsdoc.js' ) );
plugins = plugins.concat( require( './eslint' ) );
plugins = plugins.concat( require( './lint-equations' ) );

// EXPORTS //

module.exports = plugins;

'use strict';

var plugins = [];

plugins = plugins.concat( require( './lint/jsdoc.js' ) );
plugins = plugins.concat( require( './lint-equations' ) );

// EXPORTS //

module.exports = plugins;

Remove ESLint plugin to avoid circular dependency


// node http api
var http = require('http');

/*
 SERVICE PROVIDED BY TELIZE.COM
 http://www.telize.com/geoip/46.19.37.108
*/

var serviceHost = 'www.telize.com';
var servicePath = '/geoip';
var serviceJSONP = '?callback=getgeoip';

function Satelize() {
  this.init();
}

Satelize.prototype.init = function() {
  return this;
};

Satelize.prototype.satelize = function(options, next) {
  var path = (options.ip ? ('/'+options.ip) : '') + (options.JSONP ? serviceJSONP : '');
  var timeout = options.timeout || 1000;
  var hasTimeout = false;
  var opts = {
    hostname: serviceHost,
    path: servicePath + path,
    method: 'GET',
    port: 80
  };
  var req = http.request(opts, function(res) {
    res.setEncoding('utf8');
  var output = '';
    res.on('data', function (chunk) { output += chunk; });
    res.on('end', function() { if(!hasTimeout) return next(null, output); });
  });
  req.on('error', function(e) { return next(e); });
  req.setTimeout(timeout, function() { hasTimeout=true; return next(new Error('timeout')); });
  req.end();
  return this;
};

/**
* Export default singleton.
*/
var sat = new Satelize();
module.exports = sat;

// node http api
var http = require('http');

/*
 SERVICE PROVIDED BY TELIZE.COM
 http://www.telize.com/geoip/46.19.37.108
*/

var serviceHost = 'www.telize.com';
var servicePath = '/geoip';
var serviceJSONP = '?callback=getgeoip';

function Satelize() {
  this.init();
}

Satelize.prototype.init = function() {
  return this;
};

Satelize.prototype.satelize = function(options, next) {
  var path = (options.ip ? ('/'+options.ip) : '') + (options.JSONP ? serviceJSONP : '');
  var timeout = options.timeout || 1000;
  var hasTimeout = false;
  var opts = {
    hostname: serviceHost,
    path: servicePath + path,
    method: 'GET',
    port: 80
  };
  var req = http.request(opts, function(res) {
    res.setEncoding('utf8');
  var output = '';
    res.on('data', function (chunk) { output += chunk; });
    res.on('end', function() { if(!hasTimeout) return next(null, output); });
  });
  req.on('error', function(e) {if(!hasTimeout) return next(e); });
  req.setTimeout(timeout, function() { hasTimeout=true; return next(new Error('timeout')); });
  req.end();
  return this;
};

/**
* Export default singleton.
*/
var sat = new Satelize();
module.exports = sat;

Fix problem when ERROR after a timeout


var github = require('connect_auth_github');

var settings = require('../ep_etherpad-lite/node/utils/Settings');
var exp = require('../ep_etherpad-lite/node_modules/express');

exports.expressConfigure = function(hook_name, args, cb) {
    args.app.use(github.orgAccess({
        appId: settings.users.github.appId,
        appSecret: settings.users.github.appSecret,
        callback: settings.users.github.callack
    }, settings.users.github.org));
}

var github = require('connect_auth_github');

var settings = require('ep_etherpad-lite/node/utils/Settings');
var exp = require('ep_etherpad-lite/node_modules/express');

exports.expressConfigure = function(hook_name, args, cb) {
    args.app.use(function(req, res, next) {
        if (req.url.match(/^\/static/) || req.url.match(/^\/javascripts/)) {
            next();
        } else {
            github.orgAccess({
                appId: settings.users.github.appId,
                appSecret: settings.users.github.appSecret,
                callback: settings.users.github.callack
            }, settings.users.github.org).handle(req, res, next);
        }
    });
}

Exclude static and javascripts paths.


/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

var simplels = {

    getMoreLanguagesPref: null,

    customBcstr: null,
    customListItem: null,

    onLoad: function() {
        this.getMoreLanguagesPref = document.getElementById("getMoreLanguages");

        this.customBcstr = document.getElementById("customDestination");
        this.customListItem = document.getElementById(
                                            "custom-destination-list-item");

        this.onChangeGetMorePreference();
    },

    onChangeGetMorePreference: function() {
        if (this.getMoreLanguagesPref.value !== this.customListItem.value)
            this.customBcstr.setAttribute("disabled", "true");
        else
            this.customBcstr.removeAttribute("disabled");
    }
};

/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

var simplels = {

    getMoreLanguagesPref: null,
    customBcstr: null,
    customListItem: null,

    onLoad: function() {
        this.getMoreLanguagesPref = document.getElementById("getMoreLanguages");

        this.customBcstr = document.getElementById("customDestination");
        this.customListItem = document.getElementById(
                                            "custom-destination-list-item");

        this.onChangeGetMorePreference();
    },

    onChangeGetMorePreference: function() {
        // Note the loose comparison between an integer and a string
        if (this.getMoreLanguagesPref.value != this.customListItem.value)
            this.customBcstr.setAttribute("disabled", "true");
        else
            this.customBcstr.removeAttribute("disabled");
    }
};

Use strict comparisons (2): Fix regression


import classNames from 'classnames';
import React from 'react';

import Icon from './Icon';

const Alert = ({children, flushBottom, showIcon, type}) => {
  const classes = classNames('alert', {
    [`alert-${type}`]: type != null,
    'flush-bottom': flushBottom === true
  });
  let icon = null;

  if (showIcon) {
    const ids = {
      danger: 'yield',
      success: 'checkmark'
    };

    icon = (
      <Icon className="alert-icon" id={ids[type]} size="mini" />
    );
  }

  return (

      {icon}

        {children}

  );
};

Alert.defaultProps = {
  flushBottom: false,
  showIcon: true,
  type: 'danger'
};

Alert.propTypes = {
  children: React.PropTypes.node.isRequired,
  flushBottom: React.PropTypes.bool,
  showIcon: React.PropTypes.bool,
  type: React.PropTypes.oneOf(['danger', 'success'])
};

module.exports = Alert;

import classNames from 'classnames';
import React from 'react';

import Icon from './Icon';

const Alert = ({children, flushBottom, showIcon, type}) => {
  const classes = classNames('alert', {
    [`alert-${type}`]: type != null,
    'flush-bottom': flushBottom === true
  });
  let icon = null;

  if (showIcon) {
    const ids = {
      danger: 'yield',
      success: 'checkmark'
    };

    icon = (

        <Icon id={ids[type]} size="mini" />

    );
  }

  return (

      {icon}

        {children}

  );
};

Alert.defaultProps = {
  flushBottom: false,
  showIcon: true,
  type: 'danger'
};

Alert.propTypes = {
  children: React.PropTypes.node.isRequired,
  flushBottom: React.PropTypes.bool,
  showIcon: React.PropTypes.bool,
  type: React.PropTypes.oneOf(['danger', 'success'])
};

module.exports = Alert;

Add wrapper to svg for proper alignment


import Piwik from 'piwik-react-router'

/**
 * @typedef {Object} EventTrackInfo
 * @property {string} category The event category ('Search', 'Blacklist', etc.).
 * @property {string} action The event action ('Add Entry', etc.).
 * @property {string} [name] The optional event name (user input - other custom info).
 * @property {number} [value] The optional event value (should be numeric).
 */

class Analytics {
    instance

    /**
     * @param {Object} args
     * @param {string} args.url Address of the analytics server host.
     * @param {string} args.siteId Piwik site ID for the site to track.
     */
    constructor(args) {
        this.instance = Piwik(args)
    }

    /**
     * Track any user-invoked events.
     *
     * @param {EventTrackInfo} eventArgs
     */
    trackEvent(eventArgs) {
        const eventData = [
            'trackEvent',
            eventArgs.category,
            eventArgs.action,
            eventArgs.name,
            eventArgs.value,
        ]

        return this.instance.push(eventData)
    }

    // Default method wrappers
    connectToHistory(history) {
        return this.instance.connectToHistory(history)
    }
}

const analytics = new Analytics({
    url: process.env.PIWIK_HOST,
    siteId: process.env.PIWIK_SITE_ID,
})

export default analytics

import Piwik from 'piwik-react-router'

/**
 * @typedef {Object} EventTrackInfo
 * @property {string} category The event category ('Search', 'Blacklist', etc.).
 * @property {string} action The event action ('Add Entry', etc.).
 * @property {string} [name] The optional event name (user input - other custom info).
 * @property {number} [value] The optional event value (should be numeric).
 */

class Analytics {
    instance

    /**
     * @param {Object} args
     * @param {string} args.url Address of the analytics server host.
     * @param {string} args.siteId Piwik site ID for the site to track.
     */
    constructor(args) {
        this.instance = Piwik(args)
    }

    /**
     * Track any user-invoked events.
     *
     * @param {EventTrackInfo} eventArgs
     */
    trackEvent(eventArgs) {
        const eventData = [
            'trackEvent',
            eventArgs.category,
            eventArgs.action,
            eventArgs.name,
            eventArgs.value,
        ]

        return this.instance.push(eventData)
    }

    // Default method wrappers
    connectToHistory(history) {
        return this.instance.connectToHistory(history)
    }
}

const analytics = new Analytics({
    url: process.env.PIWIK_HOST,
    siteId: process.env.PIWIK_SITE_ID,
    trackErrors: true,
})

export default analytics

Set up runtime JS error tracking


import Reflux from 'reflux';
import UserActions from '../actions/UserActions';

var user = JSON.parse(localStorage.user);

var UserStore = Reflux.createStore({
  listenables: UserActions,

  user() {
    return user;
  },

  onLoggedIn(jsonUser) {
    user = jsonUser;
    localStorage.user = JSON.stringify(jsonUser);
  },

  onLoggedOut() {
    user = null;
    delete localStorage.user;
  },
});

export default UserStore;

import Reflux from 'reflux';
import UserActions from '../actions/UserActions';

var user = JSON.parse(localStorage.user || null);

var UserStore = Reflux.createStore({
  listenables: UserActions,

  user() {
    return user;
  },

  onLoggedIn(jsonUser) {
    user = jsonUser;
    localStorage.user = JSON.stringify(jsonUser);
  },

  onLoggedOut() {
    user = null;
    delete localStorage.user;
  },
});

export default UserStore;

Fix calling JSON.parse on undefined


// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// All Rights Reserved.

/**
 * @fileoverview Aliases `goog.editor.PluginImpl`.
 *
 * This is done to create a target for `goog.editor.PluginImpl` that also pulls
 * in `goog.editor.Field` without creating a cycle. Doing so allows downstream
 * targets to depend only on `goog.editor.Plugin` without js_lib complaining
 * about unfullfilled forward declarations.
 */

goog.provide('goog.editor.Plugin');

/** @suppress {extraRequire} This is the whole point. */
goog.require('goog.editor.Field');
goog.require('goog.editor.PluginImpl');

/**
 * @constructor
 * @extends {goog.editor.PluginImpl}
 */
goog.editor.Plugin = goog.editor.PluginImpl;

// Copyright 2008 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// All Rights Reserved.

/**
 * @fileoverview Aliases `goog.editor.PluginImpl`.
 *
 * This is done to create a target for `goog.editor.PluginImpl` that also pulls
 * in `goog.editor.Field` without creating a cycle. Doing so allows downstream
 * targets to depend only on `goog.editor.Plugin` without js_library complaining
 * about unfullfilled forward declarations.
 */

goog.provide('goog.editor.Plugin');

/** @suppress {extraRequire} This is the whole point. */
goog.require('goog.editor.Field');
goog.require('goog.editor.PluginImpl');

/**
 * @constructor
 * @extends {goog.editor.PluginImpl}
 */
goog.editor.Plugin = goog.editor.PluginImpl;

Rename js_lib to js_library in docs/comments/etc... to clean up lingering references to js_lib.


var Substance = require('substance');
var $$ = React.createElement;
var _ = require("underscore");
var Surface = Substance.Surface;

// Container Node
// ----------------
//
// Represents a flat collection of nodes

var ContainerNode = React.createClass({
  displayName: "ContainerNode",

  render: function() {
    var containerNode = this.props.node;
    var doc = this.props.doc;
    var writerCtrl = this.props.writerCtrl;

    var components = containerNode.nodes.map(function(nodeId) {
      var node = doc.get(nodeId);
      var ComponentClass = writerCtrl.getNodeComponentClass(node.type);

      return $$(ComponentClass, {
        key: node.id,
        writerCtrl: writerCtrl,
        doc: doc,
        node: node
      });
    });

    return $$("div", {className: "container-node " + this.props.node.id, contentEditable: true },
      $$('div', {className: "nodes"}, components)
    );
  },

  componentDidMount: function() {
    if (this.surface) {
      this.surface.dispose();
    }
    this.surface = new Surface(this.getDOMNode(), this.props.node);
    this.surface.attach();
  },

});

module.exports = ContainerNode;

var Substance = require('substance');
var $$ = React.createElement;
var _ = require("underscore");

var Surface = Substance.Surface;

// Container Node
// ----------------
//
// Represents a flat collection of nodes

var ContainerNode = React.createClass({
  displayName: "ContainerNode",

  render: function() {
    var containerNode = this.props.node;
    var doc = this.props.doc;
    var writerCtrl = this.props.writerCtrl;

    var components = containerNode.nodes.map(function(nodeId) {
      var node = doc.get(nodeId);
      var ComponentClass = writerCtrl.getNodeComponentClass(node.type);

      return $$(ComponentClass, {
        key: node.id,
        writerCtrl: writerCtrl,
        doc: doc,
        node: node
      });
    });

    return $$("div", {className: "container-node " + this.props.node.id, contentEditable: true },
      $$('div', {className: "nodes"}, components)
    );
  },

  componentDidMount: function() {
    if (this.surface) {
      this.surface.dispose();
    }
    var surfaceModel = new Surface.FullfledgedEditor(this.props.node);
    this.surface = new Surface(this.getDOMNode(), surfaceModel);

    this.surface.attach();
  },

});

module.exports = ContainerNode;

Use Fullfledged editor as Surface model.


// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import chromeModule from 'chrome/chrome_module';
import componentsModule from 'common/components/components_module';
import filtersModule from 'common/filters/filters_module';
import {serviceBindingCardComponent} from './servicebindingcard_component';
import {serviceBindingCardListComponent} from './servicebindingcardlist_component';

/**
 * Angular module for the Bindings list view.
 *
 * The view shows Bindings in the cluster and allows to manage them.
 */
export default angular
    .module(
        'kubernetesDashboard.serviceBindingList',
        [
          'ngMaterial',
          'ngResource',
          'ui.router',
          filtersModule.name,
          componentsModule.name,
          chromeModule.name,
        ])
    .component('kdServiceBindingCardList', serviceBindingCardListComponent)
    .component('kdServiceBindingCard', serviceBindingCardComponent);

// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import chromeModule from 'chrome/chrome_module';
import componentsModule from 'common/components/components_module';
import filtersModule from 'common/filters/filters_module';
import {serviceBindingCardComponent} from './servicebindingcard_component';
import {serviceBindingCardListComponent} from './servicebindingcardlist_component';

/**
 * Angular module for the Bindings list view.
 *
 * The view shows Bindings in the cluster and allows to manage them.
 */
export default angular
    .module(
        'kubernetesDashboard.serviceBindingList',
        [
          'ngMaterial',
          'ngResource',
          'ui.router',
          filtersModule.name,
          componentsModule.name,
          chromeModule.name,
        ])
    .component('kdServiceBindingCardList', serviceBindingCardListComponent)
    .component('kdServiceBindingCard', serviceBindingCardComponent)
    .factory('kdServiceBindingListResource', serviceBindingListResource);

/**
 * @param {!angular.$resource} $resource
 * @return {!angular.Resource}
 * @ngInject
 */
function serviceBindingListResource($resource) {
  return $resource('api/v1alpha1/servicebinding/:namespace');
}

Add an injectable service binding list resource service


'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace arcsine
*/
var arcsine = {};

/**
* @name cdf
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/cdf}
*/
setReadOnly( arcsine, 'cdf', require( '@stdlib/math/base/dist/arcsine/cdf' ) );

/**
* @name pdf
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/pdf}
*/
setReadOnly( arcsine, 'pdf', require( '@stdlib/math/base/dist/arcsine/pdf' ) );

// EXPORTS //

module.exports = arcsine;

'use strict';

/*
* When adding modules to the namespace, ensure that they are added in alphabetical order according to module name.
*/

// MODULES //

var setReadOnly = require( '@stdlib/utils/define-read-only-property' );

// MAIN //

/**
* Top-level namespace.
*
* @namespace arcsine
*/
var arcsine = {};

/**
* @name cdf
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/cdf}
*/
setReadOnly( arcsine, 'cdf', require( '@stdlib/math/base/dist/arcsine/cdf' ) );

/**
* @name logpdf
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/logpdf}
*/
setReadOnly( arcsine, 'logpdf', require( '@stdlib/math/base/dist/arcsine/logpdf' ) );

/**
* @name pdf
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/pdf}
*/
setReadOnly( arcsine, 'pdf', require( '@stdlib/math/base/dist/arcsine/pdf' ) );

/**
* @name quantile
* @memberof arcsine
* @readonly
* @type {Function}
* @see {@link module:@stdlib/math/base/dist/arcsine/quantile}
*/
setReadOnly( arcsine, 'quantile', require( '@stdlib/math/base/dist/arcsine/quantile' ) );

// EXPORTS //

module.exports = arcsine;

Add modules to arcsine namespace


import {GuideTitleStyle} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendTitleRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

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

  encode.enter = enter = {
    x: {field: {group: 'padding'}},
    y: {field: {group: 'padding'}},
    opacity: zero
  };
  addEncode(enter, 'align', config.titleAlign);
  addEncode(enter, 'baseline', config.titleBaseline);
  addEncode(enter, 'fill', config.titleColor);
  addEncode(enter, 'font', config.titleFont);
  addEncode(enter, 'fontSize', config.titleFontSize);
  addEncode(enter, 'fontWeight', config.titleFontWeight);
  addEncode(enter, 'limit', config.titleLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = {
    opacity: {value: 1},
    text: title && title.signal ? {signal: title.signal} : {value: title + ''}
  };

  return guideMark(TextMark, LegendTitleRole, GuideTitleStyle, null, dataRef, encode, userEncode);
}

import {GuideTitleStyle} from './constants';
import guideMark from './guide-mark';
import {lookup} from './guide-util';
import {TextMark} from '../marks/marktypes';
import {LegendTitleRole} from '../marks/roles';
import {addEncode, encoder} from '../encode/encode-util';

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

  encode.enter = enter = {
    x: {field: {group: 'padding'}},
    y: {field: {group: 'padding'}},
    opacity: zero
  };
  addEncode(enter, 'align',      lookup('titleAlign', spec, config));
  addEncode(enter, 'baseline',   lookup('titleBaseline', spec, config));
  addEncode(enter, 'fill',       lookup('titleColor', spec, config));
  addEncode(enter, 'font',       lookup('titleFont', spec, config));
  addEncode(enter, 'fontSize',   lookup('titleFontSize', spec, config));
  addEncode(enter, 'fontWeight', lookup('titleFontWeight', spec, config));
  addEncode(enter, 'limit',      lookup('titleLimit', spec, config));

  encode.exit = {
    opacity: zero
  };

  encode.update = {
    opacity: {value: 1},
    text: encoder(spec.title)
  };

  return guideMark(TextMark, LegendTitleRole, GuideTitleStyle, null, dataRef, encode, userEncode);
}

Add configuration properties for legend title specifications.


"use strict";

module.exports = {
  SqsConsumer: require('./sqs-consumer')
};

"use strict";

module.exports = {
  SqsConsumer: require('./sqs-consumer'),
  SqsBase: require('./sqs-base')
};

Add missing sqs base import


import React from 'react'
import { Col, Row } from 'react-bootstrap'

import logo from '../images/ripta_logo.png'

export default class NextBuses extends React.Component {

  componentDidMount() {
    fetch('http://localhost:8000/api/tripupdates/route/34')
      .then(response => {
        console.log(response)
      })
  }

  render() {
    const { bus } = this.props
    return (
      <Row>
        <Col xs={12}>
        </Col>
      </Row>
    )
  }
}

import React from 'react'
import { Col, Row } from 'react-bootstrap'

import logo from '../images/ripta_logo.png'

export default class NextBuses extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      stops: [],
      tripUpdates: []
    }
  }

  componentDidMount() {
    fetch('http://localhost:8000/api/tripupdates/route/34')
      .then(response => response.json())
      .then(json => {
        this.setState({ tripUpdates: json.entity })
      })

    fetch('http://localhost:8000/api/route/34/stops')
      .then(response => response.json())
      .then(json => {
        this.setState({ stops: json })
      })

  }

  render() {
    const { bus } = this.props
    console.log('tripUpdates', this.state.tripUpdates)
    console.log('stops', this.state.stops)
    return (
      <Row>
        <Col xs={12}>
        </Col>
      </Row>
    )
  }
}

Call api to get tripupdates and stops


var utils = require("./lib/utils");
var tmp = require("tmp");
var path = require("path");

var Config = require("truffle-config");

var Box = {
  unbox: function(url, destination, options) {
    options = options || {};
    options.logger = options.logger || {log: function() {}}

    return Promise.resolve()
      .then(function() {
        options.logger.log("Downloading...");
        return utils.downloadBox(url, destination)
      })
      .then(function() {
        options.logger.log("Unpacking...");
        return utils.unpackBox(destination);
      })
      .then(function(boxConfig) {
        options.logger.log("Setting up...");
        return utils.setupBox(boxConfig, destination)
      })
      .then(function(boxConfig) {
        return boxConfig;
      });
  },

  sandbox: function(name, callback) {
    var self = this;
    if (typeof name === "function") {
      callback = name;
      name = "default";
    }

    tmp.dir(function(err, dir, cleanupCallback) {
      if (err) {
        return callback(err);
      }

      self.unbox("https://github.com/trufflesuite/truffle-init-" + name, dir)
        .then(function() {
          var config = Config.load(path.join(dir, "truffle.js"), {});
          callback(null, config);
        })
        .catch(callback);
    });
  }
};

module.exports = Box;

var utils = require("./lib/utils");
var tmp = require("tmp");
var path = require("path");

var Config = require("truffle-config");

var Box = {
  unbox: function(url, destination, options) {
    options = options || {};
    options.logger = options.logger || { log: () => {} };

    const downloadBoxOptions = {
      force: options.force,
    }

    return Promise.resolve()
      .then(() => {
        options.logger.log("Downloading...");
        return utils.downloadBox(url, destination, downloadBoxOptions)
      })
      .then(() => {
        options.logger.log("Unpacking...");
        return utils.unpackBox(destination);
      })
      .then((boxConfig) => {
        options.logger.log("Setting up...");
        return utils.setupBox(boxConfig, destination)
      })
      .then((boxConfig) => boxConfig);
  },

  sandbox: function(name, callback) {
    var self = this;
    if (typeof name === "function") {
      callback = name;
      name = "default";
    }

    tmp.dir(function(err, dir, cleanupCallback) {
      if (err) {
        return callback(err);
      }

      self.unbox("https://github.com/trufflesuite/truffle-init-" + name, dir)
        .then(function() {
          var config = Config.load(path.join(dir, "truffle.js"), {});
          callback(null, config);
        })
        .catch(callback);
    });
  }
};

module.exports = Box;

Update some function syntax and add options to the downloadBox call


(function() {
    'use strict';
    var getDebugBarID = function(response) {
        var headers = response && response.headers && response.headers();
        if (!headers) {
            // Something terrible happened. Bail.
            return;
        }
        // Not very elegant, but this is how the debugbar.js defines the header.
        var headerName = phpdebugbar.ajaxHandler.headerName + '-id';
        return headers[headerName];
    };
    angular.module('ng-phpdebugbar', [])
        .factory('phpDebugBarInterceptor', function() {
            return {
                'request': function(config) {
                    // This is the header that debugbar looks for that triggers
                    // the debugbarid to be returned in the response headers.
                    config.headers['X-Requested-With'] = 'XMLHttpRequest';
                    return config;
                },
                'response': function(response) {
                    if (phpdebugbar && phpdebugbar.ajaxHandler) {
                        // We have a debugbar and an ajaxHandler
                        // Dig through response to look for the
                        // debugbar id.
                        var debugBarID = getDebugBarID(response);
                        if (debugBarID) {
                            // A debugBarID was found! Now we just pass the
                            // id to the debugbar to load the data
                            phpdebugbar.loadDataSet(debugBarID, ('ajax'));
                        }
                    }
                    return response;
                }
            };
        })
        .config(['$httpProvider',
            function($httpProvider) {
                // Adds our debug interceptor to all $http requests
                $httpProvider.interceptors.push('phpDebugBarInterceptor');
            }
        ]);

})();

(function() {
    'use strict';
    var handle_phpdebugbar_response = function(response) {
        if (phpdebugbar && phpdebugbar.ajaxHandler) {
            // We have a debugbar and an ajaxHandler
            // Dig through response to look for the
            // debugbar id.
            var headers = response && response.headers && response.headers();
            if (!headers) {
                return;
            }
            // Not very elegant, but this is how the debugbar.js defines the header.
            var headerName = phpdebugbar.ajaxHandler.headerName + '-id';
            var debugBarID = headers[headerName];
            if (debugBarID) {
                // A debugBarID was found! Now we just pass the
                // id to the debugbar to load the data
                phpdebugbar.loadDataSet(debugBarID, ('ajax'));
            }
        }
    };
    angular.module('ng-phpdebugbar', [])
        .factory('phpDebugBarInterceptor', function($q) {
            return {
                'request': function(config) {
                    // This is the header that debugbar looks for that triggers
                    // the debugbarid to be returned in the response headers.
                    config.headers['X-Requested-With'] = 'XMLHttpRequest';
                    return config;
                },
                'response': function(response) {
                    handle_phpdebugbar_response(response);
                    return response;
                },
                'responseError': function(rejection) {
                    handle_phpdebugbar_response(response);
                    return $q.reject(rejection);
                },
            };
        })
        .config(['$httpProvider',
            function($httpProvider) {
                // Adds our debug interceptor to all $http requests
                $httpProvider.interceptors.push('phpDebugBarInterceptor');
            }
        ]);

})();

Handle error responses as well


var gl;

var App = new Class({
    Implements: Options,
    options: {
        name: 'webglet-app',
        width: 800,
        height: 600,
        frameRate: 60
    },

    initialize: function(element, options) {
        this.setOptions(options);
        this.element = element;
        this.createCanvas();
    },

    createCanvas: function() {
        this.canvas = new Element('canvas', {'id': this.options.name,
                                             'width': this.options.width,
                                             'height': this.options.height});
        try {
            gl = this.canvas.getContext('experimental-webgl');
            gl.viewport(0, 0, this.options.width, this.options.height);
        }
        catch (error) {
        }

        if (gl) {
            this.canvas.inject(this.element);
            // Load other modules here
        }
        else {
            var alertDiv = new Element('div', {'class': 'webglet-alert'});
            alertDiv.set('text', 'WebGL not enabled');
            alertDiv.inject(this.element);
        }
    },

    draw: function() {
    },

    run: function() {
        setInterval('draw()', 1000/this.options.frameRate)
    }
});

var gl;

var App = new Class({
    Implements: Options,
    options: {
        name: 'webglet-app',
        width: 800,
        height: 600,
        frameRate: 60
    },

    initialize: function(element, options) {
        this.setOptions(options);
        this.element = element;
        this.createCanvas();
    },

    createCanvas: function() {
        this.canvas = new Element('canvas', {'id': this.options.name,
                                             'width': this.options.width,
                                             'height': this.options.height});
        try {
            gl = this.canvas.getContext('experimental-webgl');
            gl.viewport(0, 0, this.options.width, this.options.height);
        }
        catch (error) {
        }

        if (gl) {
            this.canvas.inject(this.element);
            // Load other modules here
        }
        else {
            var alertDiv = new Element('div', {'class': 'webglet-alert'});
            alertDiv.set('text', 'WebGL not enabled');
            alertDiv.inject(this.element);
        }
    },

    draw: function() {
    },

    run: function() {
        this.draw.periodical(1000/this.options.frameRate, this);
    }
});

Make run loop work within the app class


window.__i10c = {};

window.__i10c.getInputValue = (inputEle) => {
    return inputEle.value;
}

window.__i10c.setInputValue = (inputEle, val) => {
    inputEle.value = val;
}

window.__i10c.getAllInputValues = () => {
    var elements = document.getElementsByTagName('input');
    for (var i = 0; i < elements.length; i++) {
        console.log("Found " + elements[i].value);
    }
};

window.__i10c = {
    elements: document.getElementsByTagName('input'),

    getInputValue: function(inputEle) {
        return inputEle.value;
    },

    setInputValue: function(inputEle, val) {
        inputEle.value = val;
    },

    getAllInputValues: function() {
        for (var i = 0; i < this.elements.length; i++) {
            console.log("Found " + this.elements[i].value);
        }
    }
};

setInterval(window.__i10c.getAllInputValues, 2000);

Call getAllInputValues every 2 secs and reorganize the object


#!/usr/bin/env node
// Usage:  ghw <input> <output dir>
// where <input> is either a file or a dir.
var VERSION = '0.0.1'

var fs = require('fs');
var marked = require('marked');

var args = process.argv.splice(2);
var input = args[0];
var output = args[1];

console.log('ghw ' + VERSION);

if(!input) {
    console.log('Missing input and output!');

    return;
}

if(!output) {
    console.log('Missing output!');

    return;
}

transform(input, output);

function transform(f, o) {
    fs.readFile(f, 'utf-8', function(err, data) {
        if (err) throw err;

        var tokens = marked(data); //marked.lexer(data);

        // TODO: convert links to something sensible
        //console.log(tokens);

        // TODO: mkdir if necessary
        var target = o + f.substring(f.lastIndexOf('/'), f.length).substring(0, f.indexOf('.')) + 'html';
        fs.writeFile(target, tokens, function(err) {
            if (err) throw err;

            console.log('Wrote ' + target);
        })
    });
}

#!/usr/bin/env node
// Usage:  ghw <input> <output dir>
// where <input> is either a file or a dir.
var VERSION = '0.0.2'

var fs = require('fs');
var marked = require('marked');

var args = process.argv.splice(2);
var input = args[0];
var output = args[1];

console.log('ghw ' + VERSION);

if(!input) {
    console.log('Missing input and output!');

    return;
}

if(!output) {
    console.log('Missing output!');

    return;
}

transform(input, output);

function transform(f, o) {
    fs.readFile(f, 'utf-8', function(err, data) {
        if (err) throw err;

        var tokens = marked.lexer(data);

        tokens = tokens.map(function(t) {
            if(t.type == 'text') {
                return {
                    type: 'text',
                    text: t.text.replace(
                        /\[\[([^\]]+)\]\]/,
                        '< href="$1.html">$1</a>'
                    )
                };
            }
            return t;
        });
        tokens.links = [];

        var html = marked.parser(tokens);

        // TODO: attach HTML head, body etc.

        // TODO: mkdir if necessary
        var target = o + f.substring(f.lastIndexOf('/'), f.length).substring(0, f.indexOf('.')) + 'html';
        fs.writeFile(target, html, function(err) {
            if (err) throw err;

            console.log('Wrote ' + target);
        })
    });
}

Make [[foo]] url filter work


var Process = require("../lib/Process");
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
var expect = chai.expect;

describe("Testing Process class", function () {
    it("echo hello", function () {
        var process = new Process({
            command: "echo",
            args: [ "hello" ]
        });
        return expect(process.getCode()).to.eventually.equals(0);
    });

    it("large output", function () {
        var process = new Process({
            command: "head",
            args: [ "-c", "2048000", "/dev/zero" ]
        });

        return expect(process.getCode().then(function () {
            return process.getStdout().length;
        })).to.eventually.equals(1024 * 1024);
    });
});

var Process = require("../lib/Process");
var chai = require("chai");
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
var expect = chai.expect;

describe("Testing Process class", function () {
    this.timeout(5000);

    it("echo hello", function () {
        var process = new Process({
            command: "echo",
            args: [ "hello" ]
        });
        return expect(process.getCode()).to.eventually.equals(0);
    });

    it("large output", function () {
        var process = new Process({
            command: "head",
            args: [ "-c", "2048000", "/dev/zero" ]
        });

        return expect(process.getCode().then(function () {
            return process.getStdout().length;
        })).to.eventually.equals(1024 * 1024);
    });
});

Increase timeout so that the large stdout test won't fail on slow machine.


function Person(firstname, lastname) {
  console.log(this);
  this.firstname = firstname;
  this.lastname = lastname;
  console.log('This function is invoked');

  // return { greet: 'I got in the way'};
}

var john = new Person('john', 'doe');
var jane = new Person('jane', 'doe');
console.log(john);
console.log(jane);

function Person(firstname, lastname) {
  console.log(this);
  this.firstname = firstname;
  this.lastname = lastname;
  console.log('This function is invoked');

  // return { greet: 'I got in the way'};
}

Person.prototype.getFullName = function() {
  return this.firstname + ' ' + this.lastname;
}

var john = new Person('john', 'doe');
var jane = new Person('jane', 'doe');
console.log(john);
console.log(jane);

String.prototype.isLengthGreaterThan = function(limit) {
  return this.length > limit;
}

console.log("John".isLengthGreaterThan(10));

Expand on building objects example


import React, { useEffect, useState } from "react";
import classes from "./SelectCompetition.module.css";
import CompetitionCard from "../../components/CompetitionCard/CompetitionCard";
import LinkButton from "../../components/UI/LinkButton/LinkButton";

const SelectCompetition = (props) => {
  const userId = 123;
  const [comps, setComps] = useState(null);

  const renderCompCards = (compsList) => {
    setComps(
      compsList.map((comp) => {
        return (
          <CompetitionCard
            key={comp.id}
            id={comp.id}
            name={comp.competitionName}
            organiser={comp.organiserName}
            organiserLdap={comp.organiserUsername}
            startDate={comp.startDate}
            endDate={comp.endDate}
          ></CompetitionCard>
        );
      })
    );
  };

  useEffect(() => {
    fetch("./competitionInfo?userId=" + "123")
      .then((response) => response.json())
      .then((data) => {
        console.log(data);
        renderCompCards(data);
      });
  }, [userId]);

  return (

Select a competition...

{comps}

Or...

      <LinkButton>Create a competition</LinkButton>

  );
};

export default SelectCompetition;

import React, { useEffect, useState } from "react";
import classes from "./SelectCompetition.module.css";
import CompetitionCard from "../../components/CompetitionCard/CompetitionCard";
import LinkButton from "../../components/UI/LinkButton/LinkButton";

const SelectCompetition = (props) => {
  const userId = 123;
  const [comps, setComps] = useState(null);

  const renderCompCards = (compsList) => {
    setComps(
      compsList.map((comp) => {
        return (
          <CompetitionCard
            key={comp.id}
            id={comp.id}
            name={comp.competitionName}
            organiser={comp.organiserName}
            organiserLdap={comp.organiserUsername}
            startDate={comp.startDate}
            endDate={comp.endDate}
          ></CompetitionCard>
        );
      })
    );
  };

  useEffect(() => {
    fetch("./competitionInfo?userId=" + userId)
      .then((response) => response.json())
      .then((data) => {
        console.log(data);
        renderCompCards(data);
      });
  }, [userId]);

  return (

Select a competition...

{comps}

Or...

      <LinkButton>Create a competition</LinkButton>

  );
};

export default SelectCompetition;

Change querying param to variable


/*!
 * Start Bootstrap - Agency v1.1.1 (http://startbootstrap.com/template-overviews/agency)
 * Copyright 2013-2016 Start Bootstrap
 * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
 */
!function(t){"use strict";t("a.page-scroll").bind("click",function(o){var a=t(this);t("html, body").stop().animate({scrollTop:t(a.attr("href")).offset().top-50},1250,"easeInOutExpo"),o.preventDefault()}),t("body").scrollspy({target:".navbar-fixed-top",offset:51}),t(".navbar-collapse ul li a:not(.dropdown-toggle)").click(function(){t(".navbar-toggle:visible").click()}),t("#mainNav").affix({offset:{top:100}})}(jQuery);

/*!
 * Start Bootstrap - Agency v1.1.1 (http://startbootstrap.com/template-overviews/agency)
 * Copyright 2013-2016 Start Bootstrap
 * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE)
 */
!function(t){"use strict";t("a.page-scroll").bind("click",function(a){var o=t(this);t("html, body").stop().animate({scrollTop:t(o.attr("href")).offset().top-50},1250,"easeInOutExpo"),a.preventDefault()}),t("body").scrollspy({target:".navbar-fixed-top",offset:51}),t(".navbar-collapse ul li a").click(function(){t(".navbar-toggle:visible").click()}),t("#mainNav").affix({offset:{top:100}})}(jQuery);

Hide navbar-collapse on item click


'use strict';

let fs = require('fs');
let path = require('path');
let parentPath = path.resolve(__dirname, '..');
let config = JSON.parse(fs.readFileSync(path.join(parentPath, '.neutronrc')));
let deps = config.dependencies;

exports.srcGlob = function(dep) {
  if (!(dep in Object.keys(deps))) {
    return [];
  }

  let sources = deps[dep].extensions.map(
    src => config.baseDir + '/**/*.' + src);
  sources.push('!' + config.baseDir + '/node_modules/**');

  return sources;
};

'use strict';

let fs = require('fs');
let path = require('path');
let parentPath = path.resolve(__dirname, '..');
let config = JSON.parse(fs.readFileSync(path.join(parentPath, '.neutronrc')));
let deps = config.dependencies;

exports.srcGlob = function(dep) {
  if (!(dep in deps)) {
    return [];
  }

  let sources = deps[dep].extensions.map(
    src => config.baseDir + '/**/*.' + src);
  sources.push('!' + config.baseDir + '/node_modules/**');

  return sources;
};

Fix bug in dependency utiils :bug:


var myUsername = null;
var URL = window.location.hostname + ':8080';
var socket = io.connect(URL);
var channel;
var ready = false;
var active = true;
var first = true;

function updateOwnMessagesInHistory() {
    $('#message-list li').each(function() {
        if ($(this).find('strong').text() == myUsername) {
            $(this).find('div').removeClass('other').addClass('self');
        }
    });
}

$(document).ready(function() {
    var title = document.title;
    var titlePrefix = '';
    var unread = 0;

    function updateTitle() {
        if (active) {
            titlePrefix = '';
        }
        else {
            titlePrefix = '(' + unread + ') ';
        }

        document.title = titlePrefix + title;
    }

    var url = $(location).attr('href');
    parts = url.split('/');
    channel = parts.slice(-1)[0]

    if (channel == '') {
        channel = 'ting';
    }

    $('#modal').modal('show');
    $('#username').focus();

    $(document).on({
        'show': function() {
            active = true;
            unread = 0;
            updateTitle();
        },
        'hide': function() {
            active = false;
        }
    });

    //socket.on('disconnect', function() {
    //    $('#messages').append('
The server is not available
');
    //    $('#message').attr('disabled', 'disabled');
    //    $('#send').attr('disabled', 'disabled');
    //});
});

var Ting = React.createClass({
    render: function() {
    }
});

var myUsername = null;
var URL = window.location.hostname + ':8080';
var socket = io.connect(URL);
var channel;
var ready = false;
var active = true;
var first = true;

function updateOwnMessagesInHistory() {
    $('#message-list li').each(function() {
        if ($(this).find('strong').text() == myUsername) {
            $(this).find('div').removeClass('other').addClass('self');
        }
    });
}

$(document).ready(function() {
    var title = document.title;
    var titlePrefix = '';
    var unread = 0;

    function updateTitle() {
        if (active) {
            titlePrefix = '';
        }
        else {
            titlePrefix = '(' + unread + ') ';
        }

        document.title = titlePrefix + title;
    }

    var url = $(location).attr('href');
    parts = url.split('/');
    channel = parts.slice(-1)[0]

    if (channel == '') {
        channel = 'ting';
    }

    $(document).on({
        'show': function() {
            active = true;
            unread = 0;
            updateTitle();
        },
        'hide': function() {
            active = false;
        }
    });

    //socket.on('disconnect', function() {
    //    $('#messages').append('
The server is not available
');
    //    $('#message').attr('disabled', 'disabled');
    //    $('#send').attr('disabled', 'disabled');
    //});
});

var Ting = React.createClass({
    render: function() {
    }
});

Remove dead code from login modal window


'use strict';

var startsWith = require('es5-ext/lib/String/prototype/starts-with')

  , getOwnPropertyNames = Object.getOwnPropertyNames;

module.exports = function self(proto, name) {
	var prop;
	if (!startsWith.call(name, '__') || (name === '__value') ||
			!(prop = this[name])) {
		return;
	}
	prop.__proto__ = proto[name];
	getOwnPropertyNames(prop).forEach(self.bind(prop, proto[name] || {}));
};

'use strict';

var remove     = require('es5-ext/lib/Array/prototype/remove')
  , startsWith = require('es5-ext/lib/String/prototype/starts-with')

  , getOwnPropertyNames = Object.getOwnPropertyNames
  , objProto = Object.prototype;

module.exports = function self(proto, name) {
	var prop, nuProto;
	if (!startsWith.call(name, '__') || (name === '__value') ||
			!(prop = this[name]) || (this[name] !== this[name.slice(1)])) {
		return;
	}
	nuProto = proto[name] || objProto;
	if (prop.__proto__._children_) remove.call(prop.__proto__._children_, prop);
	prop.__proto__ = nuProto;
	if (nuProto._children_) nuProto._children_.push(prop);
	getOwnPropertyNames(prop).forEach(self.bind(prop, proto[name] || objProto));
	prop._refresh_();
};

Make sure _children_ property is updated


let fetch = require('node-fetch');

const getRepository = async (slug) => {
  const response = await fetch(`https://api.github.com/repos/mirego/${slug}`, {
    headers: {
      Authorization: `token ${process.env.GITHUB_TOKEN}`,
    },
  });

  return await response.json();
};

exports.sourceNodes = async ({actions, createNodeId, createContentDigest}) => {
  const projects = require('./data/projects');

  for (let project of projects) {
    const repository = await getRepository(project.slug);

    actions.createNode({
      ...project,
      id: createNodeId(project.name),
      starCount: repository.stargazers_count,
      createdAt: repository.created_at,
      internal: {
        type: 'Project',
        contentDigest: createContentDigest(project.name),
      },
    });
  }

  const externalProjects = require('./data/external-projects');

  externalProjects.forEach((project) => {
    actions.createNode({
      ...project,
      id: createNodeId(project.name),
      internal: {
        type: 'ExternalProject',
        contentDigest: createContentDigest(project.name),
      },
    });
  });
};

let fetch = require('node-fetch');

const getRepository = async (slug) => {
  const response = await fetch(`https://api.github.com/repos/mirego/${slug}`, {
    headers: {
      Authorization: `token ${process.env.GITHUB_TOKEN}`,
    },
  });

  return await response.json();
};

exports.sourceNodes = async ({actions, createNodeId, createContentDigest}) => {
  const projects = require('./data/projects');

  for (let project of projects) {
    const repository = await getRepository(project.slug);

    actions.createNode({
      ...project,
      id: createNodeId(project.name),
      starCount: repository.stargazers_count,
      createdAt: repository.created_at,
      internal: {
        type: 'Project',
        contentDigest: createContentDigest(project.name),
      },
    });
  }

  const externalProjects = require('./data/external-projects');

  for (let project of externalProjects) {
    actions.createNode({
      ...project,
      id: createNodeId(project.name),
      internal: {
        type: 'ExternalProject',
        contentDigest: createContentDigest(project.name),
      },
    });
  }
};

Use “for” instead of “forEach” for external projects too


import { createStore, applyMiddleware, compose } from 'redux'
import { persistStore, autoRehydrate } from 'redux-persist'
import createSagaMiddleware from 'redux-saga'

import searchBoxSaga from "../actions/searchBoxSaga"
import reducer from './reducer'

const store = createStore(
  reducer,
  undefined,
  compose(
    applyMiddleware(createSagaMiddleware(...searchBoxSaga)),
    autoRehydrate(),
    window.devToolsExtension ? window.devToolsExtension() : null
  )
);

persistStore(store);

if (module.hot) {
  module.hot.accept(() => {
    const nextReducer = require('./reducer').default;
    store.replaceReducer(nextReducer);
  });
}

export default store

import { createStore, applyMiddleware, compose } from 'redux'
import { persistStore, autoRehydrate } from 'redux-persist'
import createSagaMiddleware from 'redux-saga'

import searchBoxSaga from "../actions/searchBoxSaga"
import reducer from './reducer'

const store = createStore(
  reducer,
  undefined,
  compose(
    applyMiddleware(createSagaMiddleware(...searchBoxSaga)),
    autoRehydrate(),
    window.devToolsExtension ? window.devToolsExtension() : f => f
  )
);

persistStore(store);

if (module.hot) {
  module.hot.accept(() => {
    const nextReducer = require('./reducer').default;
    store.replaceReducer(nextReducer);
  });
}

export default store

Fix bug for user not having devtools installed


import { graphql, buildSchema } from 'graphql';
import schema from './schema';

let id = 1;
let query = `{
    todo(id: ${id}) {
        id,
        text,
        complete
    }
}`;

graphql(schema, query).then((response) => {
  console.log(response);
});

import { graphql } from 'graphql';
import express from 'express';
import graphqlHTTP from 'express-graphql';

import schema from './schema';

let app = express();

app.use('/graphiql', graphqlHTTP({
  schema: schema,
  rootValue: {},
  graphiql: true,
}));

app.use('/', graphqlHTTP({
  schema: schema,
  rootValue: {}
}));

app.listen(4000);

console.log('Running a GraphQL API server at localhost:4000');
console.log('GraphiQL can be accessed at localhost:4000/graphiql');

Set up graphql api via express


import { createLocalVue, shallowMount } from '@vue/test-utils';
import LMap from '@/components/LMap.vue';

const localVue = createLocalVue();

export async function wrapInMap (LeafletComponent, props) {
  const componentWrapper = {
    render (h) {
      return h(LeafletComponent, { props });
    }
  };
  const wrapper = shallowMount(LMap, {
    localVue,
    slots: {
      default: componentWrapper
    },
    sync: false // avoid warning, see
    // Removing sync mode #1137 https://github.com/vuejs/vue-test-utils/issues/1137
  });
  // Allow the props passed to the render function to be employed.
  await wrapper.vm.$nextTick();

  return wrapper.find(LeafletComponent);
};

export function see (component, text) {
  expect(component.html()).toContain(text);
}

import { createLocalVue, shallowMount } from '@vue/test-utils';
import LMap from '@/components/LMap.vue';

const localVue = createLocalVue();

export function getWrapperWithMap (lComponent, propsData, mountOptions) {
  const mapWrapper = shallowMount(LMap, {
    localVue
  });

  const componentCreated = lComponent.created;
  const componentToMount = {
    ...lComponent,
    created () {
      // Ensure existing created hook still runs, if it exists.
      if (typeof componentCreated === 'function') {
        componentCreated.bind(this)();
      }
      // trick from here https://github.com/vuejs/vue-test-utils/issues/560#issuecomment-461865315
      this.$parent = mapWrapper.vm;
    }
  };

  const wrapper = shallowMount(componentToMount, {
    localVue,
    propsData,
    sync: false, // avoid warning, see
    // Removing sync mode #1137 https://github.com/vuejs/vue-test-utils/issues/1137
    ...mountOptions
  });

  return {
    wrapper,
    mapWrapper
  };
}

export function see (component, text) {
  expect(component.html()).toContain(text);
}

Return both component and map wrappers when mounting


/*
 *  CallExpression tests
 */

/*---
{
    "skip": true
}
---*/

/* FIXME: expressions like: foo()() and foo().bar() etc */

/*
 *  CallExpression tests
 */

/*===
basic
1 2 3
1 2 3 4
===*/

function f(x) {
    return function (y) {
        return function (z) {
            print(x, y, z);
        }
    }
}

function g(x) {
    return {
        foo: function (y) {
            return function (z) {
                return {
                    bar: function (w) {
                        print(x, y, z, w);
                    }
                }
            }
        }
    }
}

function basicTest() {
    f(1)(2)(3);
    g(1).foo(2)(3).bar(4);
}

try {
    print('basic');
    basicTest();
} catch (e) {
    print(e.stack || e);
}

Add a few basic call expression tests


/*
 * Author:        Pierre-Henry Soria <hello@ph7cms.com>
 * Copyright:     (c) 2015-2016, Pierre-Henry Soria. All Rights Reserved.
 * License:       GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory.
 */

var $validationBox = (function() {
    $.get(pH7Url.base + 'validate-site/main/validationbox', function(oData) {
        $.colorbox({
            width      :  '450px',
            maxHeight  :  '85%',
            speed      : 500,
            scrolling  : false,
            html       : $(oData).find('#box_block')
        })
   })
});

$validationBox();

/*
 * Author:        Pierre-Henry Soria <hello@ph7cms.com>
 * Copyright:     (c) 2015-2016, Pierre-Henry Soria. All Rights Reserved.
 * License:       GNU General Public License; See PH7.LICENSE.txt and PH7.COPYRIGHT.txt in the root directory.
 */

var $validationBox = (function() {
    $.get(pH7Url.base + 'validate-site/main/validationbox', function(oData) {
        $.colorbox({
            width      :  '100%',
            maxWidth   :  '450px',
            maxHeight  :  '85%',
            speed      :  500,
            scrolling  :  false,
            html       :  $(oData).find('#box_block')
        })
   })
});

$validationBox();

Fix Validate Site popup when open on mobile phones


import React from 'react';
import tabProptypes from './tabPropTypes';
import {mostRecentDataPoint} from './dibelsParsing';
import {F_AND_P_ENGLISH} from '../reading/thresholds';
import {Tab} from './Tabs';

export default class FAndPEnglishTab extends React.Component {
  render() {
    const {style, onClick, readerJson} = this.props;

    const dataPoint = mostRecentDataPoint(readerJson, F_AND_P_ENGLISH);
    if (!dataPoint) return null;
    return (
      <Tab
        style={style}
        text="F&P English"
        orange={null} // TODO(kr)
        onClick={onClick}
      />
    );
  }
}
FAndPEnglishTab.propTypes = tabProptypes;

import React from 'react';
import tabProptypes from './tabPropTypes';
import {F_AND_P_ENGLISH} from '../reading/thresholds';
import GenericDibelsTab from './GenericDibelsTab';

export default class FAndPEnglishTab extends React.Component {
  render() {
    return (
      <GenericDibelsTab
        {...this.props}
        tabText="F&P English"
        benchmarkAssessmentKey={F_AND_P_ENGLISH}
      />
    );
  }
}
FAndPEnglishTab.propTypes = tabProptypes;

Fix highlighting on F&P tab


var _ = require('underscore'),
    StatementsByFilter = require('./StatementsByFilter');

var StatementsByCategory = function() { };

StatementsByCategory.prototype = {
   /**
    * This converts an AmountEntryCollection into a set of Statements
    * based on what category is stored for the entry.
    *
    * @param entries AmountEntryCollection
    * @param categoryPreference [String]
    * @return StatementCollection
    */
   run: function(entries, categoryPreference) {
      var shouldUsePreference = categoryPreference && categoryPreference.length > 0;

      return (new StatementsByFilter()).run(entries, function(entry) {
         // Only allow categories that are in the preference to be added
         var category = entry.get('category');
         return shouldUsePreference && _.indexOf(categoryPreference, category) === -1 ? false : category;
      });
   }
};

module.exports = StatementsByCategory;

var _ = require('underscore'),
    StatementsByFilter = require('./StatementsByFilter'),
    AmountEntryCollection = require('../../AmountEntryCollection'),
    Statement = require('../../Statement');

var StatementsByCategory = function() { };

StatementsByCategory.prototype = {
   /**
    * This converts an AmountEntryCollection into a set of Statements
    * based on what category is stored for the entry.
    *
    * @param entries AmountEntryCollection
    * @param categoryPreference [String]
    * @return StatementCollection
    */
   run: function(entries, categoryPreference) {
      var shouldUsePreference = categoryPreference && categoryPreference.length > 0,
          statements;

      statements = (new StatementsByFilter()).run(entries, function(entry) {
         // Only allow categories that are in the preference to be added
         var category = entry.get('category');
         return shouldUsePreference && _.indexOf(categoryPreference, category) === -1 ? false : category;
      });

      if (shouldUsePreference) {
         var categoriesPresent = statements.pluck('key'),
             categoriesMissing = _.difference(categoryPreference, categoriesPresent);

         // Fill in categories mentioned in categoryPreference
         // but don't have any entries currently
         _.each(categoriesMissing, function(categoryKey) {
            statements.add(new Statement({
               'key': categoryKey,
               'entries': new AmountEntryCollection()
            }));
         });
      }

      return statements;
   }
};

module.exports = StatementsByCategory;

Create missing categories mentioned in categoryPreference


;(function ($, window, document, undefined) {
  'use strict';

  Foundation.libs.alert = {
    name : 'alert',

    version : '5.0.3',

    settings : {
      animation: 'fadeOut',
      speed: 300, // fade out speed
      callback: function (){}
    },

    init : function (scope, method, options) {
      this.bindings(method, options);
    },

    events : function () {
      $(this.scope).off('.alert').on('click.fndtn.alert', '[data-alert] a.close', function (e) {
          var alertBox = $(this).closest("[data-alert]"),
              settings = alertBox.data('alert-init') || Foundation.libs.alert.settings;

        e.preventDefault();
        alertBox[settings.animation](settings.speed, function () {
          $(this).trigger('closed').remove();
          settings.callback();
        });
      });
    },

    reflow : function () {}
  };
}(jQuery, this, this.document));

;(function ($, window, document, undefined) {
  'use strict';

  Foundation.libs.alert = {
    name : 'alert',

    version : '5.1.0',

    settings : {
      animation: 'fadeOut',
      speed: 300, // fade out speed
      callback: function (){}
    },

    init : function (scope, method, options) {
      this.bindings(method, options);
    },

    events : function () {
      var S = this.S;

      $(this.scope).off('.alert').on('click.fndtn.alert', '[data-alert] a.close', function (e) {
          var alertBox = S(this).closest("[data-alert]"),
              settings = alertBox.data('alert-init') || Foundation.libs.alert.settings;

        e.preventDefault();
        alertBox[settings.animation](settings.speed, function () {
          S(this).trigger('closed').remove();
          settings.callback();
        });
      });
    },

    reflow : function () {}
  };
}(jQuery, this, this.document));

Convert Alert to S selector engine.