import React from 'react'
import Helper from '../../helpers'
import SingleComponentItemView from './SingleComponentItemView'

import './ItemView.css'

const ItemView = props => {
  const {typeID, name, quantity, components, component_me, facility_me, prices} = props
  const sum = Helper.price(props.price * quantity)
  const price = Helper.price(props.price)

  let cmps = Helper.manufactureQty(components, component_me, facility_me, quantity)
  let _components = cmps.map(val => {
    return <SingleComponentItemView
      key={val.item_id}
      typeID={val.item_id}
      name={val.item_name}
      quantity={val.qty}
      prices={prices}
    />
  })

  return (

          <img alt={name} src={`https://image.eveonline.com/Type/${typeID}_32.png`}/>

              {name}

              {'x'} {Helper.qty(quantity)}

              {price}

{_components}

  )
}

export default ItemView

import React from 'react'
import Helper from '../../helpers'
import SingleComponentItemView from './SingleComponentItemView'

import './ItemView.css'

const ItemView = props => {
  const {typeID, name, quantity, components, component_me, facility_me, prices} = props
  let price = 0
  let cmps = Helper.manufactureQty(components, component_me, facility_me, quantity)
  let _components = cmps.map(val => {
    price += val.qty * prices[val.item_id]
    return <SingleComponentItemView
      key={val.item_id}
      typeID={val.item_id}
      name={val.item_name}
      quantity={val.qty}
      prices={prices}
    />
  })

  return (

          <img alt={name} src={`https://image.eveonline.com/Type/${typeID}_32.png`}/>

              {name}

              {'x'} {Helper.qty(quantity)}

              {Helper.price(price)}

{_components}

  )
}

export default ItemView

Add summary price own components --skip-ci


import React from 'react';

const mapValuesToDefaultState = (defaultState, item) => {
    if (typeof item === 'string') {
        defaultState[item] = '';
    }

    if (typeof item === 'object') {
        const { key, value } = item;
        defaultState[key] = value;
    }
}

const withLinkState = (state = []) => Component => {
    const defaultState = {};

    if (!Array.isArray(state)) {
        throw new Error('keys must be an Array of Strings/Objects!');
    }

    state.forEach(item => mapValuesToDefaultState(defaultState, item));

    class LinkStateComponent extends React.Component {
        state = defaultState;

        render() {
            return (
                <Component
                    getState={this.getState}
                    linkState={this.linkState}
                    getValue={this.getValue}
                    updateState={this.updateState}
                    {...this.props}
                />
            );
        }

        linkState = (key, callback) => ({
            value: this.state[key] || '',
            onChange: event => {
                let value = event.target.value;

                if (callback && typeof(callback) === 'function') {
                    const modifiedValue = callback(event.target.value);
                    value = modifiedValue ? modifiedValue : value;
                }

                this.updateState({
                    [key]: value
                });
            }
        });

        getState = () => this.state;

        getValue = key => this.state[key] || '';

        updateState = (object, callback = undefined) => this.setState(object, callback);
    }

    return LinkStateComponent;
};

export default withLinkState;

import React from 'react';

const mapValuesToDefaultState = (defaultState, item) => {
    if (typeof item === 'string') {
        defaultState[item] = '';
    }

    if (typeof item === 'object') {
        const { key, value } = item;
        defaultState[key] = value;
    }
}

const withLinkState = (baseState = []) => Component => {
    const defaultState = {};

    if (!Array.isArray(baseState)) {
        throw new Error('keys must be an Array of Strings/Objects!');
    }

    baseState.forEach(item => mapValuesToDefaultState(defaultState, item));

    class LinkStateComponent extends React.Component {
        state = defaultState;

        render() {
            return (
                <Component
                    getState={this.getState}
                    linkState={this.linkState}
                    getValue={this.getValue}
                    updateState={this.updateState}
                    {...this.props}
                />
            );
        }

        linkState = (key, callback) => ({
            value: this.state[key] || '',
            onChange: event => {
                let value = event.target.value;

                if (callback && typeof(callback) === 'function') {
                    const modifiedValue = callback(event.target.value);
                    value = modifiedValue ? modifiedValue : value;
                }

                this.updateState({
                    [key]: value
                });
            }
        });

        getState = () => this.state;

        getValue = key => this.state[key] || '';

        updateState = (object, callback = undefined) => this.setState(object, callback);
    }

    return LinkStateComponent;
};

export default withLinkState;

Rename state variable to baseState


var ProfessionsPageController = (function(){
    function ProfessionsPageController(
        currentProfessions,
        currentPaths,
        $location
    ) {
        this.professions = currentProfessions.getCurrentData().professions;
        this.currentPaths = currentPaths;
        this.$location = $location;
    }

    ProfessionsPageController.prototype.loadPaths = function(chosenProfession) {
        this.currentPaths.setNewData(chosenProfession.educationPaths);
        this.$location.path('/paths');
    };

    ProfessionsPageController.$inject = [
        'currentProfessions',
        'currentPaths',
        '$location'
    ];
    return ProfessionsPageController;
})();

function configProfessionsPageRoute($routeProvider) {
    $routeProvider.when('/professions', {
        templateUrl: 'professions-page/professionsPage.html',
        controller: ProfessionsPageController,
        controllerAs: 'professionsPage'
    });
}
configProfessionsPageRoute.$inject = ['$routeProvider'];

angular.module('myApp.searchPage', ['ngRoute'])
    .config(configProfessionsPageRoute);

var ProfessionsPageController = (function(){
    function ProfessionsPageController(
        currentProfessions,
        currentPaths,
        $location
    ) {
        this.professions = currentProfessions.getCurrentData().professions;
        this.currentPaths = currentPaths;
        this.currentProfessions = currentProfessions;
        this.$location = $location;
    }

    ProfessionsPageController.prototype.loadPaths = function(chosenProfession) {
        this.currentProfessions.setNewData(chosenProfession);
        this.currentPaths.setNewData(chosenProfession.educationPaths);
        this.$location.path('/paths');
    };

    ProfessionsPageController.$inject = [
        'currentProfessions',
        'currentPaths',
        '$location'
    ];
    return ProfessionsPageController;
})();

function configProfessionsPageRoute($routeProvider) {
    $routeProvider.when('/professions', {
        templateUrl: 'professions-page/professionsPage.html',
        controller: ProfessionsPageController,
        controllerAs: 'professionsPage'
    });
}
configProfessionsPageRoute.$inject = ['$routeProvider'];

angular.module('myApp.searchPage', ['ngRoute'])
    .config(configProfessionsPageRoute);

Fix title of paths page when redirected from professions page


describe('Support module', function () {
  var S = GameOfLife.Support;

  it('inverts an object', function () {
    var obj = { foo: 1, bar: 2};
    expect(S.invertObject(obj)).toEqual({1: 'foo', 2: 'bar'});
  });

  describe('For validating canvas', function () {
    it('throws InvalidArgument if given other than a canvas element', function () {
      expect(function () {
        S.validateCanvas($('
foo
')[0]);
      }).toThrow(new S.InvalidArgument('Not a canvas element'));
    });

    it('returns the given element if the element is a canvas', function () {
      expect(S.validateCanvas($('<canvas></canvas>')[0]).getContext).toBeFunction();
    });
  });
});

describe('Support module', function () {
  var S   = GameOfLife.Support
    , CT  = S.CellTypes;

  it('inverts an object', function () {
    var obj = { foo: 1, bar: 2};
    expect(S.invertObject(obj)).toEqual({1: 'foo', 2: 'bar'});
  });

  describe('For validating canvas', function () {
    it('throws InvalidArgument if given other than a canvas element', function () {
      expect(function () {
        S.validateCanvas($('
foo
')[0]);
      }).toThrow(new S.InvalidArgument('Not a canvas element'));
    });

    it('returns the given element if the element is a canvas', function () {
      expect(S.validateCanvas($('<canvas></canvas>')[0]).getContext).toBeFunction();
    });
  });

  describe('For parsing a cell grid', function () {
    it('throws InvalidArgument if layout is a blank string', function () {
      expect(function () {
        S.parseCellGrid(' ');
      }).toThrow(new S.InvalidArgument('Cell grid is not a two-dimensional matrix'));
    });

    it('throws InvalidArgument if layout has unknown symbol', function () {
      var symbol = ','
      expect(function () {
        S.parseCellGrid(symbol);
      }).toThrow(new S.InvalidArgument('Unknown cell symbol: ' + symbol));
    });

    it('throws InvalidArgument if layout is not a rectangle', function () {
      expect(function () {
        S.parseCellGrid("..\n.");
      }).toThrow(new S.InvalidArgument('Cell grid is not a rectangle'));
    });

    it('parses a valid layout', function () {
      expect(S.parseCellGrid("..\n.*")).toEqual([[CT.Dead, CT.Dead], [CT.Dead, CT.Alive]]);
    });
  });
});

Add unit tests for cell grid parsing


import test from 'ava';

test.todo('Write test for Registry.emit');

import test from 'ava';
import Registry from '../src/registry';

test('Registry.emit calls each handler', t => {

    let registry = Registry([]);

    registry.on('enter', x => t.true(x === 'a'));
    registry.on('enter', y => t.true(y === 'a'));

    registry.on('exit', x => t.true(x === 'b'));
    registry.on('exit', y => t.true(y === 'b'));

    registry.once('enter', x => t.true(x === 'a'));
    registry.once('enter', y => t.true(y === 'a'));

    registry.once('exit', x => t.true(x === 'b'));
    registry.once('exit', y => t.true(y === 'b'));

    registry.emit('enter', 'a');
    registry.emit('exit', 'b');

});

test('Registry.emit removes once handlers', t => {

    let registry = Registry([]);

    registry.once('enter', () => {});
    t.true(registry.singles.enter.length === 1);

    registry.emit('enter', {});
    t.true(!registry.singles.enter.length);

});

test('Registry.emit returns the registry', t => {

    let registry = Registry([]);
    t.deepEqual(registry.emit('enter', {}), registry);

});

Add initial tests for Registry.emit


module.exports = function () {
  if (process.platform === 'win32') {
    registerProtocolHandler('magnet', 'URL:BitTorrent Magnet URL', 'WebTorrent.exe')
  }
}

function registerProtocolHandler (protocol, name, command) {
  var Registry = require('winreg')

  var protocolKey = new Registry({
    hive: Registry.HKCU, // HKEY_CURRENT_USER
    key: '\\Software\\Classes\\' + protocol
  })
  protocolKey.set('', Registry.REG_SZ, name, callback)
  protocolKey.set('URL Protocol', Registry.REG_SZ, '', callback)

  var commandKey = new Registry({
    hive: Registry.HKCU,
    key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command'
  })
  commandKey.set('', Registry.REG_SZ, '"' + command + '" "%1"', callback)

  function callback (err) {
    if (err) console.error(err.message || err)
  }
}

var electron = require('electron')

var app = electron.app

module.exports = function () {
  if (process.platform === 'win32') {
    registerProtocolHandler('magnet', 'URL:BitTorrent Magnet URL', app.getPath('exe'))
  }
}

function registerProtocolHandler (protocol, name, command) {
  var Registry = require('winreg')

  var protocolKey = new Registry({
    hive: Registry.HKCU, // HKEY_CURRENT_USER
    key: '\\Software\\Classes\\' + protocol
  })
  protocolKey.set('', Registry.REG_SZ, name, callback)
  protocolKey.set('URL Protocol', Registry.REG_SZ, '', callback)

  var commandKey = new Registry({
    hive: Registry.HKCU,
    key: '\\Software\\Classes\\' + protocol + '\\shell\\open\\command'
  })
  commandKey.set('', Registry.REG_SZ, '"' + command + '" "%1"', callback)

  function callback (err) {
    if (err) console.error(err.message || err)
  }
}

Use real path to WebTorrent.exe


var path        = require('path');
var chalk       = require('chalk');
var Promise     = require('../../lib/ext/promise');
var stringUtils = require('../../lib/utils/string');
var runCommand  = require('../../lib/utils/run-command');

module.exports = {
  // Allows the generator to not require an entity name
  normalizeEntityName: function(entityName) {
    return entityName;
  },

  locals: function(options) {
    var name = options.project.pkg.name;

    return {
      namespace:     stringUtils.classify(name),
      modulePrefix:  stringUtils.dasherize(name)
    }
  },

  addPluginToProject: function(name) {
    var ui = this.ui;

    return runCommand('cordova plugin add ' + name, null, {
      cwd: path.join(this.project.root, 'cordova')
    })().then(function() {
      if (ui) {
        ui.writeLine('  ' + chalk.green('install plugin') + ' ' + name);
      }
    });
  },

  afterInstall: function() {
    return Promise.all([
      this.addPackageToProject('broccoli-sass'),
      this.addPackageToProject('liquid-fire'),
      this.addPackageToProject('ember-mobiletouch')
    ]);
  }
};

var path        = require('path');
var chalk       = require('chalk');
var Promise     = require('../../lib/ext/promise');
var stringUtils = require('../../lib/utils/string');
var runCommand  = require('../../lib/utils/run-command');

module.exports = {
  // Allows the generator to not require an entity name
  normalizeEntityName: function(entityName) {
    return entityName;
  },

  locals: function(options) {
    var name = options.project.pkg.name;

    return {
      namespace:     stringUtils.classify(name),
      modulePrefix:  stringUtils.dasherize(name)
    }
  },

  addPluginToProject: function(name) {
    var ui = this.ui;

    return runCommand('cordova plugin add ' + name, null, {
      cwd: path.join(this.project.root, 'cordova')
    })().then(function() {
      if (ui) {
        ui.writeLine('  ' + chalk.green('install plugin') + ' ' + name);
      }
    });
  },

  afterInstall: function() {
    return Promise.all([
      this.addPackageToProject('broccoli-sass'),
      this.addPackageToProject('liquid-fire'),
      this.addPackageToProject('ember-gestures')
    ]);
  }
};

Replace ember-mobiletouch (deprecated) with ember-gestures (recommended replacement)


(function() {
    //
    // Avoid sudden background resize on mobile browsers when the address bar is hidden.
    //

    var homeTop = document.querySelector('.home__top');
    var windowWidth;

    function onWindowResize() {
        if (window.innerWidth !== windowWidth) {
            windowWidth = window.innerWidth;
            homeTop.style.height = window.innerHeight + 'px';
        }
    }

    window.addEventListener('resize', onWindowResize);
    onWindowResize();

    //
    // Blur high-res background.
    //

    var bg = document.querySelector('.home__background--high-res');
    var bgImage = getComputedStyle(bg).backgroundImage;
    var bgImageUrl = bgImage.split('"')[1];

    var img = new Image();
    img.addEventListener('load', function() {
        bg.className += ' home__background--high-res--loaded';
    });
    img.src = bgImageUrl;
}());

(function() {
    //
    // Avoid sudden background resize on mobile browsers when the address bar is hidden.
    //

    var homeTop = document.querySelector('.home__top');
    var windowWidth;

    function onWindowResize() {
        if (window.innerWidth !== windowWidth) {
            windowWidth = window.innerWidth;
            homeTop.style.height = window.innerHeight + 'px';
        }
    }

    window.addEventListener('resize', onWindowResize);
    onWindowResize();

    //
    // Blur high-res background.
    //

    var bg = document.querySelector('.home__background--high-res');
    var bgImage = getComputedStyle(bg).backgroundImage;
    var bgImageUrl = /(?:\(['|"]?)(.*?)(?:['|"]?\))/.exec(bgImage)[1];

    var img = new Image();
    img.addEventListener('load', function() {
        bg.className += ' home__background--high-res--loaded';
    });
    img.src = bgImageUrl;
}());

Update bg image extraction to support Safari


(function() {
  'use strict';

  angular.module('nin').directive('demo', function($interval, demo) {
    return {
      restrict: 'E',
      template: '

',
      link: function(scope, element) {
        demo.setContainer(element[0].children[0]);
        setTimeout(function() {
          demo.resize();
        });

        scope.$watch('fullscreen', function (toFullscreen){
          if (toFullscreen) {
            // go to fullscreen
            element[0].children[0].classList.add('fullscreen');
          } else {
            // exit fullscreen
            element[0].children[0].classList.remove('fullscreen');
          }
          demo.resize();
        });

        scope.$watch('mute', function (toMute) {
          if (toMute) {
            demo.music.setVolume(0);
          } else {
            demo.music.setVolume(scope.volume);
          }
        });

        scope.$watch('volume', function(volume) {
          if (scope.mute) return;
          demo.music.setVolume(volume);
        });

        $interval(function() {
          scope.$parent.$parent.currentFrame = demo.getCurrentFrame();
          scope.$parent.$parent.duration = demo.music.getDuration() * 60;
        }, 1000 / 60);

        setTimeout(function(){
          demo.start();
          demo.music.pause();
        }, 0);
      }
    };
  });
})();

(function() {
  'use strict';

  angular.module('nin').directive('demo', function($interval, demo) {
    return {
      restrict: 'E',
      template: '

',
      link: function(scope, element) {
        demo.setContainer(element[0].children[0]);
        setTimeout(function() {
          demo.resize();
        });

        scope.$watch('fullscreen', function (toFullscreen){
          if (toFullscreen) {
            // go to fullscreen
            element[0].children[0].classList.add('fullscreen');
          } else {
            // exit fullscreen
            element[0].children[0].classList.remove('fullscreen');
          }
          demo.resize();
        });

        scope.$watch('mute', function (toMute) {
          if (toMute) {
            demo.music.setVolume(0);
          } else {
            demo.music.setVolume(scope.volume);
          }
        });

        scope.$watch('volume', function(volume) {
          if (scope.mute) return;
          demo.music.setVolume(volume);
        });

        $interval(function() {
          scope.$parent.$parent.currentFrame = demo.getCurrentFrame();
          scope.$parent.$parent.duration = demo.music.getDuration() * 60;
        }, 1000 / 60);

        setTimeout(function(){
          demo.start();
          demo.music.pause();
          demo.jumpToFrame(0);
        }, 0);
      }
    };
  });
})();

Add more explicit jumpToFrame during frontend load


import express from 'express';
import Debug from 'debug';
import path from 'path';
import Router from './router';

const debug = Debug('league-tooltips:middleware');

export default (apiKey, region, opts = {}) => {
  debug('Init middleware', region);
  const rawRoute = opts.url || '/';
  const parsedRoute = path.parse(rawRoute).base;
  const route = `${parsedRoute}/`;

  debug('Route', route);

  debug('Initializing base router');
  const router = express();
  router.use(route, (req, res, next) => {
    // Include the mount path of the application in the middleware route
    res.locals.tooltipsRoute = path.join(req.app.mountpath, route);
    next();
  });
  const routerMiddleware = new Router(apiKey, region, route, opts);
  router.use(route, routerMiddleware.create());
  debug('Initialized base router');

  debug(`Serving the tooltips on ${route}`);

  return router;
};

import express from 'express';
import Debug from 'debug';
import path from 'path';
import Router from './router';

const debug = Debug('league-tooltips:middleware');

export default (apiKey, region, opts = {}) => {
  debug('Init middleware', region);
  const rawRoute = opts.url || '/';
  const parsedRoute = path.parse(rawRoute).base;
  const route = `${parsedRoute}/`;

  debug('Route', route);

  debug('Initializing base router');
  const router = express();
  router.use(route, (req, res, next) => {
    debug('App mount path', req.app.mountpath);
    // Include the mount path of the application in the middleware route
    res.locals.tooltipsRoute = path.join(req.app.mountpath, route);
    next();
  });
  const routerMiddleware = new Router(apiKey, region, route, opts);
  router.use(route, routerMiddleware.create());
  debug('Initialized base router');

  debug(`Serving the tooltips on ${route}`);

  return router;
};

Debug log of app mount path


require.config({
  baseUrl: '/js',
  paths: {
      'jquery': '/vendor/jquery',
  }
});

require.config({
  baseUrl: '/js',
  paths: {
      'jquery': '/vendor/jquery',
      'es-glue': 'es-glue'
  }
});

Add es-glue to the CommonJS paths.


'use strict';

var assert = require('assert')

var dataServiceFactory = require('./dataService')

function createDataServices(config) {
  var dataServices = {}

  config.forEach((dsConfig) => {
    dataServices[dsConfig.name] = dataServiceFactory(dsConfig)
  })

  return dataServices
}

/**
 * DataService controller.
 * Provides a getDataServiceForLayer method to take a layer config and
 * return a predefined DataService
 */
class DataServiceController {

  /**
   * @constructor
   * @param {object} config
   */
  constructor(config) {
    this.config = config

    this.dataServices = createDataServices(config)
  }

  /**
   * Convenience method to retrieve a dataSource for the given layerConfig definition
   * Also verifies that the layer references a known dataSource
   */
  getDataServiceForLayer(layerConfig) {
    assert.ok(!!this.dataServices[layerConfig.dataSource], 'Layer ' + layerConfig.name + ' specifies a dataSource that doesn\'t exist')

    return this.dataServices[layerConfig.dataSource]
  }
}

/**
 * Module entry point. Validates config object input using asserts
 * @param {object} config
 * @return {DataServiceController}
 */
module.exports = (config) => {
  return new DataServiceController(config)
}

'use strict';

var assert = require('assert')

var dataServiceFactory = require('./dataService')

function createDataServices(config) {
  var dataServices = {}

  config.forEach((dsConfig) => {
    dataServices[dsConfig.name] = dataServiceFactory(dsConfig)
  })

  return dataServices
}

/**
 * DataService controller.
 * Provides a getDataServiceForLayer method to take a layer config and
 * return a predefined DataService
 */
class DataServiceController {

  /**
   * @constructor
   * @param {object} config
   */
  constructor(config) {
    this.config = config || []

    this.dataServices = createDataServices(this.config)
  }

  /**
   * Convenience method to retrieve a dataSource for the given layerConfig definition
   * Also verifies that the layer references a known dataSource
   */
  getDataServiceForLayer(layerConfig) {
    assert.ok(!!this.dataServices[layerConfig.dataSource], 'Layer `' + layerConfig.name + '` specifies a dataSource that doesn\'t exist')

    return this.dataServices[layerConfig.dataSource]
  }
}

/**
 * Module entry point. Validates config object input using asserts
 * @param {object} config
 * @return {DataServiceController}
 */
module.exports = (config) => {
  return new DataServiceController(config)
}

Fix default object and validation


import xhr from 'xhr'

function isString (obj) { return (typeof (obj) === 'string') }
function isSuccess (code) { return (code >= 200 && code <= 399) }

async function get (url) {
  return request(url, 'GET')
}

async function post (url, payload) {
  return request(url, 'POST', payload)
}

async function request (url, method, payload = undefined) {
  return new Promise(
    function (resolve, reject) {
      const headers = {}
      if (payload) {
        headers['Content-Type'] = 'application/json'
      }

      const options = {
        body: isString(payload) ? payload : JSON.stringify(payload),
        headers: headers,
        uri: url,
        method: method
      }

      const callback = function (err, resp, body) {
        if (!err && isSuccess(resp.statusCode)) {
          resolve(JSON.parse(body))
        } else {
          reject(resp.statusCode)
        }
      }

      xhr(options, callback)
    }
  )
}

export { get, post }

import xhr from 'xhr'

function isString (obj) { return (typeof (obj) === 'string') }
function isSuccess (code) { return (code >= 200 && code <= 399) }

async function get (url, deserialize = true) {
  return request(url, 'GET', deserialize)
}

async function post (url, payload) {
  return request(url, 'POST', true, payload)
}

async function request (url, method, deserialize = true, payload = undefined) {
  return new Promise(
    function (resolve, reject) {
      const headers = {}
      if (payload) {
        headers['Content-Type'] = 'application/json'
      }

      const options = {
        body: isString(payload) ? payload : JSON.stringify(payload),
        headers: headers,
        uri: url,
        method: method
      }

      const callback = function (err, resp, body) {
        if (!err && isSuccess(resp.statusCode)) {
          if (deserialize) {
            resolve(JSON.parse(body))
          } else {
            resolve(body)
          }
        } else {
          reject(resp.statusCode)
        }
      }

      xhr(options, callback)
    }
  )
}

export { get, post }

Add an option to enable/disable JSON parsing


import Ember from 'ember';
import C from 'ui/utils/constants';

export default Ember.Route.extend({
  k8s: Ember.inject.service(),

  model() {
    return this.get('store').findAll('container').then((containers) => {
      let inst = null;
      for ( let i = 0 ; i < containers.get('length') ; i++)
      {
        let container = containers.objectAt(i);
        if ( container.get('state') !== 'running' )
        {
          continue;
        }

        var labels = container.get('labels')||{};
        if ( labels[C.LABEL.K8S_KUBECTL]+'' === 'true' )
        {
          inst = container;
          break;
        }
      }

      if ( inst )
      {
        return Ember.Object.create({
          command: ['/bin/bash','-l','-c','echo "# Run kubectl commands inside here\n# e.g. kubectl get rc\n"; TERM=xterm-256color /bin/bash'],
          instance: inst,
        });
      }
      else
      {
        return Ember.RSVP.reject('Unable to find an active kubectld container');
      }
    });
  },
});

import Ember from 'ember';
import C from 'ui/utils/constants';

export default Ember.Route.extend({
  k8s: Ember.inject.service(),

  model() {
    return this.get('store').findAll('container').then((containers) => {
      let inst = null;
      for ( let i = 0 ; i < containers.get('length') ; i++)
      {
        let container = containers.objectAt(i);
        if ( container.get('state') !== 'running' )
        {
          continue;
        }

        var labels = container.get('labels')||{};
        if ( labels[C.LABEL.K8S_KUBECTL]+'' === 'true' )
        {
          inst = container;
          break;
        }
      }

      if ( inst )
      {
        return Ember.Object.create({
          command: ['/bin/bash','-l','-c','echo "# Run kubectl commands inside here\n# e.g. kubectl get rc\n"; TERM=xterm-256color /bin/bash'],
          instance: inst,
        });
      }
      else
      {
        return Ember.RSVP.reject('Unable to find an active kubectld container');
      }
    });
  },

  resetController: function (controller, isExiting/*, transition*/) {
    if (isExiting)
    {
      controller.set('step', 1);
      controller.set('kubeconfig', null);
    }
  },
});

Reset kubectl config when leaving page


JARS.internal('InternalBootstrapper', function(InternalsManager) {
    'use strict';

    var getInternal = InternalsManager.get,
        InternalBootstrapper;

    /**
     * @namespace
     *
     * @memberof JARS.internals
     */
    InternalBootstrapper = {
        bootstrap: function() {
            var SourceManager = getInternal('SourceManager'),
                System = getInternal('System'),
                Loader = getInternal('Loader'),
                ConfigsManager = getInternal('ConfigsManager'),
                InterceptionManager = getInternal('InterceptionManager');

            InterceptionManager.addInterceptor(getInternal('PluginInterceptor'));

            InterceptionManager.addInterceptor(getInternal('PartialModuleInterceptor'));

            Loader.getRootModule().$export();

            Loader.registerModule('System', ['Logger', 'Modules']).$export(function systemFactory() {
                // TODO maybe calling the internal factory for System is the better option
                // to isolate System on a per context basis but right now this is enough

                /**
                 * @global
                 * @module System
                 * @see JARS.internals.System
                 */
                return System;
            });

            ConfigsManager.update({
                modules: [{
                    basePath: SourceManager.BASE_PATH,

                    cache: true,

                    minified: false,

                    timeout: 5
                }, {
                    restrict: 'System.*',

                    basePath: SourceManager.INTERNALS_PATH
                }]
            });
        }
    };

    return InternalBootstrapper;
});

JARS.internal('InternalBootstrapper', function(InternalsManager) {
    'use strict';

    var getInternal = InternalsManager.get,
        InternalBootstrapper;

    /**
     * @namespace
     *
     * @memberof JARS.internals
     */
    InternalBootstrapper = {
        bootstrap: function() {
            var SourceManager = getInternal('SourceManager'),
                System = getInternal('System'),
                Loader = getInternal('Loader'),
                ConfigsManager = getInternal('ConfigsManager');

            Loader.getRootModule().$export();

            Loader.registerModule('System', ['Logger', 'Modules']).$export(function systemFactory() {
                // TODO maybe calling the internal factory for System is the better option
                // to isolate System on a per context basis but right now this is enough

                /**
                 * @global
                 * @module System
                 * @see JARS.internals.System
                 */
                return System;
            });

            ConfigsManager.update({
                modules: [{
                    basePath: SourceManager.BASE_PATH,

                    cache: true,

                    minified: false,

                    timeout: 5
                }, {
                    restrict: 'System.*',

                    basePath: SourceManager.INTERNALS_PATH
                }],

                interceptors: [
                    getInternal('PluginInterceptor'),
                    getInternal('PartialModuleInterceptor')
                ]
            });
        }
    };

    return InternalBootstrapper;
});

Add built-in interceptors via configration


var $ = $ || function() {}; // Keeps from throwing ref errors.

function swapselected(from, to) {
	$(to).html(options[$(from).val()]);
}

function detailselected(from, to) {
	$(to).text(details[$(from).val()]);
}

$(function() {
	$("#grp-slct").change(
		function() {
			swapselected("#grp-slct", "#subgrp-slct");
		});
	$("#subgrp-slct").change(
		function() {
			detailselected("#subgrp-slct", "#detail-msg");
		});

});

var $ = $ || function() {}; // Keeps from throwing ref errors.

function swapselected(from, to) {
	$(to).html(options[$(from).val()]);
}

function detailselected(from, to) {
	$(to).text(details[$(from).val()]);
}

$(function() {
	$("#grp-slct").change(
		function() {
			swapselected("#grp-slct", "#subgrp-slct");
		});
	$("#subgrp-slct").change(
		function() {
			detailselected("#subgrp-slct", "#detail-msg");
			$("#activity_key").attr("value", $("#subgrp-slct").val());
		});

});

Add the hidden activity value to the form so we know which activity has been selected.


import "./App.css";

import React, { Component } from "react";
import { Route } from "react-router-dom";

//Components
import Header from "./components/Header";
import Basic from "./components/BasicExample";
import PropExample from "./components/PropExample";
import CallbackExample from "./components/CallbackExample";

export default class App extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="container-fluid">
        <Route exact path="/" component={Header}>
          <Header />
        </Route>

        <Route path="/example/basic" component={Basic}>
          <Basic />
        </Route>

        <Route path="/example/props" component={PropExample}>
          <Basic />
        </Route>

        <Route path="/example/callback" component={CallbackExample}>
          <CallbackExample />
        </Route>
      </div>
    );
  }
}

import "./App.css";

import React, { Component } from "react";
import { Route } from "react-router-dom";

//Components
import Header from "./components/Header";
import Basic from "./components/BasicExample";
import PropExample from "./components/PropExample";
import CallbackExample from "./components/CallbackExample";

export default class App extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <div className="container-fluid">
        <Route exact path="/" component={Header} />

        <Route path="/example/basic" component={Basic} />

        <Route path="/example/props" component={PropExample} />

        <Route path="/example/callback" component={CallbackExample} />
      </div>
    );
  }
}

Fix console error about having both child and component in react router


require('./request-store-manage');

var glimpse = require('glimpse'),
    resourceRepository = require('./request-repository-remote'),
    localRepository = require('./request-repository-local'),
    streamRepository = require('./request-repository-stream');

module.exports = {
    triggerGetLatestSummaryForSession: function(sessionId) {
        // TODO: Not sure how this is going to work yet
        //       i.e. triggering a request for given sessions request
    triggerGetLastestSummaries: function() {
        resourceRepository.triggerGetLastestSummaries();
        localRepository.triggerGetLastestSummaries();
    },
    triggerGetDetailFor: function(requestId) {
        resourceRepository.triggerGetDetailFor(requestId);
        localRepository.triggerGetDetailFor(requestId);
    },
    // TODO: Need to look and see if this is the best place for these
    subscribeToLatestSummaries: function() {
        streamRepository.subscribeToLatestSummaries();
    },
    subscribeToLatestSummariesPatches: function() {
        streamRepository.subscribeToLatestSummariesPatches();
    },
    subscribeToDetailPatchesFor: function(requestId) {
        streamRepository.subscribeToDetailPatchesFor(requestId);
    }
};

require('./request-store-manage');

var glimpse = require('glimpse'),
    resourceRepository = require('./request-repository-remote'),
    localRepository = require('./request-repository-local'),
    streamRepository = require('./request-repository-stream');

module.exports = {
    triggerGetLastestSummaries: function() {
        resourceRepository.triggerGetLastestSummaries();
        localRepository.triggerGetLastestSummaries();
    },
    triggerGetDetailFor: function(requestId) {
        resourceRepository.triggerGetDetailFor(requestId);
        localRepository.triggerGetDetailFor(requestId);
    },
    // TODO: Need to look and see if this is the best place for these
    subscribeToLatestSummaries: function() {
        streamRepository.subscribeToLatestSummaries();
    },
    subscribeToLatestSummariesPatches: function() {
        streamRepository.subscribeToLatestSummariesPatches();
    },
    subscribeToDetailPatchesFor: function(requestId) {
        streamRepository.subscribeToDetailPatchesFor(requestId);
    }
};

Remove repository function for getting requests by session


process.on('unhandledRejection', err => {
  throw err;
});

const express = require('express');
const next = require('next');
const { createRouter } = require('soya-next/server/router');
const { soya } = require('soya-next/server/config');
// @remove-on-eject-begin
const conf = require('../next.config');
// @remove-on-eject-end

const host = soya.config.host || '0.0.0.0';
const port = soya.config.port || 3000;
const dev = soya.config.dev ? soya.config.dev : process.env.NODE_ENV !== 'production';
const app = next({
  dev,
  // @remove-on-eject-begin
  conf,
  // @remove-on-eject-end
});

app.prepare()
  .then(() => {
    const server = express();
    server.use(createRouter(app, soya.config));
    server.listen(port, host, err => {
      if (err) {
        throw err;
      }
      // eslint-disable-next-line no-console
      console.log(`> Ready on ${host}:${port}`);
    });
  })
  .catch(ex => {
    // eslint-disable-next-line no-console
    console.error(ex.stack);
    process.exit(1);
  });

process.on('unhandledRejection', err => {
  throw err;
});

const express = require('express');
const next = require('next');
const { createRouter } = require('soya-next/server/router');
const { soya } = require('soya-next/server/config');
// @remove-on-eject-begin
const conf = require('../next.config');
// @remove-on-eject-end

const host = soya.config.host || '0.0.0.0';
const port = soya.config.port || 3000;
const dev = typeof soya.config.dev !== 'undefined' ? soya.config.dev : process.env.NODE_ENV !== 'production';
const app = next({
  dev,
  // @remove-on-eject-begin
  conf,
  // @remove-on-eject-end
});

app.prepare()
  .then(() => {
    const server = express();
    server.use(createRouter(app, soya.config));
    server.listen(port, host, err => {
      if (err) {
        throw err;
      }
      // eslint-disable-next-line no-console
      console.log(`> Ready on ${host}:${port}`);
    });
  })
  .catch(ex => {
    // eslint-disable-next-line no-console
    console.error(ex.stack);
    process.exit(1);
  });

Fix wrong dev config logic


const compile = require("truffle-compile");

class DebugCompiler {
  constructor(config) {
    this.config = config;
  }

  async compile() {
    const { contracts, files } = await new Promise((accept, reject) => {
      //we need to set up a config object for the compiler.
      //it's the same as the existing config, but we turn on quiet.
      //unfortunately, we don't have Babel here, so cloning is annoying.
      let compileConfig = Object.assign(
        {},
        ...Object.entries(this.config).map(([key, value]) => ({ [key]: value }))
      ); //clone
      compileConfig.quiet = true;

      compile.all(compileConfig, (err, contracts, files) => {
        if (err) {
          return reject(err);
        }

        return accept({ contracts, files });
      });
    });

    return { contracts, files };
  }
}

module.exports = {
  DebugCompiler
};

const compile = require("truffle-compile");

class DebugCompiler {
  constructor(config) {
    this.config = config;
  }

  async compile() {
    //we need to set up a config object for the compiler.
    //it's the same as the existing config, but we turn on quiet.
    //unfortunately, we don't have Babel here, so cloning is annoying.
    const compileConfig = Object.assign(
      {},
      ...Object.entries(this.config).map(([key, value]) => ({ [key]: value }))
    ); //clone
    compileConfig.quiet = true;

    // since `compile.all()` returns two results, we can't use promisify
    // and are instead stuck with using an explicit Promise constructor
    const { contracts, files } = await new Promise((accept, reject) => {
      compile.all(compileConfig, (err, contracts, files) => {
        if (err) {
          return reject(err);
        }

        return accept({ contracts, files });
      });
    });

    return { contracts, files };
  }
}

module.exports = {
  DebugCompiler
};

Reduce weight of ugly Promise constructor


import pick from 'lodash/pick';

/**
 * Extract input props for the FormComponentInner
 * @param {*} props All component props
 * @returns Initial props + props specific to the HTML input in an inputProperties object
 */
export const getHtmlInputProps = props => {
  const { name, path, options, label, onChange, onBlur, value, disabled } = props;

  // these properties are whitelisted so that they can be safely passed to the actual form input
  // and avoid https://facebook.github.io/react/warnings/unknown-prop.html warnings
  const inputProperties = {
    ...props.inputProperties,
    name,
    path,
    options,
    label,
    onChange,
    onBlur,
    value,
    disabled,
  };

  return {
    ...props,
    inputProperties,
  };
};

/**
 * Extract input props for the FormComponentInner
 * @param {*} props All component props
 * @returns Initial props + props specific to the HTML input in an inputProperties object
 */
export const whitelistInputProps = props => {
  const whitelist = ['name', 'path', 'options', 'label', 'onChange', 'onBlur', 'value', 'disabled'];
  return pick(props, whitelist);
};

import pick from 'lodash/pick';

/**
 * Extract input props for the FormComponentInner
 * @param {*} props All component props
 * @returns Initial props + props specific to the HTML input in an inputProperties object
 */
export const getHtmlInputProps = props => {
  const { name, path, options, label, onChange, onBlur, value, disabled } = props;

  // these properties are whitelisted so that they can be safely passed to the actual form input
  // and avoid https://facebook.github.io/react/warnings/unknown-prop.html warnings
  const inputProperties = {
    ...props.inputProperties,
    name,
    path,
    options,
    label,
    onChange,
    onBlur,
    value,
    disabled,
  };

  return {
    ...props,
    inputProperties,
  };
};

/**
 * Extract input props for the FormComponentInner
 * @param {*} props All component props
 * @returns Initial props + props specific to the HTML input in an inputProperties object
 */
export const whitelistInputProps = props => {
  const whitelist = ['name', 'path', 'options', 'label', 'onChange', 'onBlur', 'value', 'disabled', 'placeholder'];
  return pick(props, whitelist);
};

Add placeholder to the whitelist


import React from 'react'
import { Box, Grid, Typography, Card, CardContent } from '@material-ui/core'
import { Edit, Delete } from '@material-ui/icons'

export default function TravelObject(props) {
    let content = null;
    switch (props.type) {
        case 'event':
            content = <Typography variant="h4" gutterBottom>Event!</Typography>
            break;
        case 'flight':
            content = <Typography variant="h4" gutterBottom>Flight!</Typography>
            break;
        case 'hotel':
            content = <Typography variant="h4" gutterBottom>Hotel!</Typography>
            break;
        default:
            console.log("Invalid type");
            break;
    }
    return (
        <Card>
            <CardContent>
                <Grid container direction="row" justify="flex-end" alignItems="center">
                    <Box mr={10} width="100%" height="100%">
                        {content}
                    </Box>
                    <Grid item>
                        <Grid container direction="column">
                            <Edit
                                onClick={() => console.log("editing")}
                            />
                            <Delete
                                onClick={() => console.log("deleting")}
                            />
                        </Grid>
                    </Grid>
                </Grid>
            </CardContent>
        </Card>
    )
}

import React from 'react'
import { Box, Grid, Typography, Card, CardContent } from '@material-ui/core'
import { Edit, Delete } from '@material-ui/icons'

export default function TravelObject(props) {
    let content = null;
    switch (props.type) {
        case 'event':
            content = <Typography variant="h4" gutterBottom>Event!</Typography>
            break;
        case 'flight':
            content = <Typography variant="h4" gutterBottom>Flight!</Typography>
            break;
        case 'hotel':
            content = <Typography variant="h4" gutterBottom>Hotel!</Typography>
            break;
        default:
            return null;
    }
    return (
        <Card>
            <CardContent>
                <Grid container direction="row" justify="flex-end" alignItems="center">
                    <Box mr={10} width="100%" height="100%">
                        {content}
                    </Box>
                    <Grid item>
                        <Grid container direction="column">
                            <Edit
                                onClick={() => console.log("editing")}
                            />
                            <Delete
                                onClick={() => console.log("deleting")}
                            />
                        </Grid>
                    </Grid>
                </Grid>
            </CardContent>
        </Card>
    )
}

Return null instead of setting content to null


var async = require( 'async' );
var Validation = require( './validation' );
var Data = require( './data' );
var Output = require( './output' );
var utils = require( '../utils' );

exports.userAdminList = function ( req, res ) {

    async.waterfall( [
        function ( callback ) {
            Validation.forAdminList( req.query, callback );
        },
        function ( queryParams, callback ) {
            Data.standard.list( queryParams, callback );
        }
    ], function ( err, userList ) {
        if ( err ) {
            return utils.handleRouteError( err, res );
        }
        return res.json( userList, 200 );
    } );

};

exports.createAdmin = function ( req, res ) {

    async.waterfall( [
        function ( callback ) {
            Validation.createAdmin( req, callback );
        },
        function ( email, password, callback ) {
            Data.createAdmin( email, password, callback );
        }
    ], function ( err, data ) {
        if ( err ) {
            return utils.handleRouteError( err, res );
        }
        return res.json( data, 201 );
    } );

};

var async = require( 'async' );
var Validation = require( './validation' );
var Data = require( './data' );
var Output = require( './output' );
var handleRouteError = require( '../utils' ).handleRouteError;

exports.userAdminList = function ( req, res ) {

    async.waterfall( [
        // Perform request validation here
        function ( callback ) {

            Validation.forAdminList( req.query, callback );

        },
        // Perform any database actions with validated data here
        function ( queryParams, callback ) {

            Data.standard.list( queryParams, callback );

        }
    ], function ( err, userList ) {
        if ( err ) {
            return handleRouteError( err, res );
        }
        return res.json( userList, 200 );
    } );

};

exports.createAdmin = function ( req, res ) {

    async.waterfall( [
        // Perform request validation here
        function ( callback ) {

            req.checkBody( 'email', "Must be an email address" ).isEmail();
            req.checkBody( 'password', "Field is required" ).notEmpty();

            var errors = req.validationErrors();

            var key = request.headers.admin_key;
            if ( typeof key === "undefined" || key !== process.env.ADMIN_KEY ) {
                // Add our own header validation error manually
                errors.push( {
                    param: "ADMIN_KEY",
                    msg: "ADMIN_KEY is not valid",
                    value: key
                } );
            }

            if ( errors ) {
                return callback( errors );
            }
            return callback( null, req.body );

        },
        // Perform any database actions with validated data here
        function ( email, password, callback ) {

            Data.createAdmin( email, password, callback );

        }
    ], function ( err, data ) {
        if ( err ) {
            return handleRouteError( err, res );
        }
        return res.json( data, 201 );
    } );

};

Clean up user route validation


var heroku = 'https://topoftheflops.herokuapp.com'
var localUrl = 'http://localhost:3000'

var url = localUrl

module.exports = url

var heroku = 'https://topoftheflops.herokuapp.com'
var localUrl = 'http://localhost:3000'

var url = heroku

module.exports = url

Change deployed version to using heroku for api rather than local host


var clock = function() {
  var sDial = document.getElementsByClassName("seconds")[0];
  var mDial = document.getElementsByClassName("minutes")[0];
  var hDial = document.getElementsByClassName("hours")[0];

  function moveDials(hours, minutes, seconds) {
    hDeg = (360 / 12) * hours;
    mDeg = (360 / 60) * minutes;
    sDeg = (360 / 60) * seconds;
    sDial.setAttribute("transform", "rotate("+sDeg+")");
    mDial.setAttribute("transform", "rotate("+mDeg+")");
    hDial.setAttribute("transform", "rotate("+hDeg+")");
  }

  function update() {
    var currentTime = new Date();
    moveDials(currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds());
  };
  update();
}

setInterval(clock, 50);

var updateClock = (function() {
  var sDial = document.getElementById("secondDial");
  var mDial = document.getElementById("minuteDial");
  var hDial = document.getElementById("hourDial");

  function moveDials(hours, minutes, seconds) {
    hDeg = (360 / 12) * (hours + minutes/60);
    mDeg = (360 / 60) * minutes;
    sDeg = (360 / 60) * seconds;
    sDial.setAttribute("transform", "rotate("+sDeg+")");
    mDial.setAttribute("transform", "rotate("+mDeg+")");
    hDial.setAttribute("transform", "rotate("+hDeg+")");
  }

  function update() {
    var currentTime = new Date();
    moveDials(currentTime.getHours(), currentTime.getMinutes(), currentTime.getSeconds());
  };

  return update;
})();

// update every 50ms, just to be sure
setInterval(updateClock, 50);

Use improved animation code as it was used inline


const Promise = require('bluebird')
const chai = require('chai')
chai.use(require('chai-as-promised'))
const expect = chai.expect
const rewire = require('rewire')
const fetchCountryMapping = rewire('../../lib/fetchCountryMapping')

describe('Country mapping', () => {
  it('should be the body of the HTTP response if the given input is a URL', () => {
    fetchCountryMapping.__set__({
      request () {
        return Promise.resolve(`
ctf:
  countryMapping:
    scoreBoardChallenge:
      name: Canada
      code: CA
`)
      }
    })
    return expect(fetchCountryMapping('http://localhorst:3000')).to.eventually.deep.equal({
      scoreBoardChallenge: {
        name: 'Canada',
        code: 'CA'
      }
    })
  })
})

const Promise = require('bluebird')
const chai = require('chai')
chai.use(require('chai-as-promised'))
const expect = chai.expect
const rewire = require('rewire')
const fetchCountryMapping = rewire('../../lib/fetchCountryMapping')

describe('Country mapping', () => {
  it('should be the body of the HTTP response if the given input is a URL', () => {
    fetchCountryMapping.__set__({
      request () {
        return Promise.resolve(`
ctf:
  countryMapping:
    scoreBoardChallenge:
      name: Canada
      code: CA
`)
      }
    })
    return expect(fetchCountryMapping('http://localhorst:3000')).to.eventually.deep.equal({
      scoreBoardChallenge: {
        name: 'Canada',
        code: 'CA'
      }
    })
  })

  it('should be undefined if no map file URL is given', () => {
    return expect(fetchCountryMapping()).to.eventually.equal(undefined)
  })
})

Add unit test for missing country mapping


Space.Object.extend(TodoMVC, 'LayoutController', {

  mixin: [
    Space.messaging.EventSubscribing
  ],

  dependencies: {
    layout: 'BlazeLayout'
  },

  eventSubscriptions() {
    return [{
      'TodoMVC.FilterRouteTriggered'() {
        this.layout.render('index', {
          input: 'input',
          todo_list: 'todo_list',
          footer: 'footer'
        });
      }
    }];
  }
});

TodoMVC.LayoutController.mixin(Space.messaging.EventSubscribing);

Remove outdated code to apply mixin


import Ember from 'ember';

export default Ember.Component.extend({
    session: Ember.inject.service(),
    actions: {
        invalidateSession() {
            this.get('session').invalidate();
        }
    }
});

import Ember from 'ember';

export default Ember.Component.extend({
    session: Ember.inject.service(),
    actions: {
        invalidateSession() {
            this.get('session').invalidate();
            window.location = '/';
        }
    }
});

Reset window location on logout, to force clearing the datastore.


import promisify from 'promisify-object'
import semverRegex from 'semver-regex'

const ghissues = promisify(require('ghissues'), ['createComment', 'list'])

import {logger} from '../logging'

function writeComment (authData, owner, project, pr, comment) {
  return ghissues.createComment(authData, owner, project, pr, comment).then(
    ([comment]) => {
      logger.debug('Comment added to PR#%d: %s', pr, comment.html_url)
    },
    (error) => {
      logger.error('Error adding comment to PR#%d: %s', pr, error)
    })
}

function getSemverComments (commentList) {
  const commentBodies = commentList.map((comment) => comment.body)
  const semverComments = commentBodies.filter((body) => semverRegex().test(body))
  return semverComments
}

function checkAuthorization (authData, program) {
  // Get issues to make sure GitHub authorization has been successful
  const promise = ghissues.list(authData, program.owner, program.project)
  promise.then(() => {
    logger.debug('GitHub Authorization success for user: %s', authData.user)
  })
  return promise.then(() => {
    return Promise.resolve(authData)
  })
}

export {
  checkAuthorization,
  getSemverComments,
  writeComment
}

import promisify from 'promisify-object'
import semverRegex from 'semver-regex'

const ghissues = promisify(require('ghissues'), ['createComment', 'list'])

import {logger} from '../logging'

function writeComment (authData, owner, project, pr, comment) {
  return ghissues.createComment(authData, owner, project, pr, comment).then(
    ([comment]) => {
      logger.debug('Comment added to PR#%d: %s', pr, comment.html_url)
    },
    (error) => {
      logger.error('Error adding comment to PR#%d: %s', pr, error)
    })
}

function getSemverComments (commentList) {
  const commentBodies = commentList.map((comment) => comment.body)
  const semverComments = commentBodies.filter((body) => semverRegex().test(body))
  return semverComments
}

function checkAuthorization (authData, program) {
  // Get issues to make sure GitHub authorization has been successful
  return ghissues.list(authData, program.owner, program.project)
    .then(() => {
      logger.debug('GitHub Authorization success for user: %s', authData.user)
    })
    .then(() => {
      return Promise.resolve(authData)
    })
}

export {
  checkAuthorization,
  getSemverComments,
  writeComment
}

Fix unhandled rejection in test cases


define ({
    title: 'Titre',
    format: 'Format',
    layout: 'Disposition',
    settings: 'Paramètres',
    mapScaleExtent: 'Échelle/étendue de la carte',
    preserve: 'Préserver',
    mapScale: 'échelle de la carte',
    mapExtent: 'étendue de la carte',
    fullLayoutOptions: 'Options complètes de mise en page',
    scaleBarUnits: 'Unités de la barre d\'échelle',
    miles: 'Miles',
    kilometers: 'Kilomètres',
    meters: 'Mètres',
    feet: 'Pieds',
    includeLegend: 'Inclure la légende',
    printQualityOptions: 'Qualité d`impression',
    dpiInput: {
        label: 'DPI',
        invalidMessage: 'S\\\'il vous plaît entrer une valeur numérique.',
        rangeMessage: 'S\\\'il vous plaît entrer une valeur entre 100 et 300.'
    },
    mapOnlyOptions: 'Options MAP_ONLY',
    width: 'Largeur',
    height: 'Hauteur',
    printButton: {
        busyLabel: 'Impression',
        label: 'Imprimer'
    },
    clearHistoryButton: {
        label: 'Effacer l\'historique d\'impression'
    },
    printResults: {
        progressBar: {
            label: 'Création de l\\\'impression'
        },
        errorMessage: 'Erreur, réessayez'
    }
});

define ({
    title: 'Titre',
    format: 'Format',
    layout: 'Disposition',
    settings: 'Paramètres',
    mapScaleExtent: 'Échelle/étendue de la carte',
    preserve: 'Préserver',
    mapScale: 'échelle de la carte',
    mapExtent: 'étendue de la carte',
    fullLayoutOptions: 'Options complètes de mise en page',
    scaleBarUnits: 'Unités de la barre d\'échelle',
    miles: 'Miles',
    kilometers: 'Kilomètres',
    meters: 'Mètres',
    feet: 'Pieds',
    includeLegend: 'Inclure la légende',
    printQualityOptions: 'Qualité d\'impression',
    dpiInput: {
        label: 'DPI',
        invalidMessage: 'S\\\'il vous plaît entrer une valeur numérique.',
        rangeMessage: 'S\\\'il vous plaît entrer une valeur entre 100 et 300.'
    },
    mapOnlyOptions: 'Options MAP_ONLY',
    width: 'Largeur',
    height: 'Hauteur',
    printButton: {
        busyLabel: 'Impression',
        label: 'Imprimer'
    },
    clearHistoryButton: {
        label: 'Effacer l\'historique d\'impression'
    },
    printResults: {
        progressBar: {
            label: 'Création de l\\\'impression'
        },
        errorMessage: 'Erreur, réessayez'
    }
});

Replace accent with apostrophe for consistency.


// import React and Redux dependencies
var React = require('react');
var connect = require('react-redux').connect;
var _ = require('underscore');

var bindActionCreators = require('redux').bindActionCreators;
var Immutable = require('immutable');

// import actions
var MeasureActions = require('../../actions/Measures');
var Actions = _.extend(MeasureActions);

function mapStatetoProps (state, ownProps) {
  return {
    unit: state.Measures.getIn([ownProps.measureId, 'unit']),
  };
}

function mapDispatchtoProps (dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

var MeasureNumeric = React.createClass({

  handleChange: function () {
    this.props.actions.setUnit(this.refs.unit.value, this.props.measureId);
  },

  render: function () {

    return (

      <input ref="unit" type="text" onChange={this.handleChange}/>

Current unit: {this.props.unit}

      );
  }
});

module.exports = connect(mapStatetoProps, mapDispatchtoProps)(MeasureNumeric);

// import React and Redux dependencies
var React = require('react');
var connect = require('react-redux').connect;
var _ = require('underscore');

var bindActionCreators = require('redux').bindActionCreators;
var Immutable = require('immutable');

var MeasureActions = require('../../actions/Measures');

function mapStatetoProps (state, ownProps) {
  return {
    unit: state.Measures.getIn([ownProps.measureId, 'unit']),
  };
}

function mapDispatchtoProps (dispatch) {
  return {
    actions: bindActionCreators(MeasureActions, dispatch)
  };
}

var MeasureNumeric = React.createClass({

  setUnit: function () {
    this.props.actions.setUnit(this.refs.unit.value, this.props.measureId);
  },

  render: function () {

    return (
      <div>
        <label>
          Choose Unit<input ref="unit" type="text" value={this.props.unit} onChange={this.setUnit} />
        </label>
      </div>
      );
  }
});

module.exports = connect(mapStatetoProps, mapDispatchtoProps)(MeasureNumeric);

Add input for numeric measures


'use strict';
let path = require('path');
let assert = require('yeoman-generator').assert;
let helpers = require('yeoman-generator').test

describe('react-webpack-redux:reducer', () => {

  describe('When creating a new reducer', () => {

    let generatorReducer = path.join(__dirname, '../../../generators/reducer');

    /**
     * Return a newly generated reducer with given name
     * @param {String} name
     * @param {Function} callback
     */
    function createGeneratedReducer(name, callback) {
      helpers.run(generatorReducer)
        .withArguments([name])
        .on('end', callback);
    }

    it('should create a reducer when invoked', (done) => {

      createGeneratedReducer('test', () => {
        assert.file([
          'src/reducers/test.js'
        ]);

        done();
      });
    });

    it('should create the reducers unit test', (done) => {

      createGeneratedReducer('test', () => {
        assert.file([
          'test/reducers/testTest.js'
        ]);

        done();
      });
    });
  });
});

'use strict';
let path = require('path');
let assert = require('yeoman-generator').assert;
let helpers = require('yeoman-generator').test;
let fs = require('fs-extra');

describe('react-webpack-redux:reducer', () => {

  describe('When creating a new reducer', () => {

    const generatorReducer = path.join(__dirname, '../../../generators/reducer');
    const reducerSource = path.join(__dirname, '../../../generators/root/templates/reducer.js');
    const appSource = path.join(__dirname, '../../../generators/root/templates/App.js');
    let rootReducerPath = '';
    let appPath = '';

    /**
     * Return a newly generated reducer with given name
     * @param {String} name
     * @param {Function} callback
     */
    function createGeneratedReducer(name, callback) {
      helpers.run(generatorReducer)
        .inTmpDir(function(tmpDir) {
          rootReducerPath = path.join(tmpDir, 'src/reducers/index.js');
          fs.copySync(reducerSource, rootReducerPath);

          appPath = path.join(tmpDir, 'src/containers/App.js');
          fs.copySync(appSource, appPath);
        })
        .withArguments([name])
        .on('end', callback);
    }

    it('should create a reducer when invoked', (done) => {

      createGeneratedReducer('test', () => {
        assert.file([
          'src/reducers/test.js'
        ]);

        done();
      });
    });

    it('should create the reducers unit test', (done) => {

      createGeneratedReducer('test', () => {
        assert.file([
          'test/reducers/testTest.js'
        ]);

        done();
      });
    });

    it('should add the reducer to the root reducer', (done) => {

      createGeneratedReducer('test', () => {
        assert.fileContent(rootReducerPath, 'test: require(\'./test.js\')');
        done();
      });
    });

    it('should add the reducer to App.js', (done) => {

      createGeneratedReducer('test', () => {
        assert.fileContent(appPath, 'test: state.test');
        done();
      });
    });
  });
});

Check that the reducer is attached to the root reducer and the App container state is updated accordingly.


Package.describe({
  summary: "Jade template language",
  version: "0.2.9",
  name: "mquandalle:jade",
  git: "https://github.com/mquandalle/meteor-jade.git"
});

Package._transitional_registerBuildPlugin({
  name: "compileJade",
  use: [
    "underscore",
    "htmljs",
    "html-tools",
    "spacebars-compiler",
  ],
  sources: [
    "plugin/lexer.js",
    "plugin/parser.js",
    "plugin/compiler.js",
    "plugin/handler.js",
  ],
  npmDependencies: {
    "jade": "https://github.com/mquandalle/jade/tarball/f3f956fa1031e05f85be7bc7b67f12e9ec80ba37"
  }
});

Package.onTest(function (api) {
  api.versionsFrom("METEOR@0.9.0");
  api.use("tinytest");
  api.use(["mquandalle:jade", "ui", "spacebars", "templating"]);
  api.addFiles(["tests/match.jade", "tests/match.html", "tests/runtime.jade"]);
  api.addFiles(["tests/match.js", "tests/runtime.js"], "client");
});

Package.describe({
  summary: "Jade template language",
  version: "0.2.9",
  name: "mquandalle:jade",
  git: "https://github.com/mquandalle/meteor-jade.git"
});

Package.registerBuildPlugin({
  name: "compileJade",
  use: [
    "underscore",
    "htmljs",
    "html-tools",
    "spacebars-compiler",
  ],
  sources: [
    "plugin/lexer.js",
    "plugin/parser.js",
    "plugin/compiler.js",
    "plugin/handler.js",
  ],
  npmDependencies: {
    "jade": "https://github.com/mquandalle/jade/tarball/f3f956fa1031e05f85be7bc7b67f12e9ec80ba37"
  }
});

Package.onTest(function (api) {
  api.versionsFrom("METEOR@0.9.0");
  api.use("tinytest");
  api.use(["mquandalle:jade", "ui", "spacebars", "templating"]);
  api.addFiles(["tests/match.jade", "tests/match.html", "tests/runtime.jade"]);
  api.addFiles(["tests/match.js", "tests/runtime.js"], "client");
});

Use the new API to register a build plugin


/*! resol-vbus | Copyright (c) 2013-2014, Daniel Wippermann | MIT license */
'use strict';

var _ = require('lodash');
var Q = require('q');

var testUtils = {

    performAsyncTest: function(done, callback) {
        return Q.fcall(callback).then(function() {
            done();
        }).fail(function(reason) {
            done(reason);
        });
    },

    expectPromise: function(promise) {
        expect(promise).to.be.an('object');
        expect(promise.then).to.be.a('function');
        return promise;
    },

    expectRanges: function(ranges) {
        expect(ranges).a('array');

        var comparableRanges = _.map(ranges, function(range) {
            return {
                minTimestamp: range.minTimestamp.toISOString(),
                maxTimestamp: range.maxTimestamp.toISOString(),
            };
        });

        return expect(comparableRanges);
    },

};

module.exports = testUtils;

/*! resol-vbus | Copyright (c) 2013-2014, Daniel Wippermann | MIT license */
'use strict';

var _ = require('lodash');
var Q = require('q');

var testUtils = {

    performAsyncTest: function(done, callback) {
        return Q.fcall(callback).then(function() {
            done();
        }).fail(function(reason) {
            done(reason);
        });
    },

    expectPromise: function(promise) {
        expect(promise).to.be.an('object');
        expect(promise).to.have.a.property('then').that.is.a('function');
        return promise;
    },

    expectRanges: function(ranges) {
        expect(ranges).a('array');

        var comparableRanges = _.map(ranges, function(range) {
            return {
                minTimestamp: range.minTimestamp.toISOString(),
                maxTimestamp: range.maxTimestamp.toISOString(),
            };
        });

        return expect(comparableRanges);
    },

};

module.exports = testUtils;

Enhance `expectPromise` helper to first check existence of `then`.


/* eslint-env node */
'use strict';

module.exports = {
  allowedVersions: {
    'ember-cli-string-helpers': '^1.4.0', //temporary workaround for conflict with ember-light-table
    'ember-getowner-polyfill': '^1.0.0 || ^2.0.0',
    'ember-inflector': '^1.0.0 || ^2.0.0',
    'ember-runtime-enumerable-includes-polyfill': '^1.0.0 || ^2.0.0',
    'ember-require-module': '^0.1',
  }
};

/* eslint-env node */
'use strict';

module.exports = {
  allowedVersions: {
    'ember-cli-string-helpers': '^1.4.0', //temporary workaround for conflict with ember-light-table
    'ember-getowner-polyfill': '^1.0.0 || ^2.0.0',
    'ember-inflector': '^1.0.0 || ^2.0.0',
  }
};

Remove no longer needed allowedVersions


const DYNAMIC_TEMPLATE_CHAR_WARNING = `
Content with characters ', " or & may need to be escaped with three brackets
{{{ content }}}
See https://sendgrid.com/docs/ui/sending-email/using-handlebars/ for more information.`;

module.exports = {
  DYNAMIC_TEMPLATE_CHAR_WARNING,
};

const DYNAMIC_TEMPLATE_CHAR_WARNING = `
Content with characters ', " or & may need to be escaped with three brackets
{{{ content }}}
See https://sendgrid.com/docs/for-developers/sending-email/using-handlebars/ for more information.`;

module.exports = {
  DYNAMIC_TEMPLATE_CHAR_WARNING
};

Update url to point to a working current link


(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');

  var Content = helper.inherits(function(props) {
    Content.super_.call(this);

    this.element = this.prop(props.element);
  }, jCore.Component);

  Content.prototype.contentHeaderElement = function() {
    return dom.child(this.element(), 0);
  };

  if (typeof module !== 'undefined' && module.exports)
    module.exports = Content;
  else
    app.Content = Content;
})(this.app || (this.app = {}));

(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');

  var Content = helper.inherits(function(props) {
    Content.super_.call(this);

    this.element = this.prop(props.element);
  }, jCore.Component);

  Content.prototype.contentHeaderElement = function() {
    return dom.child(this.element(), 0);
  };

  Content.prototype.moduleContainerElement = function() {
    return dom.child(this.element(), 1);
  };

  if (typeof module !== 'undefined' && module.exports)
    module.exports = Content;
  else
    app.Content = Content;
})(this.app || (this.app = {}));

Add method to access an element of the module-container


const Command = require('../Command');

module.exports = Command.extend({
    commandName: 'ip',
    commandAliases: ['address', 'server', 'connect', 'version'],
    processMessage: function (message, tokens) {
        return message.channel.send(this.i18n.__mf("Come join me on Shotbow using the address `play.shotbow.net` and version 1.12.2!"));
    }
});

const Command = require('../Command');

module.exports = Command.extend({
    commandName: 'ip',
    commandAliases: ['address', 'server', 'connect', 'version'],
    processMessage: function (message, tokens) {
        return message.channel.send(this.i18n.__mf("Come join me on Shotbow using the address `play.shotbow.net`!  We support versions 1.12.2 through 1.16.2"));
    }
});

Update supported versions in !ip


var consoleJSON = consoleJSON || {};

consoleJSON.log = function(json, ruleset) {
  // pretty prints JSON to console according to given ruleset
  // obj is a Javascript object, ruleset is a consoleJSON ruleset
  console.traverse(json, ruleset, 0);
  //console.log(json);
};

consoleJSON.traverse = function(json, ruleset, lvl) {
  // traverses the json tree
  // lvl is the depth of the current node (for indentation)
  consoleJSON.printBegin(json, ruleset, lvl);

  consoleJSON.printEnd(json, ruleset, lvl);
};

consoleJSON.printBegin = function(json, ruleset, lvl) {
};

consoleJSON.printEnd = function(json, ruleset, lvl) {
};

var consoleJSON = consoleJSON || {};

consoleJSON.log = function(json, ruleset) {
  // pretty prints JSON to console according to given ruleset
  // obj is a Javascript object, ruleset is a consoleJSON ruleset
  var beginD = consoleJSON.beginDelimiter(json, ruleset);
  if (beginD) {
    consoleJSON.print(beginD);
  }
  consoleJSON.traverse(json, ruleset, 1);
  var endD = consoleJSON.endDelimiter(json, ruleset);
  if (endD) {
    consoleJSON.print(endD);
  }
  //console.log(json);
};

consoleJSON.traverse = function(json, ruleset, lvl) {
  // traverses the json tree
  // lvl is the depth of the current node (for indentation)
  if (json instanceof Array) {

  } else if (typeof json === 'object') {
    return '{';
  }

};

consoleJSON.beginDelimiter = function(json, ruleset) {
  var type = jQuery.type(json);
  if (json !== null) {
    if (json instanceof Array) {
      return '[';
    }
    else if (typeof json === 'object') {
      return '{';
    }
  }
  return null;
};

consoleJSON.endDelimiter = function(json, ruleset) {
  if (json !== null) {
    if (json instanceof Array) {
      return ']';
    }
    else if (typeof json === 'object') {
      return '}';
    }
  }
  return null;
};

consoleJSON.print = function(string) {
  console.log(string);
};

Add delimiter code; not working yet


#! /usr/bin/env node

const program = require('commander')
const PipelineRunner = require('../pipeline/runner')

program
  .version('scry 0.1.0')
  .usage('[options] <type> <dir> <file...>')
  .option('-r --reporter [reporter]', 'Reporter', /^(console|json)$/i)
  .parse(process.argv)

if (!program.args.length) {
  program.help()
} else {
  PipelineRunner.run(program.reporter || 'console', ...program.args).then((summary) => {
    console.info(summary) // eslint-disable-line no-console
  })
}

#! /usr/bin/env node

const program = require('commander')
const PipelineRunner = require('../pipeline/runner')

program
  .version('scry 0.1.0')
  .usage('[options] <type> <dir> <file...>')
  .option('-r --reporter [reporter]', 'Reporter', /^(console|json)$/i)
  .parse(process.argv)

if (!program.args.length) {
  program.help()
} else {
  PipelineRunner.run(program.reporter || 'console', ...program.args).then((summary) => {
    console.log(summary) // eslint-disable-line no-console
  })
}

Use log instead of info.


import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import api from './api';

let server = null;

function start(port) {
    return new Promise((resolve, reject) => {
        if (server !== null) {
            reject(new Error('The server is already running.'));
        }
        let app = express();
        app.use(express.static(path.join(__dirname, '../public')));
        app.use(bodyParser.json({ limit: '1MB' }));
        app.use('/api', api);
        server = app.listen(port, () => {
            resolve();
        });
    });
}

function stop() {
    return new Promise((resolve, reject) => {
        if (server === null) {
            reject(new Error('The server is not running.'));
        }
        server.close(() => {
            server = null;
            resolve();
        });
    });
}

export default {
    start,
    stop
};

import express from 'express';
import path from 'path';
import bodyParser from 'body-parser';
import api from './api';

let server = null;

function start(port) {
    return new Promise((resolve, reject) => {
        if (server !== null) {
            reject(new Error('The server is already running.'));
        }
        let app = express();
        app.use(express.static(path.join(__dirname, '../public')));
        app.use(bodyParser.json({ limit: '1.5MB' }));
        app.use('/api', api);
        server = app.listen(port, () => {
            resolve();
        });
    });
}

function stop() {
    return new Promise((resolve, reject) => {
        if (server === null) {
            reject(new Error('The server is not running.'));
        }
        server.close(() => {
            server = null;
            resolve();
        });
    });
}

export default {
    start,
    stop
};

Increase payload limit to 1.5MB


import {Observable as O} from "rx"

export default function main({DOM, model$, mux}) {
  const {h} = DOM

  // we can use our model like normal observable
  const vdom$ = DOM.prepare(model$.map(counter =>
    h("div", [
      h("h1", `Counter value is ${counter}`),
      h("button.inc", "++"),
      h("button.dec", "--")
    ])))

  const incMod$ = DOM.events(vdom$, ".inc", "click").map(() => state => state + 1)
  const decMod$ = DOM.events(vdom$, ".dec", "click").map(() => state => state - 1)

  // let's merge all mods from this component
  const mod$ = O.merge(incMod$, decMod$)

  return mux({
    DOM: vdom$,
    // and make the compatible with the model
    model$: model$.mod(mod$)
  })
}

import {Observable as O} from "rx"

export default function main({DOM, model$, mux}) {
  const {h} = DOM

  // model$ is an instance of @tsers/model - it provides the application
  // state as an observable, so you can use model$ like any other observable
  // (map, filter, combineLatest, ...).

  // let's use the model$ observable to get its value and render a virtual-dom
  // based on the value
  const vdom$ = DOM.prepare(model$.map(counter =>
    h("div", [
      h("h1", `Counter value is ${counter}`),
      h("button.inc", "++"),
      h("button.dec", "--")
    ])))

  // model$ enables you to change the state by emitting "modify functions"
  // as out output signals. The modify functions have always signature
  // (curState => nextState) - they receive the current state of the model
  // as input and must provide the next state based on the current state

  // Let's make modify functions for the counter: when increment button is
  // clicked, increment the counter state by +1. When decrement button is clicked,
  // decrement the state by -1
  const incMod$ = DOM.events(vdom$, ".inc", "click").map(() => state => state + 1)
  const decMod$ = DOM.events(vdom$, ".dec", "click").map(() => state => state - 1)

  // And because the modify are just observables, we can merge them
  const mod$ = O.merge(incMod$, decMod$)

  return mux({
    DOM: vdom$,
    // Like DOM interpreter, Model interpreter also expects that model modifications
    // are "prepared". That's why model interpreter provides a helper function .mod(mod$)
    // which converts the modify function observables to actual state modify observables
    // that do the actual state modifications
    model$: model$.mod(mod$)
  })
}

/*

// In order to run this app, you must setup a model interpreter
// for counter (with initial value):
import TSERS from "@tsers/core"
import ReactDOM from "@tsers/react"
import Model from "@tsers/model"

import Counter from "./counter"

TSERS(Counter, {
  DOM: ReactDOM("#app"),
  model$: Model(0)          // initial value = 0
})

*/

Add documentation to counter example


"use strict";

function setAllBlogId() {
    let blogLinkElements = document.querySelectorAll('.blog-link');
    for(let i = blogLinkElements.length - 1; i >= 0; i--) {
        blogLinkElements[i].id = 'blog-' + (i+1);
    }
}

setAllBlogId();

$(document).ready(function() {
    $("#blog-1").click(function() {
        $("#blog-1").load("blogs/2018-06-05-remove-persistent-running-app-in-notification-background.html #blogPost")
    });
});

$(document).ready(function() {
    $("#blog-2").click(function() {
        $("#blog-2").load("blogs/2016-08-29-thoughts-on-internship-with-OpenDayLight.html #blogPost")
    });
});

"use strict";

function setAllBlogId() {
    let blogLinkElements = document.querySelectorAll('.blog-link');
    for(let i = blogLinkElements.length - 1; i >= 0; i--) {
        blogLinkElements[i].id = 'blog-' + (i+1);
    }
}

setAllBlogId();

$(document).ready(() => {
    $("#blog-1").click(() => {
        $("#blog-1").load("blogs/2018-06-05-remove-persistent-running-app-in-notification-background.html #blogPost");
    });
});

$(document).ready(() => {
    $("#blog-2").click(() => {
        $("#blog-2").load("blogs/2016-08-29-thoughts-on-internship-with-OpenDayLight.html #blogPost");
    });
});

Change function to arrow function


/* @flow */
'use strict';

import React, {Component} from 'react';
import {View, } from 'react-native';

import computeProps from '../Utils/computeProps';
import _ from 'lodash';

export default class RowNB extends Component {
    prepareRootProps() {

        var type = {
        	flexDirection: 'row',
        	flex: (this.props.size) ? this.props.size : 1,
        }

        var defaultProps = {
            style: type
        }
        return computeProps(this.props, defaultProps);

    }
    render() {
        return(
            <View {...this.prepareRootProps()} >{this.props.children}</View>
        );
    }

}

/* @flow */
'use strict';

import React, {Component} from 'react';
import {View, } from 'react-native';

import computeProps from '../Utils/computeProps';
import _ from 'lodash';

export default class RowNB extends Component {
    prepareRootProps() {

        var type = {
        	flexDirection: 'row',
        	flex: (this.props.size) ? this.props.size : (this.props.style && this.props.style.height) ? 0 : 1,
        }

        var defaultProps = {
            style: type
        }
        return computeProps(this.props, defaultProps);

    }
    render() {
        return(
            <View {...this.prepareRootProps()} >{this.props.children}</View>
        );
    }

}

Allow rows to have fixed height


/**
 * @fileoverview Enforce no single element style arrays
 * @author Michael Gall
 */

'use strict';

module.exports = {
  meta: {
    docs: {
      description:
        'Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes',
      category: 'Stylistic Issues',
      recommended: false,
      url: '',
    },
    fixable: 'code',
  },

  create(context) {
    function reportNode(JSXExpressionNode) {
      context.report({
        node: JSXExpressionNode,
        message:
          'Single element style arrays are not necessary and cause unnecessary re-renders',
        fix(fixer) {
          const realStyleNode = JSXExpressionNode.value.expression.elements[0];
          const styleSource = context.getSourceCode().getText(realStyleNode);
          return fixer.replaceText(JSXExpressionNode.value, `{${styleSource}}`);
        },
      });
    }

    // --------------------------------------------------------------------------
    // Public
    // --------------------------------------------------------------------------
    return {
      JSXAttribute(node) {
        if (node.name.name !== 'style') return;
        if (node.value.expression.type !== 'ArrayExpression') return;
        if (node.value.expression.elements.length === 1) {
          reportNode(node);
        }
      },
    };
  },
};

/**
 * @fileoverview Enforce no single element style arrays
 * @author Michael Gall
 */

'use strict';

module.exports = {
  meta: {
    docs: {
      description:
        'Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes',
      category: 'Stylistic Issues',
      recommended: false,
      url: '',
    },
    fixable: 'code',
  },

  create(context) {
    function reportNode(JSXExpressionNode) {
      context.report({
        node: JSXExpressionNode,
        message:
          'Single element style arrays are not necessary and cause unnecessary re-renders',
        fix(fixer) {
          const realStyleNode = JSXExpressionNode.value.expression.elements[0];
          const styleSource = context.getSourceCode().getText(realStyleNode);
          return fixer.replaceText(JSXExpressionNode.value.expression, styleSource);
        },
      });
    }

    // --------------------------------------------------------------------------
    // Public
    // --------------------------------------------------------------------------
    return {
      JSXAttribute(node) {
        if (node.name.name !== 'style') return;
        if (node.value.expression.type !== 'ArrayExpression') return;
        if (node.value.expression.elements.length === 1) {
          reportNode(node);
        }
      },
    };
  },
};

Replace the whole expression rather than the whole node


import PropTypes from 'prop-types';
import React from 'react';

// A visual UI element for horizontal dots indicating "more"
// See https://material.io/icons/#ic_more_horiz
function MoreDots({color = '#ccc'}) {
  return (
    <svg fill={color} height="18" viewBox="0 0 24 24" width="18" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="none"/>
      <path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
    </svg>
  );
}
MoreDots.propTypes = {
  color: PropTypes.string
};

export default MoreDots;

import PropTypes from 'prop-types';
import React from 'react';

// A visual UI element for horizontal dots indicating "more"
// See https://material.io/icons/#ic_more_horiz
function MoreDots({color = '#ccc'}) {
  return (
    <svg className="MoreDots" fill={color} height="18" viewBox="0 0 24 24" width="18" xmlns="http://www.w3.org/2000/svg">
      <path d="M0 0h24v24H0z" fill="none"/>
      <path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
    </svg>
  );
}
MoreDots.propTypes = {
  color: PropTypes.string
};

export default MoreDots;

Add disableDraggingForSnapshotTest to CreateGroups to workaround react-beautiful-dnd / snapshot renderer mismatch


import contract from 'truffle-contract'

import RFQRegistryJSON from 'contracts/build/contracts/RFQRegistry.json'
import RFQJSON from 'contracts/build/contracts/RFQ.json'

const RFQRegistry = contract(RFQRegistryJSON)
const RFQ = contract(RFQJSON)

export { RFQ, RFQRegistry }

import Web3 from 'web3'
import contract from 'truffle-contract'

import RFQRegistryJSON from 'contracts/build/contracts/RFQRegistry.json'
import RFQJSON from 'contracts/build/contracts/RFQ.json'

const RFQRegistry = contract(RFQRegistryJSON)
const RFQ = contract(RFQJSON)

const provider = new Web3.providers.HttpProvider('http://localhost:8545')
RFQRegistry.setProvider(provider)
RFQ.setProvider(provider)

export { RFQ, RFQRegistry }

Set Web3 provider on contracts.


L.AngularControl = L.Control.extend({
	options: {
		position: 'bottomleft',
		template: ''
	},
	onAdd: function (map) {
		var container = L.DomUtil.create('div', 'leaflet-angular');

		var $injector = angular.injector(['ng']);
		var $rootScope = $injector.get('$rootScope'),
			$compile = $injector.get('$compile'),
			$controller = $injector.get('$controller');

		var scope = $rootScope.$new(true);
		var element = angular.element(container);

		element.html(this.options.template);

		var link = $compile(element)

		if (this.options.controller) {

          var controller = $controller(this.options.controller, {
          	$map: map,
          	$scope: scope,
          	$element: element
          });

          if (this.options.controllerAs) {
            scope[this.options.controllerAs] = controller;
          }

          element.data('$ngControllerController', controller);
          element.children().data('$ngControllerController', controller);
        }

        link(scope);
		scope.$apply();
		return container;
	}
});

L.angularControl = function (options) {
  return new L.AngularControl(options);
};

L.AngularControl = L.Control.extend({
    options: {
        position: 'bottomleft',
        template: ''
    },
    onAdd: function (map) {
        var container = L.DomUtil.create('div', 'leaflet-angular');
        var $injector = angular.injector(['ng']);
        var $rootScope = $injector.get('$rootScope'),
            $compile = $injector.get('$compile'),
            $controller = $injector.get('$controller');

        var scope = $rootScope.$new(true);
        var element = angular.element(container);

        element.html(this.options.template);

        var link = $compile(element);

        if (this.options.controller) {
            var controller = $controller(this.options.controller, {
                $map: map,
                $scope: scope,
                $element: element
            });

            if (this.options.controllerAs) {
                scope[this.options.controllerAs] = controller;
            }

            element.data('$ngControllerController', controller);
            element.children().data('$ngControllerController', controller);
        }

        link(scope);
        scope.$apply();
        return container;
    }
});

L.angularControl = function (options) {
  return new L.AngularControl(options);
};

Fix formatting and missing semicolon


export default (Promise=Promise) => f =>
  (...args) =>
    new Promise((resolve, reject) =>
      f(...args, (err, val) => err ? reject(err) : resolve(val))
    )

export default (PromiseArg=Promise) => f =>
  (...args) =>
    new PromiseArg((resolve, reject) =>
      f(...args, (err, val) => err ? reject(err) : resolve(val))
    )

Fix global 'Promise' as default argument


module.exports = function(config) {
    config.set({
        plugins: [
            'karma-jasmine',
            'karma-firefox-launcher',
            'karma-phantomjs-launcher',

            require('../index')
        ],
        frameworks: ['jasmine', 'loud'],
        browsers: ['Firefox', 'PhantomJS'],
        files: ['test.js']
    });
};

module.exports = function(config) {
    config.set({
        plugins: [
            'karma-jasmine',
            'karma-firefox-launcher',
            'karma-phantomjs-launcher',

            require('../index')
        ],
        frameworks: ['jasmine', 'loud'],
        browsers: ['Firefox', 'PhantomJS'],
        files: ['test.js'],
        reporters: ['dots']
    });
};

Change reporter for clean output


var TwoDimensionalFixedArray = require('./two_dementional_fixed_array.js');
var _ = require('lodash');
var np = require('named-parameters');

module.exports = function(args) {
  parsedArgs = np.parse(args).
    require('army1').
    require('army2').
    values();

  var spaces = new TwoDimensionalFixedArray({ rowCount: 64, colCount: 64 });
  var army1 = parsedArgs.army1;
  var army2 = parsedArgs.army2;

  return {
    addPiece: addPiece
  };

  function addPiece(args) {
    parsedArgs = np.parse(args).
      require('piece').
      require('row', 'non-negative integer').
      require('col', 'non-negative integer').
      values();

    var piece = parsedArgs.piece;
    var row = parsedArgs.row;
    var col = parsedArgs.col;

    existing_piece = spaces.get({ row: row, col: col });

    if (existing_piece === undefined) {
      spaces.set({ item: piece, row: row, col: col });
    } else {
      throw('space taken');
    }
  }
};

var TwoDimensionalFixedArray = require('./two_dementional_fixed_array.js');
var _ = require('lodash');
var np = require('named-parameters');

module.exports = function(args) {
  parsedArgs = np.parse(args).
    require('army1').
    require('army2').
    values();

  var spaces = new TwoDimensionalFixedArray({ rowCount: 64, colCount: 64 });
  var armyData = [];

  armyData.push({
    army: parsedArgs.army1,
    key: 'army1',
    activePieces: []
  });

  armyData.push({
    army: parsedArgs.army2,
    key: 'army1',
    activePieces: []
  });

  return {
    addPiece: addPiece,
    activePieces: activePieces
  };

  function addPiece(args) {
    parsedArgs = np.parse(args).
      require('piece').
      require('row', 'non-negative integer').
      require('col', 'non-negative integer').
      values();

    var piece = parsedArgs.piece;
    var row = parsedArgs.row;
    var col = parsedArgs.col;

    existing_piece = spaces.get({ row: row, col: col });

    if (existing_piece === undefined) {
      addToActivePieces(piece);
      spaces.set({ item: piece, row: row, col: col });
    } else {
      throw('space taken');
    }
  }

  function dataFor(army) {
    data = _.find(armyData, function(data) {
      return data.army === army;
    });

    if(data) {
      return data;
    } else {
      throw('data not found');
    }
  }

  function addToActivePieces(piece) {
    dataFor(piece.army).activePieces.push(piece);
  }

  function activePieces(args) {
    parsedArgs = np.parse(args).
      require('army').
      values();

    return _.clone(dataFor(parsedArgs.army).activePieces);
  }
};

Add activePieces Lookup to Board


'use strict';

export default {

  Container : require('./container'),
  Row : require('./row'),
  Col : require('./col'),

  IconButton : require('./icon-button'),

  AppHeader : require('./layout/side-nav'),
  TopNav : require('./layout/top-nav'),
  SideNav : require('./layout/side-nav'),

  Modal : require('./modal'),

  Collapsible : require('./collapsible'),

  // Utilities
  LayeredComponentMixin : require('./mixins/layered-component'),
  TransitionIn : require('./transition-in'),

};

'use strict';

export default {

  Container : require('./container'),
  Row : require('./row'),
  Col : require('./col'),

  IconButton : require('./icon-button'),

  AppHeader : require('./layout/side-nav'),
  TopNav : require('./layout/top-nav'),
  SideNav : require('./layout/side-nav'),

  Modal : require('./modal'),

  Collapsible: require("./collapsible/collapsible"),

  // Utilities
  LayeredComponentMixin : require('./mixins/layered-component'),
  TransitionIn : require('./transition-in'),

};

Fix require for collapsible components


import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { RouterProvider } from 'react-router5';
import App from './containers/App';
import io from 'socket.io-client';

// Router
import createRouter from './router';
// Redux
import configureStore from './stores';
// Styles
import './index.css';

// Basic simple peer config
// let config = {
//   iceServers: [
//     { url: 'stun:stun.l.google.com:19302' }
//   ]
// };

const socket = io('http://api.discuzzion.docker');

// Redux and router
const router = createRouter();
const store = configureStore(router, {
  // Initial State
  socket: { socket }
});

router.start((err, state) => {
  ReactDOM.render(
    <Provider store={ store }>
      <RouterProvider router={ router }>
        <App />
      </RouterProvider>
    </Provider>,
    document.getElementById('root')
  );
});

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { RouterProvider } from 'react-router5';
import App from './containers/App';
import io from 'socket.io-client';

// Router
import createRouter from './router';
// Redux
import configureStore from './stores';
// Styles
import './index.css';

// Basic simple peer config
// let config = {
//   iceServers: [
//     { url: 'stun:stun.l.google.com:19302' }
//   ]
// };

const socket = io();

// Redux and router
const router = createRouter();
const store = configureStore(router, {
  // Initial State
  socket: { socket }
});

router.start((err, state) => {
  ReactDOM.render(
    <Provider store={ store }>
      <RouterProvider router={ router }>
        <App />
      </RouterProvider>
    </Provider>,
    document.getElementById('root')
  );
});

Remove the custom URL when initialize socket.io


const { createClient } = require('./client')
const { attachCommands } = require('./commands')
require('dotenv').config()

const TG_API_TOKEN = process.env.TG_API_TOKEN
const WEBHOOK_PORT = parseInt(process.env.PORT || '1234', 10)

console.log(`Starting bot`)

const opts = { apiToken: TG_API_TOKEN }
if (process.env.HEROKU_APP_NAME) {
    opts.webhook = {
        url: `https://${process.env.HEROKU_APP_NAME}.herokuapp.com/bot${TG_API_TOKEN}`,
        port: WEBHOOK_PORT
    }
}

const client = createClient(opts)
attachCommands(client)

const { createClient } = require('./client')
const { attachCommands } = require('./commands')
require('dotenv').config()

const TG_API_TOKEN = process.env.TG_API_TOKEN
const WEBHOOK_PORT = parseInt(process.env.PORT || '1234', 10)

console.log('Starting bot')

const opts = { apiToken: TG_API_TOKEN }
if (process.env.HEROKU_APP_NAME) {
    opts.webhook = {
        url: `https://${process.env.HEROKU_APP_NAME}.herokuapp.com/bot${TG_API_TOKEN}`,
        port: WEBHOOK_PORT
    }
}

const client = createClient(opts)
attachCommands(client)

Replace unnecessary ` with '


/*
 * Copyright (c) 2015 Nick Jurgens <nicholas2010081@gmail.com>
 */
'use strict';

import Poller from './poller';
import api from './api';

let poller = new Poller();

poller.dispatcher
    .register('ping', (text, message) => {
        console.dir(message);
        return 'pong';
    })
    .register('marco', (text, message) => {
        return 'polo';
    })
    .register('me', (text, message) => {
        console.dir(message);

        if (!text.length) {
            return null;
        }

        let {first_name, last_name} = message.from;
        let name = last_name ? `${first_name} ${last_name}` : first_name;

        return `${name} ${text}`;
    });

poller.start();

/*
 * Copyright (c) 2015 Nick Jurgens <nicholas2010081@gmail.com>
 */
'use strict';

import Poller from './poller';
import api from './api';

let poller = new Poller();

poller.dispatcher
    .register('ping', (text, message) => {
        console.dir(message);
        return 'pong';
    })
    .register('marco', (text, message) => {
        return 'polo';
    })
    .register('me', (text, message) => {
        console.dir(message);

        if (!text.length) {
            return null;
        }

        let {first_name, last_name} = message.from;
        let name = last_name ? `${first_name} ${last_name}` : first_name;

        return `${name} ${text}`;
    })
    .register('flip', (text, message) => {
        return '(╯°□°）╯︵ ┻━┻';
    })
    .register('flop', (text, message) => {
        return '┬─┬ノ( º _ ºノ)';
    });

poller.start();

Add /flip and /flop commands


import 'babel-core/lib/babel/polyfill';
import {renderInBrowser} from './render.js';

renderInBrowser();

Add the polyfills so they work in the browser.