import React from 'react';
import { c } from 'ttag';
import { Loader, Alert, PrimaryButton, useFolders, useModals } from 'react-components';

import FolderTreeViewList from './FolderTreeViewList';
import EditLabelModal from './modals/Edit';

function LabelsSection() {
    const [folders, loadingFolders] = useFolders();
    const { createModal } = useModals();

    if (loadingFolders) {
        return <Loader />;
    }

    return (
        <>
            <Alert
                type="info"
                className="mt1 mb1"
                learnMore="https://protonmail.com/support/knowledge-base/creating-folders/"
            >
                {c('LabelSettings').t`A message can only be in filed in a single Folder at a time.`}
            </Alert>
            <div className="mb1">
                <PrimaryButton onClick={() => createModal(<EditLabelModal type="folder" />)}>
                    {c('Action').t`Add folder`}
                </PrimaryButton>
            </div>
            {folders.length ? (
                <FolderTreeViewList items={folders} />
            ) : (
                <Alert>{c('LabelSettings').t`No folders available`}</Alert>
            )}
        </>
    );
}

export default LabelsSection;

import React from 'react';
import { c } from 'ttag';
import { Loader, Alert, PrimaryButton, useFolders, useModals } from 'react-components';

import FolderTreeViewList from './FolderTreeViewList';
import EditLabelModal from './modals/Edit';

function LabelsSection() {
    const [folders, loadingFolders] = useFolders();
    const { createModal } = useModals();

    if (loadingFolders) {
        return <Loader />;
    }

    return (
        <>
            <Alert
                type="info"
                className="mt1 mb1"
                learnMore="https://protonmail.com/support/knowledge-base/creating-folders/"
            >
                {c('LabelSettings').t`A message can only be filed in a single Folder at a time.`}
            </Alert>
            <div className="mb1">
                <PrimaryButton onClick={() => createModal(<EditLabelModal type="folder" />)}>
                    {c('Action').t`Add folder`}
                </PrimaryButton>
            </div>
            {folders.length ? (
                <FolderTreeViewList items={folders} />
            ) : (
                <Alert>{c('LabelSettings').t`No folders available`}</Alert>
            )}
        </>
    );
}

export default LabelsSection;

Fix translation typo message info folders


import moment from 'moment';
class NavbarController {
  constructor() {
    this.name = 'navbar';
  }

  $onInit(){
    this.moment = moment().format('dddd HH:mm');

    this.updateDate();

    this.user =
      {
        name: 'Jesus Garcia',
        mail: 'ctw@ctwhome.com',
        picture: '//icons.iconarchive.com/icons/graphicloads/flat-finance/256/person-icon.png',
        lists: [
          {
            name: 'Study',
            timers: [
              {
                name: 'Timer 1',
                time: '1500'
              },
              {
                name: 'Timer 2',
                time: '1500'
              },
              {
                name: 'Timer 3',
                time: '1500'
              }
            ]
          },
          {
            name: 'Piano',
            timers: [
              {
                name: 'Timer 4',
                time: '1500'
              },
              {
                name: 'Timer 5',
                time: '1500'
              }
            ]
          }
        ]
      };
  }

  updateDate () {
    setTimeout(() => {
      this.moment = moment().format('dddd HH:mm');
      this.updateDate();
    }, 1000);
  }

}

export default NavbarController;

import moment from 'moment';
class NavbarController {
  constructor() {
    this.name = 'navbar';
  }

  $onInit(){
    this.moment = moment().format('dddd HH:mm');

    this.updateDate();

    this.user =
      {
        name: 'Jesus Garcia',
        mail: 'ctw@ctwhome.com',
        picture: '//icons.iconarchive.com/icons/graphicloads/flat-finance/256/person-icon.png',
        lists: [
          {
            name: 'Study',
            timers: [
              {
                name: 'Timer 1',
                time: '1500'
              },
              {
                name: 'Timer 2',
                time: '1500'
              },
              {
                name: 'Timer 3',
                time: '1500'
              }
            ]
          },
          {
            name: 'Piano',
            timers: [
              {
                name: 'Timer 4',
                time: '1500'
              },
              {
                name: 'Timer 5',
                time: '1500'
              }
            ]
          }
        ]
      };
  }

  updateDate () {
    setTimeout(() => {
      this.moment = moment().format('dddd HH:mm');
      this.updateDate();
    }, 60000);
  }

}

export default NavbarController;

Update local Date automatically each 60s


/**
 * Created by groupsky on 18.11.15.
 */

require('../app').controller('UsersController', /* @ngInject */function ($filter, $scope, User) {
  var controller = this
  var filter = $filter('filter')

  $scope.rows = User.query({
    limit: 1000
  })

  controller.filterRows = function (config) {
    return function (row) {
      if (config && config.role) {
        if (config.role !== row.role) {
          return false
        }
      }
      if (config && config.search) {
        if (!filter([row], config.search).length) {
          return false
        }
      }
      return true
    }
  }
})

/**
 * Created by groupsky on 18.11.15.
 */

require('../app').controller('UsersController', /* @ngInject */function ($filter, $scope, User) {
  var controller = this
  var filter = $filter('filter')

  $scope.rows = User.query({
    limit: 5000
  })

  controller.filterRows = function (config) {
    return function (row) {
      if (config && config.role) {
        if (config.role !== row.role) {
          return false
        }
      }
      if (config && config.search) {
        if (!filter([row], config.search).length) {
          return false
        }
      }
      return true
    }
  }
})

Increase limit for fetching users in UI


"use strict";

const path = require('path');
const Sails = require('sails');
const _ = require('lodash');

module.exports = function (grunt) {
    grunt.registerTask('cron', async function (...args) {
        const done = this.async();
        Sails.load({ hooks: { grunt: false } }, async () => {
            try {
                const filePath = path.resolve('config', 'scientilla.js');
                const config = require(filePath);
                const crons = config.scientilla.crons.filter(cron => cron.name === args[0]);

                if (crons.length > 0) {
                    for (const cron of crons) {
                        for (const job of cron.jobs) {
                            try {
                                await _.get(global, job.fn)(...job.params);
                            } catch (e) {
                                throw e;
                            }
                        }
                    }
                } else {
                    throw 'Cron not found!';
                }
                done();
            } catch(err) {
                sails.log.debug(err);
                done();
                return 1;
            }
        });
    });
};

"use strict";

const Sails = require('sails');
const _ = require('lodash');

module.exports = function (grunt) {
    grunt.registerTask('cron', async function (...args) {
        const done = this.async();
        Sails.load({ hooks: { grunt: false } }, async () => {
            try {
                const crons = sails.config.scientilla.crons.filter(cron => cron.name === args[0]);

                if (crons.length > 0) {
                    for (const cron of crons) {
                        for (const job of cron.jobs) {
                            try {
                                await _.get(global, job.fn)(...job.params);
                            } catch (e) {
                                throw e;
                            }
                        }
                    }
                } else {
                    throw 'Cron not found!';
                }
                done();
            } catch(err) {
                sails.log.debug(err);
                done();
                return 1;
            }
        });
    });
};

Remove reading config from file


import M_Gizmo from './M_Gizmo';
import Arrow from '../../../low_level/primitives/Arrow';
import ClassicMaterial from '../../../low_level/materials/ClassicMaterial';
import M_Mesh from '../meshes/M_Mesh';
import Vector4 from '../../../low_level/math/Vector4';

export default class M_DirectionalLightGizmo extends M_Gizmo {
  constructor(glBoostContext, length) {
    super(glBoostContext, null, null);
    this._init(glBoostContext, length);

//    this.isVisible = false;

    this.baseColor = new Vector4(0.8, 0.8, 0, 1);
  }

  _init(glBoostContext, length) {
    this._material = new ClassicMaterial(this._glBoostContext);
    this._mesh = new M_Mesh(glBoostContext,
      new Arrow(this._glBoostContext, length, 3),
      this._material);

    this.addChild(this._mesh);
  }

  set rotate(rotateVec3) {
    this._mesh.rotate = rotateVec3;
  }

  get rotate() {
    return this._mesh.rotate;
  }

  set baseColor(colorVec) {
    this._material.baseColor = colorVec;
  }

  get baseColor() {
    return this._material.baseColor;
  }
}

import M_Gizmo from './M_Gizmo';
import Arrow from '../../../low_level/primitives/Arrow';
import ClassicMaterial from '../../../low_level/materials/ClassicMaterial';
import M_Mesh from '../meshes/M_Mesh';
import Vector4 from '../../../low_level/math/Vector4';

export default class M_DirectionalLightGizmo extends M_Gizmo {
  constructor(glBoostContext, length) {
    super(glBoostContext, null, null);
    this._init(glBoostContext, length);

    this.isVisible = false;

    this.baseColor = new Vector4(0.8, 0.8, 0, 1);
  }

  _init(glBoostContext, length) {
    this._material = new ClassicMaterial(this._glBoostContext);
    this._mesh = new M_Mesh(glBoostContext,
      new Arrow(this._glBoostContext, length, 3),
      this._material);

    this.addChild(this._mesh);
  }

  set rotate(rotateVec3) {
    this._mesh.rotate = rotateVec3;
  }

  get rotate() {
    return this._mesh.rotate;
  }

  set baseColor(colorVec) {
    this._material.baseColor = colorVec;
  }

  get baseColor() {
    return this._material.baseColor;
  }
}

Make directional light gizmo invisible


po.d3TopoJson = function(fetch) {
  if (!arguments.length) fetch = po.queue.json;

  var topoToGeo = function(url, callback) {
    function convert(topology, object, layer, features) {
      if (object.type == "GeometryCollection" && !object.properties) {
        object.geometries.forEach(function(g) {
          convert(topology, g, layer, features);
        });
      }
      else {
        var feature = topojson.feature(topology, object);
        feature.properties = { layer: layer };
        if (object.properties) {
          Object.keys(object.properties).forEach(function(property) {
            feature.properties[property] = object.properties[property];
          });
        }
        features.push(feature);
      }
    }

    return fetch(url, function(topology) {
      var features = [];
      for (var o in topology.objects) {
        convert(topology, topology.objects[o], o, features);
      }
      callback({
        type: "FeatureCollection",
        features: features
      });
    });
  };

  var d3TopoJson = po.d3GeoJson(topoToGeo);

  return d3TopoJson;
};

po.d3TopoJson = function(fetch) {
  if (!arguments.length) fetch = po.queue.json;

  var topologyFeatures = function(topology) {
    function convert(topology, object, layer, features) {
      if (object.type == "GeometryCollection" && !object.properties) {
        object.geometries.forEach(function(g) {
          convert(topology, g, layer, features);
        });
      }
      else {
        var feature = topojson.feature(topology, object);
        feature.properties = { layer: layer };
        if (object.properties) {
          Object.keys(object.properties).forEach(function(property) {
            feature.properties[property] = object.properties[property];
          });
        }
        features.push(feature);
      }
    }

    var features = [];
    for (var o in topology.objects) {
      convert(topology, topology.objects[o], o, features);
    }
    return features;
  };

  var topoToGeo = function(url, callback) {
    return fetch(url, function(topology) {
      callback({
        type: "FeatureCollection",
        features: topologyFeatures(topology)
      });
    });
  };

  var d3TopoJson = po.d3GeoJson(topoToGeo);

  d3TopoJson.topologyFeatures = function(x) {
    if (!arguments.length) return topologyFeatures;
    topologyFeatures = x;
    return d3TopoJson;
  };

  return d3TopoJson;
};

Allow changing the function used to extract GeoJSON features from TopoJSON.


window.addEventListener('load', function(){

    // touchstart

    module('touchstart', environment);

    test('should respond to touchstart', 1, function() {
        listen('touchstart').trigger('mousedown');
    });

    // touchend

    module('touchend', environment);

    test('should respond to touchend', 1, function() {
        listen('touchend').trigger('mouseup');
    });

    // touchmove

    module('touchmove', environment);

    test('should respond to touchmove', 1, function() {
        listen('touchmove').trigger('mousemove');
    });

});

window.addEventListener('load', function(){

    // mousedown

    module('mousedown', environment);

    test('should respond to mousedown', 1, function() {
        listen('mousedown').trigger('mousedown');
    });

    // mouseup

    module('mouseup', environment);

    test('should respond to mouseup', 1, function() {
        listen('mouseup').trigger('mouseup');
    });

    // mousemove

    module('mousemove', environment);

    test('should respond to mousemove', 1, function() {
        listen('mousemove').trigger('mousemove');
    });

    // touchstart

    module('touchstart', environment);

    test('should respond to touchstart', 1, function() {
        listen('touchstart').trigger('mousedown');
    });

    // touchend

    module('touchend', environment);

    test('should respond to touchend', 1, function() {
        listen('touchend').trigger('mouseup');
    });

    // touchmove

    module('touchmove', environment);

    test('should respond to touchmove', 1, function() {
        listen('touchmove').trigger('mousemove');
    });

});

Add mousedown/mouseup/mousemove to test suite.


'use strict';

const Promise = require('bluebird');

const glob = Promise.promisify(require('glob'));
const mkdirp = Promise.promisify(require('mkdirp'));
const path = require('path');
const fs = require('fs');
const mu = require('mu2');

function compile(src, dest, settings) {
  settings = settings || {};
  return mkdirp(path.dirname(dest))
    .then(() => {
      return new Promise((resolve, reject) => {
        let stream;
        if (path.basename(src).match(/\.tpl\./)) {
          dest = dest.replace('.tpl', '');
          stream = mu.compileAndRender(src, settings);
        } else {
          stream = fs.createReadStream(src);
        }
        stream.pipe(fs.createWriteStream(dest));
        stream.on('end', resolve);
        stream.on('error', reject);
      });
    });
}

function copy(src, dest, settings) {
  const pattern = path.resolve(src, '**/*');
  return glob(pattern, { nodir: true, dot: true })
    .then((files) => {
      return Promise.map(files, (file) => {
        const target = path.resolve(dest, path.relative(src, file));
        return compile(file, target, settings);
      }, {concurrency: 1});
    });
}

module.exports = copy;

'use strict';

const Promise = require('bluebird');

const glob = Promise.promisify(require('glob'));
const mkdirp = Promise.promisify(require('mkdirp'));
const path = require('path');
const fs = require('fs');
const mu = require('mu2');

function compile(src, dest, settings) {
  settings = settings || {};
  return mkdirp(path.dirname(dest))
    .then(() => {
      return new Promise((resolve, reject) => {
        let stream;
        if (path.basename(src).match(/\.tpl(\.|$)/)) {
          dest = dest.replace('.tpl', '');
          stream = mu.compileAndRender(src, settings);
        } else {
          stream = fs.createReadStream(src);
        }
        stream.pipe(fs.createWriteStream(dest));
        stream.on('end', resolve);
        stream.on('error', reject);
      });
    });
}

function copy(src, dest, settings) {
  const pattern = path.resolve(src, '**/*');
  return glob(pattern, { nodir: true, dot: true })
    .then((files) => {
      return Promise.map(files, (file) => {
        const target = path.resolve(dest, path.relative(src, file));
        return compile(file, target, settings);
      }, {concurrency: 1});
    });
}

module.exports = copy;

Fix regex for template files


'use strict';

var R = require('ramda');

/**
 * Output a block (or its inverse) based on whether or not both of the suppied
 * arguments are truthy.
 *
 * @since v0.0.1
 * @param {*} left
 * @param {*} right
 * @param {Object} options
 * @throws {Error} An error is thrown when the `right` argument is missing.
 * @return {String}
 * @example
 *
 *  var a = true;
 *  var b = 1;
 *  var c = false;
 *
 *  {{#and a b}}✔{{else}}✘{{/and}} //=> ✔
 *  {{#and b c}}✔{{else}}✘{{/and}} //=> ✘
 */

module.exports = function and (left, right, options) {
  if (arguments.length < 3) {
    throw new Error('The "or" helper needs two arguments.');
  }
  return R.and(left, right) ?
    options.fn(this) : options.inverse(this);
}

'use strict';

var R = require('ramda');

/**
 * Output a block (or its inverse) based on whether or not both of the suppied
 * arguments are truthy.
 *
 * @since v0.0.1
 * @param {*} left
 * @param {*} right
 * @param {Object} options
 * @throws {Error} An error is thrown when the `right` argument is missing.
 * @return {String}
 * @example
 *
 *  var a = true;
 *  var b = 1;
 *  var c = false;
 *
 *  {{#and a b}}✔{{else}}✘{{/and}} //=> ✔
 *  {{#and b c}}✔{{else}}✘{{/and}} //=> ✘
 */

module.exports = function and (left, right, options) {
  if (arguments.length < 3) {
    throw new Error('The "and" helper needs two arguments.');
  }
  return R.and(left, right) ?
    options.fn(this) : options.inverse(this);
}

Fix typo in error message


var _ = require('underscore');
var UserContainer = require('../lib/authentication/user-container');
var assert = require('chai').assert;

describe('tests of garbage collecting of outdated cookies', function() {

  var responseMock = {
    cookies: {
      set: function() {
      }
    }
  };

  it('', function(done) {
    //for the sake of the test
    UserContainer._collectorIntervalMs = 100;
    UserContainer._oudatedTimeMs = UserContainer._collectorIntervalMs + 1;

    var userContainer = new UserContainer();
    userContainer.saveUser(responseMock, 'token');
    assert(_.size(userContainer._userList) == 1);

    var user = userContainer._userList[0];
    setTimeout(function() {
      assert(userContainer.hasUserByCookie(user.cookie), 'Cookie should be presented');
      assert(userContainer.hasUserByToken(user.token), 'Token should be presented');
      setTimeout(function() {
        assert(!userContainer.hasUserByCookie(user), 'User should be deleted');
        assert(!userContainer.hasUserByToken(user), 'User should be deleted');
        done();
      }, (UserContainer._oudatedTimeMs + 2 * UserContainer._collectorIntervalMs));
    }, UserContainer._collectorIntervalMs);
  });

});

var _ = require('underscore');
var UserContainer = require('../lib/authentication/user-container');
var assert = require('chai').assert;

describe('tests of garbage collecting of outdated cookies', function() {

  var responseMock = {
    cookies: {
      set: function() {
      }
    }
  };

  it('', function(done) {
    //for the sake of the test
    UserContainer._collectorIntervalMs = 100;
    UserContainer._oudatedTimeMs = UserContainer._collectorIntervalMs + 10;

    var userContainer = new UserContainer();
    userContainer.saveUser(responseMock, 'token');
    assert(_.size(userContainer._userList) == 1);

    var user = userContainer._userList[0];
    setTimeout(function() {
      assert(userContainer.hasUserByCookie(user.cookie), 'Cookie should be presented');
      assert(userContainer.hasUserByToken(user.token), 'Token should be presented');
      setTimeout(function() {
        assert(!userContainer.hasUserByCookie(user), 'User should be deleted');
        assert(!userContainer.hasUserByToken(user), 'User should be deleted');
        done();
      }, (UserContainer._oudatedTimeMs + 2 * UserContainer._collectorIntervalMs));
    }, UserContainer._collectorIntervalMs);
  });

});

Fix timeout error in UserContainer test.


var React = require("react");

module.exports = {
  propTypes: {
    flux: React.PropTypes.object
  },

  childContextTypes: {
    flux: React.PropTypes.object
  },

  contextTypes: {
    flux: React.PropTypes.object
  },

  getChildContext: function() {
    return {
      flux: this.context.flux || this.props.flux
    };
  }
};

var React = require("react");

module.exports = {
  propTypes: {
    flux: React.PropTypes.object.isRequired
  },

  childContextTypes: {
    flux: React.PropTypes.object
  },

  getChildContext: function() {
    return {
      flux: this.props.flux
    };
  }
};

Make Fluxbox.Mixin only for the top-level components


/* eslint no-console: 0 */
'use strict';

const irc = require('irc');

const server = process.env.IRC_SERVER;
const user = process.env.IRC_USER;
const channel = process.env.IRC_CHANNEL;

const client = module.exports.client = new irc.Client(server, user, {
  channels: [channel],
});

if (process.env.NODE_ENV !== 'testing') {
  client.on('registered', function clientOnRegisterd(message) {
    console.log(new Date(), '[IRC]', message.args[1]);
  });
}

client.on('error', function clientOnError(error) {
  console.error(error);
  console.error('Shutting Down...');
  process.exit(1);
});

module.exports.notify = function ircPost(nodes, callback) {
  nodes.forEach(function nodesForEach(node) {
    // let name = `[${node.name}](${jenkins}/computer/${node.name})`;

    if (node.offline) {
      client.say(channel, `Jenkins slave ${node.name} is offline`);
    } else {
      client.say(channel, `Jenkins slave ${node.name} is online`);
    }
  });

  callback(null);
};

/* eslint no-console: 0 */
'use strict';

const irc = require('irc');

const server = process.env.IRC_SERVER;
const user = process.env.IRC_USER;
const channel = process.env.IRC_CHANNEL;

const client = module.exports.client = new irc.Client(server, user, {
  debug: true,
  autoConnect: false,
  autoRejoin: true,
  channels: [channel],
  showErrors: true,
});

client.connect(5, function() {
  console.log(arguments);
});

if (process.env.NODE_ENV !== 'testing') {
  client.on('registered', function clientOnRegisterd(message) {
    console.log(new Date(), '[IRC]', message.args[1]);
  });
}

client.on('error', function clientOnError(error) {
  console.error(error);
  console.error('Shutting Down...');
  process.exit(1);
});

module.exports.notify = function ircPost(nodes, callback) {
  nodes.forEach(function nodesForEach(node) {
    // let name = `[${node.name}](${jenkins}/computer/${node.name})`;

    if (node.offline) {
      client.say(channel, `Jenkins slave ${node.name} is offline`);
    } else {
      client.say(channel, `Jenkins slave ${node.name} is online`);
    }
  });

  callback(null);
};

Add debug information to IRC handler


/**
 Contains core methods and classes for Orbit.js

 @module orbit
 @main orbit
 */

// Prototype extensions
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function (fn, scope) {
    var i, len;
    for (i = 0, len = this.length; i < len; ++i) {
      if (i in this) {
        fn.call(scope, this[i], i, this);
      }
    }
  };
}

/**
 Namespace for core Orbit methods and classes.

 @class Orbit
 @static
 */
var Orbit = {};

export default Orbit;

/**
 Contains core methods and classes for Orbit.js

 @module orbit
 @main orbit
 */

/**
 Namespace for core Orbit methods and classes.

 @class Orbit
 @static
 */
var Orbit = {};

export default Orbit;

Remove prototype extensions. ES5.1 now required.


const program = require('commander');

program
    .version('1.0.0')
    .option('-p, --port <port>', 'specify the websocket port to listen to [9870]', 9870)
    .parse(process.argv);

const io = require('socket.io'),
      winston = require('winston');

winston.level = 'debug';
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {'timestamp': true});

const PORT = program.port;

winston.info('Unichat hall service');
winston.info('Listening on port ' + PORT);

const socket = io.listen(PORT);

socket.on('connection', (client) => {
    winston.debug('New connection from client ' + client.id);
});

const program = require('commander');

program
    .version('1.0.0')
    .option('-p, --port <port>', 'specify the websocket port to listen to [9870]', 9870)
    .parse(process.argv);

const io = require('socket.io'),
      winston = require('winston');

winston.level = 'debug';
winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {'timestamp': true});

const PORT = program.port;

winston.info('Unichat hall service');
winston.info('Listening on port ' + PORT);

const socket = io.listen(PORT);

const ROOMID = 'room1';

socket.on('connection', (client) => {
    winston.debug('New connection from client ' + client.id);

    client.on('client-get-partner', () => {
        winston.debug('Client ' + client.id + ' wants partner.');
        client.emit('server-join-room', ROOMID);
        winston.debug('Sending client ' + client.id + ' to room ' + ROOMID);
    });
});

Add client-get-partner listener to hall server


var game = new Phaser.Game(600, 800, Phaser.AUTO, '', {preload: preload, create: create, update: update});

function preload() {
  game.load.image('player', 'assets/player.png');
}

var player;
function create() {
  player = game.add.sprite(game.world.width / 2 - 50, game.world.height - 76, 'player');
}

function update() {

}

var game = new Phaser.Game(600, 800, Phaser.AUTO, '', {preload: preload, create: create, update: update});

function preload() {
  game.load.image('player', 'assets/player.png');
}

var player;
var cursors;
function create() {
  game.physics.startSystem(Phaser.Physics.ARCADE);
  player = game.add.sprite(game.world.width / 2 - 50, game.world.height - 76, 'player');
  game.physics.arcade.enable(player);
  player.body.collideWorldBounds = true;
  cursors = game.input.keyboard.createCursorKeys();
}

function update() {
  player.body.velocity.x = 0;
  player.body.velocity.y = 0;

  if (cursors.left.isDown) {
    player.body.velocity.x = -200;
  }
  else if (cursors.right.isDown) {
    player.body.velocity.x = 200;
  }
  if (cursors.up.isDown) {
    player.body.velocity.y = -200;
  }
  else if (cursors.down.isDown) {
    player.body.velocity.y = 200;
  }
}

Allow player to move up/down/right/left


var WebSocket = require('faye-websocket'),
    http      = require('http'),
    reject    = require('lodash/collection/reject'),
    without   = require('lodash/array/without');

module.exports = function (config) {
  var server = http.createServer(),
      connections = [];

  // Send to everyone except sender
  function broadcastMessageFrom(sender, data) {
    var sockets = reject(connections, function (c) { return c === sender; });
    console.log('Broadcast to %s of %s connections', sockets.length, connections.length);
    sockets.forEach(function (s) {
      s.send(data);
    });
  }

  server.on('upgrade', function(request, socket, body) {
    if (WebSocket.isWebSocket(request)) {
      var ws = new WebSocket(request, socket, body);

      // Keep track of new WebSocket connection
      connections.push(ws);

      ws.on('message', function(event) {
        console.log('New message', event.data);
        broadcastMessageFrom(ws, event.data);
      });

      // Remove from connections
      ws.on('close', function(event) {
        console.log('close', event.code, event.reason);
        connections = without(connections, ws);
        ws = null;
      });
    }
  });

  console.log('Listening on ', config.port);
  server.listen(config.port);
}

var WebSocket = require('faye-websocket'),
    http      = require('http'),
    reject    = require('lodash/collection/reject'),
    without   = require('lodash/array/without');

module.exports = function (config) {
  var server = http.createServer(),
      connections = [];

  // Send to everyone except sender
  function broadcastMessageFrom(sender, data) {
    var sockets = reject(connections, function (c) { return c === sender; });
    console.log('Broadcast to %s of %s connections', sockets.length, connections.length);
    sockets.forEach(function (s) {
      s.send(data);
    });
  }

  server.on('upgrade', function(request, socket, body) {
    if (WebSocket.isWebSocket(request)) {
      var ws = new WebSocket(request, socket, body);

      // Keep track of new WebSocket connection
      connections.push(ws);

      ws.on('message', function(event) {
        console.log('New message', event.data);
        broadcastMessageFrom(ws, event.data);
      });

      // Remove from connections
      ws.on('close', function(event) {
        console.log('close', event.code, event.reason);
        connections = without(connections, ws);
        ws = null;
      });
    }
  });

  console.log('Listening on port', config.port);
  server.listen(config.port);
}

Add consistancy to port logging


var contentType = require('../middleware/contentType'),
    config = require('../config');

function apiRoot(req, res) {
  var root = config.get('apiEndpoint');
  var answer = {
    motd: 'Welcome to the NGP VAN OSDI Service!',
    max_pagesize: 200,
    vendor_name: 'NGP VAN, Inc.',
    product_name: 'VAN',
    osdi_version: '1.0',
    _links: {
      self: {
        href: root,
        title: 'NGP VAN OSDI Service Entry Point'
      },
      'osdi:tags': {
        'href': root + 'tags',
        'title': 'The collection of tags in the system'
      },
      'osdi:questions': {
        'href': root + 'questions',
        'title': 'The collection of questions in the system'
      },
      'osdi:people': {
        'href': root + 'people',
        'title': 'The collection of people in the system'
      }
    }
  };

  return res.status(200).send(answer);
}

module.exports = function (app) {
  app.get('/api/v1/', contentType, apiRoot);
};

var contentType = require('../middleware/contentType'),
    config = require('../config');

function apiRoot(req, res) {
  var root = config.get('apiEndpoint');
  var answer = {
    motd: 'Welcome to the NGP VAN OSDI Service!',
    max_pagesize: 200,
    vendor_name: 'NGP VAN, Inc.',
    product_name: 'VAN',
    osdi_version: '1.0',
    _links: {
      self: {
        href: root,
        title: 'NGP VAN OSDI Service Entry Point'
      },
      'osdi:tags': {
        'href': root + 'tags',
        'title': 'The collection of tags in the system'
      },
      'osdi:questions': {
        'href': root + 'questions',
        'title': 'The collection of questions in the system'
      },
      "osdi:person_signup_helper": {
          "href": root + 'people/person_signup',
          "title": "The person signup helper for the system"
      }
    }
  };

  return res.status(200).send(answer);
}

module.exports = function (app) {
  app.get('/api/v1/', contentType, apiRoot);
};

Correct AEP resource for person signup helper


var Router = require('express').Router;

var keyed = ['get', 'read', 'put', 'patch', 'update', 'del', 'delete'],
	map = { index:'get', list:'get', read:'get', create:'post', update:'put', modify:'patch' };

module.exports = function ResourceRouter(route) {
	route.mergeParams = route.mergeParams ? true : false;
	var router = Router({mergeParams: route.mergeParams}),
		key, fn, url;

	if (route.middleware) router.use(route.middleware);

	if (route.load) {
		router.param(route.id, function(req, res, next, id) {
			route.load(req, id, function(err, data) {
				if (err) return res.status(404).send(err);
				req[route.id] = data;
				next();
			});
		});
	}

	for (key in route) {
		fn = map[key] || key;
		if (typeof router[fn]==='function') {
			url = ~keyed.indexOf(key) ? ('/:'+route.id) : '/';
			router[fn](url, route[key]);
		}
	}

	return router;
};

module.exports.keyed = keyed;

var Router = require('express').Router;

var keyed = ['get', 'read', 'put', 'update', 'patch', 'modify', 'del', 'delete'],
	map = { index:'get', list:'get', read:'get', create:'post', update:'put', modify:'patch' };

module.exports = function ResourceRouter(route) {
	route.mergeParams = route.mergeParams ? true : false;
	var router = Router({mergeParams: route.mergeParams}),
		key, fn, url;

	if (route.middleware) router.use(route.middleware);

	if (route.load) {
		router.param(route.id, function(req, res, next, id) {
			route.load(req, id, function(err, data) {
				if (err) return res.status(404).send(err);
				req[route.id] = data;
				next();
			});
		});
	}

	for (key in route) {
		fn = map[key] || key;
		if (typeof router[fn]==='function') {
			url = ~keyed.indexOf(key) ? ('/:'+route.id) : '/';
			router[fn](url, route[key]);
		}
	}

	return router;
};

module.exports.keyed = keyed;

Add modify to keyed methods to enable patch with id


'use strict';

var es = require('event-stream'),
	path = require('path'),
	zlib = require('zlib');

var compressibles = [
	'.js',
	'.json',
	'.css',
	'.html'
];

function isCompressibleFile( file ) {
	var ext = path.extname( file.path ).toLowerCase();
	return ( compressibles.indexOf( ext ) > -1 );
}

module.exports = function() {

	return es.map( function( file, cb ) {

		if( !isCompressibleFile( file ) ) {
			cb( null, file );
			return;
		}

		zlib.gzip( file.contents, function( err, result ) {
			if( err ) {
				cb( err, null );
				return;
			}
			file.path += '.gz';
			file.contents = result;
			cb( null, file );
		} );

	} );
};

module.exports._isCompressibleFile = isCompressibleFile;

'use strict';

var es = require('event-stream'),
	path = require('path'),
	zlib = require('zlib');

var compressibles = [
	'.js',
	'.css',
	'.html'
];

function isCompressibleFile( file ) {
	var ext = path.extname( file.path ).toLowerCase();
	return ( compressibles.indexOf( ext ) > -1 );
}

module.exports = function() {

	return es.map( function( file, cb ) {

		if( !isCompressibleFile( file ) ) {
			cb( null, file );
			return;
		}

		zlib.gzip( file.contents, function( err, result ) {
			if( err ) {
				cb( err, null );
				return;
			}
			file.path += '.gz';
			file.contents = result;
			cb( null, file );
		} );

	} );
};

module.exports._isCompressibleFile = isCompressibleFile;

Revert "adding JSON to the list of extensions that should be compressed"


import NodePatcher from './../../../patchers/NodePatcher.js';

export default class SoakedMemberAccessOpPatcher extends NodePatcher {
  patchAsExpression() {

  }

  patchAsStatement() {
    this.patchAsExpression();
  }
}

import NodePatcher from './../../../patchers/NodePatcher.js';

export default class SoakedMemberAccessOpPatcher extends NodePatcher {
  patchAsExpression() {
    throw this.error('cannot patch soaked member access (e.g. `a?.b`) yet');
  }
}

Throw when encountering a SoakedMemberAccessOp.


module.exports.movePlugins = function (src, dest) {
  var exec = require('child_process').exec
  console.log(`Copying ${src} to ${dest}`)
  exec(`rm -rf ${dest}${src}`, function (error) {
    if (error) {
      console.error(`exec error: ${error}`)
    } else {
      exec(`cp -r ${src} ${dest}`, function (error, stdout, stderr) {
        if (error) {
          console.error(`exec error: ${error}`)
        }
      })
    }
  })
}

module.exports.movePlugins = function (src, dest) {
  var exec = require('child_process').exec
  exec(`rm ${dest}${src} -rf`, function (error) {
    if (error) console.error(`exec error: ${error}`)
    exec(`cp -r ${src} ${dest}`, function (error, stdout, stderr) {
      if (error) console.error(`exec error: ${error}`)
    })
  })
}

Revert "fixed possible bug & Mac OSX compatibility issue with rm"


'use strict';

define(['ChoPidoTurnos'], function(ChoPidoTurnos) {
  function DoctorProfileCtrl(doctorsService) {
    return {
      '$onInit': function () {
        var _this = this;

        doctorsService
          .getUserRating(this.doctor.id)
          .then(function (result) {
            _this.userRating = result.data.value;
          });

        doctorsService
          .getRatingSummary(this.doctor.id)
          .then(function (result) {
            var data = result.data;

            _this.ratingAverage = Math.round(data.average);
            _this.ratingSummary = data.valuesCount;
          });
      },
      onDoctorRated: function (ev) {
        doctorsService
          .rate(this.doctor.id, ev.rating)
          .then(function (result) {
            // TODO
          });
      }
    };
  }

  DoctorProfileCtrl.$inject = ['doctorsService'];

  ChoPidoTurnos
    .component('doctorProfile', {
      bindings: {
        doctor: '<'
      },
      controller: DoctorProfileCtrl,
      templateUrl: 'views/doctorProfile.html'
    });
});

'use strict';

define(['ChoPidoTurnos'], function(ChoPidoTurnos) {
  function DoctorProfileCtrl(doctorsService, sessionService) {
    return {
      '$onInit': function () {
        var _this = this;

        if (sessionService.getLoggedUser()) {
          doctorsService
            .getUserRating(this.doctor.id)
            .then(function (result) {
              _this.userRating = result.data.value;
            });
        }

        doctorsService
          .getRatingSummary(this.doctor.id)
          .then(function (result) {
            var data = result.data;

            _this.ratingAverage = Math.round(data.average);
            _this.ratingSummary = data.valuesCount;
          });
      },
      onDoctorRated: function (ev) {
        doctorsService
          .rate(this.doctor.id, ev.rating)
          .then(function (result) {
            // TODO
          });
      }
    };
  }

  DoctorProfileCtrl.$inject = ['doctorsService', 'sessionService'];

  ChoPidoTurnos
    .component('doctorProfile', {
      bindings: {
        doctor: '<'
      },
      controller: DoctorProfileCtrl,
      templateUrl: 'views/doctorProfile.html'
    });
});

Remove failing request when user is not logged in


import React from 'react';
import ClipboardJS from 'clipboard';

export default class CopyButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.btnRef = React.createRef();
    this.clipboardRef = React.createRef();
  }

  static defaultProps = {
    content: '',
  };

  componentDidMount() {
    this.clipboardRef.current = new ClipboardJS(this.btnRef.current, {
      text: () => this.props.content,
    });
  }

  render() {
    return (
      <button
        ref={this.btnRef}
        key="copy"
        onClick={() => {}}
        className="btn-copy"
        data-clipboard-target="#testCopyTarget"
      >
        複製到剪貼簿
        <style jsx>{`
          .btn-copy {
            margin-left: 10px;
          }
        `}</style>
      </button>
    );
  }
}

import React from 'react';
import ClipboardJS from 'clipboard';

export default class CopyButton extends React.PureComponent {
  constructor(props) {
    super(props);
    this.btnRef = React.createRef();
    this.clipboardRef = React.createRef();
  }

  static defaultProps = {
    content: '',
  };

  componentDidMount() {
    this.clipboardRef.current = new ClipboardJS(this.btnRef.current, {
      text: () => this.props.content,
    });
  }

  render() {
    return (
      <button
        ref={this.btnRef}
        key="copy"
        onClick={() => {}}
        className="btn-copy"
      >
        複製到剪貼簿
        <style jsx>{`
          .btn-copy {
            margin-left: 10px;
          }
        `}</style>
      </button>
    );
  }
}

Solve 'invalid target element' error


angular.module("Prometheus.services").factory('AnnotationRefresher', ["$http", function($http) {
  return function(graph, scope) {
    var tags = graph.tags.map(function(e) {
      if (e.name) {
        return e.name.split(",").map(function(s) { return s.trim(); });
      } else {
        return "";
      }
    })
    if (tags.length) {
      var range = Prometheus.Graph.parseDuration(graph.range);
      var until = Math.floor(graph.endTime || Date.now()) / 1000;

      tags.forEach(function(t) {
        $http.get('/annotations', {
          params: {
            tags: t.join(","),
            until: until,
            range: range
          }
        })
        .then(function(payload) {
          scope.$broadcast('annotateGraph', payload.data.posts);
        }, function(response) {
          scope.errorMessages.push("Error " + response.status + ": Error occurred fetching annotations.");
        });
      });
    }
  };
}]);

angular.module("Prometheus.services").factory('AnnotationRefresher', ["$http", function($http) {
  return function(graph, scope) {
    var tags = graph.tags.map(function(e) {
      if (e.name) {
        return e.name.split(",").map(function(s) { return s.trim(); });
      } else {
        return "";
      }
    })
    if (tags.length) {
      var range = Prometheus.Graph.parseDuration(graph.range);
      var until = Math.floor(graph.endTime || Date.now()) / 1000;

      tags.forEach(function(t) {
        $http.get('/annotations', {
          params: {
            'tags[]': t,
            until: until,
            range: range
          }
        })
        .then(function(payload) {
          scope.$broadcast('annotateGraph', payload.data.posts);
        }, function(response) {
          scope.errorMessages.push("Error " + response.status + ": Error occurred fetching annotations.");
        });
      });
    }
  };
}]);

Send annotation tags as array.


angular.module("Prometheus.services").factory('AnnotationRefresher', ["$http", function($http) {
  return function(graph, scope) {
    var tags = graph.tags.map(function(e) {
      if (e.name) {
        return e.name.split(",").map(function(s) { return s.trim(); });
      } else {
        return "";
      }
    })
    if (tags.length) {
      var range = Prometheus.Graph.parseDuration(graph.range);
      var until = Math.floor(graph.endTime || Date.now()) / 1000;

      tags.forEach(function(t) {
        $http.get('/annotations', {
          params: {
            'tags[]': t,
            until: until,
            range: range
          }
        })
        .then(function(payload) {
          scope.$broadcast('annotateGraph', payload.data.posts);
        }, function(response) {
          scope.errorMessages.push("Error " + response.status + ": Error occurred fetching annotations.");
        });
      });
    }
  };
}]);

angular.module("Prometheus.services").factory('AnnotationRefresher', ["$http", "VariableInterpolator", function($http, VariableInterpolator) {
  return function(graph, scope) {
    var tags = graph.tags.map(function(e) {
      if (e.name) {
        var n = VariableInterpolator(e.name, scope.vars);
        return n.split(",").map(function(s) { return s.trim(); });
      } else {
        return "";
      }
    })
    if (tags.length) {
      var range = Prometheus.Graph.parseDuration(graph.range);
      var until = Math.floor(graph.endTime || Date.now()) / 1000;

      tags.forEach(function(t) {
        $http.get('/annotations', {
          params: {
            'tags[]': t,
            until: until,
            range: range
          }
        })
        .then(function(payload) {
          scope.$broadcast('annotateGraph', payload.data.posts);
        }, function(response) {
          scope.errorMessages.push("Error " + response.status + ": Error occurred fetching annotations.");
        });
      });
    }
  };
}]);

Allow for tags to be interpolated variables.


'use strict';

exports.register = function (callback) {
  var commands = [{
    name    : 'hello',
    desc    : 'print Hello, John',
    options : {
      wizard : false,
      params : {
        required: 'name',
        optional: 'etc...'
      }
    },
    handler : function (callback, args) {
      console.log ('Hello, ' + args.join (' '));
      callback ();
    }
  }, {
    name    : 'wizard',
    desc    : 'begins a wizard',
    options : {
      wizard : true
    },
    handler : function (callback, args) {
      var wizard = [{
        /* Inquirer definition... */
        type: 'input',
        name: 'zog',
        message: 'tell zog'
      }];

      callback (wizard, function (answers) {
        /* stuff on answers */
        if (answers.zog === 'zog') {
          console.log ('zog zog');
        } else {
          console.log ('lokthar?');
        }

        /*
         * You can return false if you must provide several wizard with only
         * one call to this command handler.
         * You can call callback () without argument in order to return to the
         * prompt instead of returning true.
         */
        return true;
      });
    }
  }];

  callback (null, commands);
};

exports.unregister = function (callback) {
  /* internal stuff */
  callback ();
};

'use strict';

var cmd = {};

cmd.hello = function (callback, args) {
  console.log ('Hello, ' + args.join (' '));
  callback ();
};

cmd.wizard = function (callback) {
  var wizard = [{
    /* Inquirer definition... */
    type: 'input',
    name: 'zog',
    message: 'tell zog'
  }];

  callback (wizard, function (answers) {
    /* stuff on answers */
    if (answers.zog === 'zog') {
      console.log ('zog zog');
    } else {
      console.log ('lokthar?');
    }

    /*
    * You can return false if you must provide several wizard with only
    * one call to this command handler.
    * You can call callback () without argument in order to return to the
    * prompt instead of returning true.
    */
    return true;
  });
};

exports.register = function (callback) {
  var commands = [{
    name    : 'hello',
    desc    : 'print Hello, John',
    options : {
      wizard : false,
      params : {
        required: 'name',
        optional: 'etc...'
      }
    },
    handler : cmd.hello
  }, {
    name    : 'wizard',
    desc    : 'begins a wizard',
    options : {
      wizard : true
    },
    handler : cmd.wizard
  }];

  callback (null, commands);
};

exports.unregister = function (callback) {
  /* internal stuff */
  callback ();
};

Split the register function for the readability.


exports.onClientEntry = () => {
  (() => {
    function OptanonWrapper() { } // eslint-disable-line no-unused-vars
  })();
};

exports.onClientEntry = () => {
  (() => {
    function OptanonWrapper() {} // eslint-disable-line no-unused-vars
  })();
};

// Always start at the top of the page on a route change.
exports.onInitialClientRender = () => {
  if (!window.location.hash) {
    window.scrollTo(0, 0);
  } else {
    window.location = window.location.hash;
  }
};

Add function to start at top of new page unless window.location has a hash


'use strict';

var PropagatorMethods = {
  attach: function(component) {
    var target = component;
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) return;
    }
    this._.components.push(component);
  },

  detach: function(component) {
    for (var i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) {
        this._.components.splice(i, 1);
        break;
      }
    }
  },

  propagate: function() {
    for (var i = this._.components.length; i--;)
      this._.components[i].refresh();
  }
}

module.exports = PropagatorMethods;

'use strict'

let PropagatorMethods = {
  attach: function(component) {
    let target = component
    for (let i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) return
    }
    this._.components.push(component)
  },

  detach: function(component) {
    for (let i = 0, len = this._.components.length; i < len; i++) {
      if (this._.components[i] === component) {
        this._.components.splice(i, 1)
        break
      }
    }
  },

  propagate: function() {
    for (let i = this._.components.length; i--;)
      this._.components[i].refresh()
  }
}

module.exports = PropagatorMethods

Rewrite PropagatorMethods module with ES6 syntax


import { Base } from 'yeoman-generator';
import generatorArguments from './arguments';
import generatorOptions from './options';
import generatorSteps from './steps';

export default class HookGenerator extends Base {
  constructor(...args) {
    super(...args);

    Object.keys(generatorArguments).forEach(key => this.argument(key, generatorArguments[key]));
    Object.keys(generatorOptions).forEach(key => this.option(key, generatorOptions[key]));
  }

  get configuring() {
    return generatorSteps.configuring;
  }

  get conflicts() {
    return generatorSteps.conflicts;
  }

  get default() {
    return generatorSteps.default;
  }

  get end() {
    return generatorSteps.end;
  }

  get initializing() {
    return generatorSteps.initializing
  }

  get install() {
    return generatorSteps.install;
  }

  get prompting() {
    return generatorSteps.prompting
  }

  get writing() {
    return generatorSteps.writing;
  }
}

import { Base } from 'yeoman-generator';
import generatorArguments from './arguments';
import generatorOptions from './options';
import generatorSteps from './steps';

export default class HookGenerator extends Base {
  constructor(...args) {
    super(...args);

    Object.keys(generatorArguments).forEach(key => this.argument(key, generatorArguments[key]));
    Object.keys(generatorOptions).forEach(key => this.option(key, generatorOptions[key]));

    this.description = 'Scaffold a custom hook in api/hooks';
  }

  get configuring() {
    return generatorSteps.configuring;
  }

  get conflicts() {
    return generatorSteps.conflicts;
  }

  get default() {
    return generatorSteps.default;
  }

  get end() {
    return generatorSteps.end;
  }

  get initializing() {
    return generatorSteps.initializing
  }

  get install() {
    return generatorSteps.install;
  }

  get prompting() {
    return generatorSteps.prompting
  }

  get writing() {
    return generatorSteps.writing;
  }
}

Add description to hook generator


/**
 * You can customize the initial state of the module from the editor initialization
 * ```js
 * const editor = grapesjs.init({
 *  i18n: {
 *    locale: 'en',
 *    messages: {
 *      en: {
 *       hello: 'Hello',
 *      },
 *      ...
 *    }
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
 *
 * ```js
 * const i18n = editor.I18n;
 * ```
 *
 * @module I18n
 */
import messages from './messages';

export default () => {
  let em;
  let config;
  const { language } = window.navigator || {};
  const localeDef = language ? language.split('-')[0] : 'en';
  const configDef = {
    locale: localeDef,
    localeFallback: 'en',
    counter: 'n',
    messages
  };

  return {
    name: 'I18n',

    /**
     * Get module configurations
     * @returns {Object} Configuration object
     */
    getConfig() {
      return config;
    },

    /**
     * Initialize module
     * @param {Object} config Configurations
     * @private
     */
    init(opts = {}) {
      config = { ...configDef, ...opts };
      em = opts.em;
      this.em = em;
      return this;
    }
  };
};

/**
 * You can customize the initial state of the module from the editor initialization
 * ```js
 * const editor = grapesjs.init({
 *  i18n: {
 *    locale: 'en',
 *    messages: {
 *      en: {
 *       hello: 'Hello',
 *      },
 *      ...
 *    }
 *  }
 * })
 * ```
 *
 * Once the editor is instantiated you can use its API. Before using these methods you should get the module from the instance
 *
 * ```js
 * const i18n = editor.I18n;
 * ```
 *
 * @module I18n
 */
import messages from './messages';

export default () => {
  const { language } = window.navigator || {};
  const localeDef = language ? language.split('-')[0] : 'en';
  const config = {
    locale: localeDef,
    localeFallback: 'en',
    counter: 'n',
    messages
  };

  return {
    name: 'I18n',

    config,

    /**
     * Get module configurations
     * @returns {Object} Configuration object
     */
    getConfig() {
      return this.config;
    },

    /**
     * Update current locale
     * @param {String} locale Locale value
     * @returns {this}
     * @example
     * i18n.setLocale('it');
     */
    setLocale(locale) {
      this.config.locale = locale;
      return this;
    },

    /**
     * Get current locale
     * @returns {String} Current locale value
     */
    getLocale() {
      return this.config.locale;
    },

    /**
     * Initialize module
     * @param {Object} config Configurations
     * @private
     */
    init(opts = {}) {
      this.em = opts.em;
      return this;
    }
  };
};

Add locales methods to i18n


var path = Npm.require("path");

Package.describe({
  summary: "JavaScript.next-to-JavaScript-of-today compiler",
  version: "1.0.3+0.0.42"
});

Package._transitional_registerBuildPlugin({
  name: "compileHarmony",
  use: [],
  sources: [
    "plugin/compile-harmony.js"
  ],
  npmDependencies: {
    "traceur": "0.0.42"
  }
});

Package.on_use(function (api) {
  // The location of this runtime file is not supposed to change:
  // http://git.io/B2s0Tg
  var dir = ".npm/plugin/compileHarmony/node_modules/traceur/bin/";
  api.add_files(path.join(dir, "traceur-runtime.js"));

  // Export `module.exports` and `exports` down the package pipeline
  api.use('exports');
  api.export(['module', 'exports']);
});

Package.on_test(function (api) {
  api.use(['harmony', 'tinytest']);
  api.add_files([
    'harmony_test_setup.js',
    'harmony_tests.js',
    'tests/harmony_test_setup.next.js',
    'tests/harmony_tests.next.js'
  ], ["client", "server"]);
});

var path = Npm.require("path");

Package.describe({
  summary: "JavaScript.next-to-JavaScript-of-today compiler",
  version: "1.0.3+0.0.42"
});

Package._transitional_registerBuildPlugin({
  name: "compileHarmony",
  use: [],
  sources: [
    "plugin/compile-harmony.js"
  ],
  npmDependencies: {
    "traceur": "0.0.42"
  }
});

Package.on_use(function (api) {
  // The location of this runtime file is not supposed to change:
  // http://git.io/B2s0Tg
  var dir = ".npm/plugin/compileHarmony/node_modules/traceur/bin/";
  api.add_files(path.join(dir, "traceur-runtime.js"));

  // Export `module.exports` and `exports` down the package pipeline
  api.imply('exports');
});

Package.on_test(function (api) {
  api.use(['harmony', 'tinytest']);
  api.add_files([
    'harmony_test_setup.js',
    'harmony_tests.js',
    'tests/harmony_test_setup.next.js',
    'tests/harmony_tests.next.js'
  ], ["client", "server"]);
});

Use `imply` instead of `use` and `export` together


/* eslint-env node */

const Canvas = require('canvas');
const fs = require('fs');

const { Image } = Canvas;

/**
 * Create a new canvas object with height and width
 * set to the given values.
 *
 * @param width {number} The width of the canvas.
 * @param height {number} The height of the canvas.
 *
 * @return {Canvas} A canvas object with
 * height and width set to the given values.
 */
function createCanvas(width, height) {
  return new Canvas(width, height);
}

/**
 * Load the image given by the file path, returning
 * a promise to the image represented by the given path.
 *
 * @parm path {string} The path to the image.
 *
 * @return {Image} An image element referring to
 * the given path.
 */
function loadImage(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) {
        return reject(err);
      }
      const image = new Image();
      image.src = data;
      return resolve(image);
    });
  });
}

module.exports = {
  createCanvas,
  loadImage,
};

/* eslint-env node */

const Canvas = require('canvas');
const fs = require('fs');

const { Image } = Canvas;

/**
 * Create a new canvas object with height and width
 * set to the given values.
 *
 * @param width {number} The width of the canvas.
 * @param height {number} The height of the canvas.
 *
 * @return {Canvas} A canvas object with
 * height and width set to the given values.
 */
function createCanvas(width, height) {
  return new Canvas(width, height);
}

/**
 * Load the image given by the file path, returning
 * a promise to the image represented by the given path.
 *
 * @parm path {string} The path to the image.
 *
 * @return {Image} An image element referring to
 * the given path.
 */
function loadImage(path) {
  return new Promise((resolve, reject) => {
    fs.readFile(path, (err, data) => {
      if (err) {
        reject(err);
        return;
      }
      const image = new Image();
      image.onload = () => resolve(image);
      image.onerror = err => reject(err);
      image.src = data;
      return resolve(image);
    });
  });
}

module.exports = {
  createCanvas,
  loadImage,
};

Use image onload and onerror


/*
 * Copyright (c) 1997-2013, SalesLogix, NA., LLC. All rights reserved.
 */

/**
 * @class Mobile.SalesLogix.Views.PickList
 *
 *
 * @extends Sage.Platform.Mobile.List
 *
 */
define('Mobile/SalesLogix/Views/PickList', [
    'dojo/_base/declare',
    'dojo/string',
    'Sage/Platform/Mobile/List'
], function(
    declare,
    string,
    List
) {

    return declare('Mobile.SalesLogix.Views.PickList', [List], {
        //Templates
        itemTemplate: new Simplate([
            '<h3>{%: $.text %}</h3>'
        ]),

        //View Properties
        id: 'pick_list',
        expose: false,
        resourceKind: 'picklists',
        resourceProperty: 'items',
        contractName: 'system',

        activateEntry: function(params) {
            if (this.options.keyProperty === 'text' && !this.options.singleSelect) {
                params.key = params.descriptor;
            }

            this.inherited(arguments);
        },
        show: function(options) {
            this.set('title', options && options.title || this.title);
            this.inherited(arguments);
        },
        formatSearchQuery: function(searchQuery) {
            return string.substitute('upper(text) like "${0}%"', [this.escapeSearchQuery(searchQuery.toUpperCase())]);
        }
    });
});

/*
 * Copyright (c) 1997-2013, SalesLogix, NA., LLC. All rights reserved.
 */

/**
 * @class Mobile.SalesLogix.Views.PickList
 *
 *
 * @extends Sage.Platform.Mobile.List
 *
 */
define('Mobile/SalesLogix/Views/PickList', [
    'dojo/_base/declare',
    'dojo/string',
    'Sage/Platform/Mobile/List'
], function(
    declare,
    string,
    List
) {

    return declare('Mobile.SalesLogix.Views.PickList', [List], {
        //Templates
        itemTemplate: new Simplate([
            '<h3>{%: $.text %}</h3>'
        ]),

        //View Properties
        id: 'pick_list',
        expose: false,
        resourceKind: 'picklists',
        resourceProperty: 'items',
        contractName: 'system',

        activateEntry: function(params) {
            if (this.options.keyProperty === 'text' && !this.options.singleSelect) {
                params.key = params.descriptor;
            }

            this.inherited(arguments);
        },
        show: function(options) {
            this.set('title', options && options.title || this.title);
            if (options.keyProperty) {
                this.idProperty = options.keyProperty;
            }

            if (options.textProperty) {
                this.labelProperty = options.textProperty;
            }

            this.inherited(arguments);
        },
        formatSearchQuery: function(searchQuery) {
            return string.substitute('upper(text) like "${0}%"', [this.escapeSearchQuery(searchQuery.toUpperCase())]);
        }
    });
});

Update the idProperty and labelProperty of the store properly based on what the picklist is using.


import h from 'hyperscript';
import fetch from 'unfetch';
import audio from './audio';
import aboutSrc from './content/about.md';

let visible = false;
let fetched = false;

const toggle = () => {
  visible = !visible;
  document.body.classList[visible ? 'remove' : 'add']('mod-overflow-hidden');
  about.classList[visible ? 'remove' : 'add']('mod-hidden');
  audio[visible ? 'pause' : 'play']();
  if (!fetched) {
    fetched = true;
    fetch(aboutSrc)
      .then(response => response.text())
      .then(data => {
        about.innerHTML = data;
        about.appendChild(closeButton);
      });
  }
};

const about = h('div.about.mod-hidden')
const closeButton = h('div.about-close-button', { onclick: toggle }, '×');
document.body.appendChild(about);

export default { toggle };

import h from 'hyperscript';
import fetch from 'unfetch';
import audio from './audio';
import aboutSrc from './content/about.md';

let visible = false;
let fetched = false;

const toggle = async () => {
  visible = !visible;
  document.body.classList[visible ? 'remove' : 'add']('mod-overflow-hidden');
  about.classList[visible ? 'remove' : 'add']('mod-hidden');
  audio[visible ? 'pause' : 'play']();
  if (!fetched) {
    fetched = true;
    const response = await fetch(aboutSrc);
    const data = await response.text();
    about.innerHTML = data;
    about.appendChild(closeButton);
  }
};

const about = h('div.about.mod-hidden');
const closeButton = h('div.about-close-button', { onclick: toggle }, '×');
document.body.appendChild(about);

export default { toggle };

Switch markdown loading to fetch/async/await


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


module.exports = (config) => {
  config.set({
    frameworks: ['mocha', 'karma-typescript'],
    browsers: ['ChromeHeadless'],
    singleRun: true,
    concurrency: Infinity,
    reporters: ['mocha'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_WARN,

    files: [
      'src/*.ts',
      'test/*.ts',
    ],

    preprocessors: {
      '**/*.ts': ['karma-typescript'],
    },

    karmaTypescriptConfig: {
      compilerOptions: {
        target: 'es6',
        baseUrl: __dirname,
      },
    },
  })
};

module.exports = (config) => {
	config.set({
		frameworks: ['mocha', 'karma-typescript'],
		browsers: ['ChromeHeadless'],
		singleRun: true,
		concurrency: Infinity,
		reporters: ['mocha'],
		port: 9876,
		colors: true,
		logLevel: config.LOG_WARN,

		files: [
			'src/*.ts',
			'test/*.ts',

			{
				pattern: 'test/*.html',
				watched: false,
				included: false,
				served: true,
			},
		],

		preprocessors: {
			'**/*.ts': ['karma-typescript'],
		},

		karmaTypescriptConfig: {
			compilerOptions: {
				target: 'es6',
				baseUrl: __dirname,
			},
		},
	});
};

Add file rule for test template file


var http = require('http');

/*
* Convert from coursera sample format to javascript array.
* e.g :
*
* a.txt :
*
* 111
* 222
* 333
* 444
*
* converts to
*
* [111,222,333,444]
* */
var strToArray = function(str) {
    return str.trim().split('\r\n').map(function (elStr) {
        return parseInt(elStr);
    })
}

function simpleHttpHandler(url, callback) {
    http.get(url, function(response) {
        var str = '';
        response.on('data', function (chunk) {
            str += chunk;
        });
        response.on('end', function () {
            callback( str )
        });
    });
}

exports.getNumberArray = function (url, callback) {
    simpleHttpHandler(url, function (str) {
        var numberArry = str.trim().split('\r\n').map(function (elStr) {
            return parseInt(elStr);
        })
        callback(numberArry);
    });

};

var http = require('http');

var courseraHttpHandler = function(url, processor, callback) {
    http.get(url, function(response) {
        var str = '';
        response.on('data', function (chunk) {
            str += chunk;
        });
        response.on('end', function () {
            var processedStr = str.trim().split('\r\n').map( processor );
            callback( processedStr );
        });
    });
}

var strToInt = function (str) {
    return parseInt(str);
}
/*
 * Convert from coursera sample format to javascript array.
 * e.g :
 *
 * a.txt :
 *
 * 111
 * 222
 * 333
 * 444
 *
 * converts to
 *
 * [111,222,333,444]
 * */

exports.getNumberArray = function (url, callback) {
    courseraHttpHandler(url, strToInt, callback);

};

exports.getAdjacencylist = function (url, callback) {
    courseraHttpHandler(url, function (str) {
        return str.trim().split('\t').map( strToInt );
    }, callback);
}

Refactor coursera tool. Add getAdjacencylist function.


/**
 * @provides javelin-behavior-repository-crossreference
 * @requires javelin-behavior
 *           javelin-dom
 *           javelin-uri
 */

JX.behavior('repository-crossreference', function(config) {

  // NOTE: Pretty much everything in this file is a worst practice. We're
  // constrained by the markup generated by the syntax highlighters.

  var container = JX.$(config.container);
  JX.DOM.alterClass(container, 'repository-crossreference', true);
  JX.DOM.listen(
    container,
    'click',
    'tag:span',
    function(e) {
      var target = e.getTarget();
      var map = {nc : 'class', nf : 'function'};
      if (JX.DOM.isNode(target, 'span') && (target.className in map)) {
        var symbol = target.textContent || target.innerText;
        var uri = JX.$U('/diffusion/symbol/' + symbol + '/');
        uri.addQueryParams({
          type : map[target.className],
          lang : config.lang,
          projects : config.projects.join(','),
          jump : true
        });
        window.open(uri);
        e.kill();
      }
    });

});

/**
 * @provides javelin-behavior-repository-crossreference
 * @requires javelin-behavior
 *           javelin-dom
 *           javelin-uri
 */

JX.behavior('repository-crossreference', function(config) {

  // NOTE: Pretty much everything in this file is a worst practice. We're
  // constrained by the markup generated by the syntax highlighters.

  var container = JX.$(config.container);
  JX.DOM.alterClass(container, 'repository-crossreference', true);
  JX.DOM.listen(
    container,
    'click',
    'tag:span',
    function(e) {
      var target = e.getTarget();
      var map = {nc : 'class', nf : 'function'};
      while (target !== document.body) {
        if (JX.DOM.isNode(target, 'span') && (target.className in map)) {
          var symbol = target.textContent || target.innerText;
          var uri = JX.$U('/diffusion/symbol/' + symbol + '/');
          uri.addQueryParams({
            type : map[target.className],
            lang : config.lang,
            projects : config.projects.join(','),
            jump : true
          });
          window.open(uri);
          e.kill();
          break;
        }
        target = target.parentNode;
      }
    });

});

Make symbol linking more lenient.


var Queue = require('./queue');
var Job = require('./job');
var Worker = require('./worker');
var redis = require('./redis');

exports.redis = redis;

exports.createQueue = function(name){
  var q = new Queue(name);
  q.client = exports.redis.createClient();
  q.workerClient = exports.redis.createClient();
  return q;
};

exports.Job = Job;
exports.Worker = Worker;

var Queue = require('./queue');
var Job = require('./job');
var Worker = require('./worker');
var redis = require('./redis');

exports.redis = redis;

exports.createQueue = function(name, opts){
  if(!opts)
    opts = {};

  if(typeof opts.redis == 'undefined'){
    opts.redis = redis;
  }

  var q = new Queue(name, opts);
  return q;
};

exports.Job = Job;
exports.Worker = Worker;

Send redis library to queue via opts


var JSLINT = require("../lib/nodelint");

function addDefaults(options) {
    'use strict';
    ['node', 'es5'].forEach(function (opt) {
        if (!options.hasOwnProperty(opt)) {
            options[opt] = true;
        }
    });
    return options;
}

exports.lint = function (script, options) {
    'use strict';
    // remove shebang
    /*jslint regexp: true*/
    script = script.replace(/^\#\!.*/, "");

    options = options || {};
    delete options.argv;
    options = addDefaults(options);

    var ok = JSLINT(script, options),
        result = {
            ok: true,
            errors: []
        };

    if (!ok) {
        result = JSLINT.data();
        result.errors = (result.errors || []).filter(function (error) {
            return !(/\/\/.*bypass/).test(error.evidence);
        });
        result.ok = !result.errors.length;
    }

    result.options = options;

    return result;
};

var JSLINT = require("../lib/nodelint");

function addDefaults(options) {
    'use strict';
    ['node', 'es5'].forEach(function (opt) {
        if (!options.hasOwnProperty(opt)) {
            options[opt] = true;
        }
    });
    return options;
}

exports.lint = function (script, options) {
    'use strict';
    // remove shebang
    /*jslint regexp: true*/
    script = script.replace(/^\#\!.*/, "");

    options = options || {};
    delete options.argv;
    options = addDefaults(options);

    var ok = JSLINT(script, options),
        result = {
            ok: true,
            errors: []
        };

    if (!ok) {
        result = JSLINT.data();
        result.errors = (result.errors || []).filter(function (error) {
            return !error.evidence || !(/\/\/.*bypass/).test(error.evidence);
        });
        result.ok = !result.errors.length;
    }

    result.options = options;

    return result;
};

Fix unexpected error when there is no context in an error


"use strict";

angular.module('arethusa.artificialToken').directive('artificialTokenList', [
  'artificialToken',
  'idHandler',
  function(artificialToken, idHandler) {
    return {
      restrict: 'A',
      scope: true,
      link: function(scope, element, attrs) {
        scope.aT = artificialToken;
        scope.formatId = function(id) {
          return idHandler.formatId(id, '%w');
        };
      },
      templateUrl: 'templates/arethusa.artificial_token/artificial_token_list.html'
    };
  }
]);

"use strict";

angular.module('arethusa.artificialToken').directive('artificialTokenList', [
  'artificialToken',
  'idHandler',
  function(artificialToken, idHandler) {
    return {
      restrict: 'A',
      scope: true,
      link: function(scope, element, attrs) {
        scope.aT = artificialToken;
        scope.formatId = function(id) {
          return idHandler.formatId(id, '%s-%w');
        };
      },
      templateUrl: 'templates/arethusa.artificial_token/artificial_token_list.html'
    };
  }
]);

Fix id formatting in artificialTokenList


'use strict';

angular.module('confRegistrationWebApp')
  .directive('radioQuestion', function () {
    return {
      templateUrl: 'views/radioQuestion.html',
      restrict: 'E',
      controller: function ($scope) {
        $scope.answer = {};
      }
    };
  });

'use strict';

angular.module('confRegistrationWebApp')
  .directive('radioQuestion', function () {
    return {
      templateUrl: 'views/radioQuestion.html',
      restrict: 'E',
      controller: function ($scope) {
        $scope.updateAnswer = function (answer) {
          console.log('block ' + $scope.block.id + ' answer changed to ' + answer);
        };
        $scope.answer = {};
      }
    };
  });

Add the previously removed updateAnswer function


var escape    = require('./util/escape')
var format    = require('string-template');
var hljs      = require('highlight.js');
var heading   = require('./util/writeHeading');
var marked    = require('marked');
var multiline = require('multiline');

var mdRenderer = new marked.Renderer();

var HTML_EXAMPLE_TEMPLATE = multiline(function() {/*

    {1}

*/});

// Adds an anchor link to each heading created
mdRenderer.heading = heading;

// Adds special formatting to each code block created
// If the language is suffixed with "_example", the raw HTML is printed after the code sample, creating a live example.
mdRenderer.code = function(code, language) {
  var extraOutput = '';

  if (language === 'inky') {
    return require('./buildInkySample')(code);
  }

  if (typeof language === 'undefined') language = 'html';

  // If the language is *_example, live code will print out along with the sample
  if (language.match(/_example$/)) {
    extraOutput = format('\n\n
{0}
', [code]);
    language = language.replace(/_example$/, '');
  }

  var renderedCode = hljs.highlight(language, code).value;
  var output = format(HTML_EXAMPLE_TEMPLATE, [language, renderedCode]);

  return output + extraOutput;
}

module.exports = mdRenderer;

var escape    = require('./util/escape')
var format    = require('string-template');
var hljs      = require('highlight.js');
var heading   = require('./util/writeHeading');
var marked    = require('marked');
var multiline = require('multiline');

var mdRenderer = new marked.Renderer();

var HTML_EXAMPLE_TEMPLATE = multiline(function() {/*

    {1}

*/});

// Adds an anchor link to each heading created
mdRenderer.heading = heading;

// Adds special formatting to each code block created
// If the language is suffixed with "_example", the raw HTML is printed after the code sample, creating a live example.
mdRenderer.code = function(code, language) {
  var extraOutput = '';

  if (language === 'inky') {
    return require('./util/buildInkySample')(code);
  }

  if (typeof language === 'undefined') language = 'html';

  // If the language is *_example, live code will print out along with the sample
  if (language.match(/_example$/)) {
    extraOutput = format('\n\n
{0}
', [code]);
    language = language.replace(/_example$/, '');
  }

  var renderedCode = hljs.highlight(language, code).value;
  var output = format(HTML_EXAMPLE_TEMPLATE, [language, renderedCode]);

  return output + extraOutput;
}

module.exports = mdRenderer;

Fix incorrect require() path in Marked renderer


export function search(select, queryString, callback) {
  select.find('input').simulate('change', { target: { value: queryString } });
  setTimeout(() => { callback(); }, 0);
}

export function chooseOption(select, optionText) {
  const options = select.find('.Select-option span');
  const matchingOptions = options.findWhere((option) => {
    return option.text() === optionText;
  });
  matchingOptions.simulate('mouseDown');
}

export function chooseOptionBySearching(select, queryString, optionText, callback) {
  search(select, queryString, () => {
    chooseOption(select, optionText);
    callback();
  });
}

export default {
  search,
  chooseOption,
  chooseOptionBySearching
};

import Select from 'react-select';

function findSelect(wrapper) {
  const plainSelect = wrapper.find(Select);
  if (plainSelect.length > 0) {
    return plainSelect;
  }

  const asyncSelect = wrapper.find(Select.Async);
  if (asyncSelect.length > 0) {
    return asyncSelect;
  }

  throw "Couldn't find Select or Select.Async in wrapper";
}

export function search(wrapper, queryString, callback) {
  findSelect(wrapper).find('.Select-input input').simulate('change', { target: { value: queryString } });
  setTimeout(callback, 0);
}

export function chooseOption(wrapper, optionText) {
  const options = findSelect(wrapper).find('.Select-option');
  const matchingOptions = options.findWhere((option) => {
    return option.text() === optionText;
  });
  matchingOptions.simulate('mouseDown');
}

export function chooseOptionBySearching(wrapper, queryString, optionText, callback) {
  search(wrapper, queryString, () => {
    chooseOption(wrapper, optionText);
    callback();
  });
}

export default {
  search,
  chooseOption,
  chooseOptionBySearching
};

Make helpers a little more robust by searching specifically for Select or Select.Async components


import {StreamTransformer} from './stream.transformer';
import {TracebackTransformer} from './traceback.transformer';
import {LaTeXTransformer} from './latex.transformer';
import {MarkdownTransformer} from 'transformime-commonmark';
import {PDFTransformer} from './pdf.transformer';

export default {StreamTransformer, TracebackTransformer, MarkdownTransformer};

import {StreamTransformer} from './stream.transformer';
import {TracebackTransformer} from './traceback.transformer';
import {LaTeXTransformer} from './latex.transformer';
import {MarkdownTransformer} from 'transformime-commonmark';
import {PDFTransformer} from './pdf.transformer';

export default {
    StreamTransformer,
    TracebackTransformer,
    MarkdownTransformer,
    LaTeXTransformer,
    PDFTransformer
};

Include the PDF and LaTeX Transformers


Router.configure({
  layoutTemplate: 'layout'
});
Router.route('/votes', {name: 'votesList'});
Router.route('/iframe', {name: 'iFrame'});
Router.route('/submitvote', {name: 'submitVote'});
Router.route('/signup', {name: 'signup'});
Router.route('/scores', {name: 'scoreCard'});
Router.route('/login', {name: 'loginpage'});

var requireLogin = function() { if (! Meteor.user()) {
  if (Meteor.loggingIn()) { this.render(this.loadingTemplate);
  } this.render('accessDenied');
} else {
  this.next(); }
}

Router.onBeforeAction(requireLogin, {only: 'submitVote'});

Router.route('/votes/:_id', {
  name: 'voteInfoPage',
  data: function() { return VotesCollection.findOne(this.params._id); }
});

Router.route('/votes/comments/:_id', {
  name: 'commentList',
  data: function() { return VotesCollection.findOne(this.params._id); }
});

Router.configure({
  layoutTemplate: 'layout'
});
Router.route('/', {name: 'votesList'});
Router.route('/iframe', {name: 'iFrame'});
Router.route('/submitvote', {name: 'submitVote'});
Router.route('/signup', {name: 'signup'});
Router.route('/scores', {name: 'scoreCard'});
Router.route('/login', {name: 'loginpage'});

var requireLogin = function() { if (! Meteor.user()) {
  if (Meteor.loggingIn()) { this.render(this.loadingTemplate);
  } this.render('accessDenied');
} else {
  this.next(); }
}

Router.onBeforeAction(requireLogin, {only: 'submitVote'});

Router.route('/votes/:_id', {
  name: 'voteInfoPage',
  data: function() { return VotesCollection.findOne(this.params._id); }
});

Router.route('/votes/comments/:_id', {
  name: 'commentList',
  data: function() { return VotesCollection.findOne(this.params._id); }
});

Change votes route to /


Router.configure({
  layoutTemplate: 'layout',
  loadingTemplate: 'loading',
  notFoundTemplate: 'notFound',
  waitOn: function() {
    return [Meteor.subscribe('posts'), Meteor.subscribe('notifications')];
  }
});

Router.route('/', { name: 'postsList'});

Router.route('/posts/:_id', {
  name: 'postPage',

  waitOn: function() {
    return Meteor.subscribe('comments', this.params._id);
  },

  data: function() {
    return Posts.findOne(this.params._id);
  }
});

Router.route('posts/:_id/edit', {
  name: 'postEdit',
  data: function() {
    return Posts.findOne(this.params._id);
  }
});

Router.route('/submit', { name: 'postSubmit' });

var requireLogin = function() {
  if (!Meteor.user()) {
    if (Meteor.loggingIn()) {
      this.render(this.loadingTemplate);
    } else {
      this.render('accessDenied');
    }
  } else {
    this.next();
  }
}

Router.onBeforeAction('dataNotFound', { only: 'postPage' });
Router.onBeforeAction(requireLogin, { only: 'postSubmit' });

Router.configure({
  layoutTemplate: 'layout',
  loadingTemplate: 'loading',
  notFoundTemplate: 'notFound',
  waitOn: function() {
    return Meteor.subscribe('notifications');
  }
});

Router.route('/', { name: 'postsList'});

Router.route('/posts/:_id', {
  name: 'postPage',

  waitOn: function() {
    return Meteor.subscribe('comments', this.params._id);
  },

  data: function() {
    return Posts.findOne(this.params._id);
  }
});

Router.route('posts/:_id/edit', {
  name: 'postEdit',
  data: function() {
    return Posts.findOne(this.params._id);
  }
});

Router.route('/submit', { name: 'postSubmit' });

Router.route('/:postsLimit?', {
  name: 'postsList',
  waitOn: function() {
    var limit = parseInt(this.params.postsLimit) || 5;
    return Meteor.subscribe('posts', { sort: { submitted: -1 }, limit: limit });
  }
});

var requireLogin = function() {
  if (!Meteor.user()) {
    if (Meteor.loggingIn()) {
      this.render(this.loadingTemplate);
    } else {
      this.render('accessDenied');
    }
  } else {
    this.next();
  }
}

Router.onBeforeAction('dataNotFound', { only: 'postPage' });
Router.onBeforeAction(requireLogin, { only: 'postSubmit' });

Add route to limit posts


import BarChart from './BarChart';
import BoxPlot from './BoxPlot';
import BulletChart from './BulletChart';
import GanttChart from './GanttChart';
import Geo from './Geo';
import Heatmap from './Heatmap';
import Histogram from './Histogram';
import LineChart from './LineChart';
import LineUp from './LineUp';
import ParallelCoordinates from './ParallelCoordinates';
import ScatterPlot from './ScatterPlot';
import ScatterPlotMatrix from './ScatterPlotMatrix';
import UpSet from './UpSet';

export default {
  BarChart,
  BoxPlot,
  BulletChart,
  GanttChart,
  Geo,
  Heatmap,
  Histogram,
  LineChart,
  LineUp,
  ParallelCoordinates,
  UpSet
};

import BarChart from './BarChart';
import BoxPlot from './BoxPlot';
import BulletChart from './BulletChart';
import GanttChart from './GanttChart';
import Geo from './Geo';
import Heatmap from './Heatmap';
import Histogram from './Histogram';
import LineChart from './LineChart';
import LineUp from './LineUp';
import ParallelCoordinates from './ParallelCoordinates';
import ScatterPlot from './ScatterPlot';
import ScatterPlotMatrix from './ScatterPlotMatrix';
import UpSet from './UpSet';

export default {
  BarChart,
  BoxPlot,
  BulletChart,
  GanttChart,
  Geo,
  Heatmap,
  Histogram,
  LineChart,
  LineUp,
  ParallelCoordinates,
  ScatterPlot,
  ScatterPlotMatrix,
  UpSet
};

Replace lost classes in components list


"use strict";

(function () {
    angular
        .module("argo")
        .controller("Trades", Trades);

    Trades.$inject = ["toastService", "tradesService"];
    function Trades(toastService, tradesService) {
        var vm = this;

        vm.getTrades = getTrades;
        vm.closeTrade = closeTrade;

        tradesService.getTrades().then(getTrades);

        function getTrades(trades) {
            vm.trades = trades;
        }

        function closeTrade(id) {
            tradesService.closeTrade(id).then(function (trade) {
                var message = "Closed " +
                    trade.side + " " +
                    trade.instrument +
                    " #" + trade.id +
                    " @" + trade.price +
                    " P&L " + trade.profit;

                toastService.show(message);
                tradesService.getTrades().then(getTrades);
            });
        }
    }

}());

"use strict";

(function () {
    angular
        .module("argo")
        .controller("Trades", Trades);

    Trades.$inject = ["$mdDialog", "toastService", "tradesService"];
    function Trades($mdDialog, toastService, tradesService) {
        var vm = this;

        vm.getTrades = getTrades;
        vm.closeTrade = closeTrade;

        tradesService.getTrades().then(getTrades);

        function getTrades(trades) {
            vm.trades = trades;
        }

        function closeTrade(event, id) {
            var confirm = $mdDialog.confirm()
                  .content("Are you sure to close the trade?")
                  .ariaLabel("Trade closing confirmation")
                  .ok("Ok")
                  .cancel("Cancel")
                  .targetEvent(event);

            $mdDialog.show(confirm).then(function () {
                tradesService.closeTrade(id).then(function (trade) {
                    var message = "Closed " +
                        trade.side + " " +
                        trade.instrument +
                        " #" + trade.id +
                        " @" + trade.price +
                        " P&L " + trade.profit;

                    toastService.show(message);
                    tradesService.getTrades().then(getTrades);
                });
            });
        }
    }

}());

Add confirmation dialog to close trade.


var Transmitter = function (config) {

  var router = require('./router.js');
  router(config);

  var io = require('socket.io')(router.server);
  // Socket.io connection handling
  io.on('connection', function(socket){
    console.log('PULSAR: client connected');
    socket.on('disconnect', function() {
      console.log('PULSAR: client disconnected');
    });
  });

  var Processor = require('@dermah/pulsar-input-keyboard');
  var processor = new Processor(io, config);
}

module.exports = Transmitter;

var Transmitter = function (config) {

  var router = require('./router.js');
  router(config);

  var io = require('socket.io')(router.server);
  // Socket.io connection handling
  io.on('connection', function(socket){
    console.log('PULSAR: client connected');
    socket.on('disconnect', function() {
      console.log('PULSAR: client disconnected');
    });
  });

  var Processor = require('@dermah/pulsar-input-keyboard');
  var processor = new Processor(config);

  processor.on('pulse', pulse => {
    io.emit('pulse', pulse)
  });
  processor.on('pulsar control', pulse => {
    io.emit('pulsar control', pulse)
  });
  processor.on('pulse update', pulse => {
    io.emit('pulse update', pulse);
  });
}

module.exports = Transmitter;

Use the new EventEmitter input by passing its events to socket.io


"use strict";

const http = require('http');
const mongoose = require('mongoose');
const requireAll = require('require-all');
const TelegramBot = require('node-telegram-bot-api');
const GitHubNotifications = require('./common/GitHubNotifications');
const User = require('./models/User');

const BOT_COMMANDS = requireAll({dirname: `${__dirname}/commands`});
const TELEGRAM_BOT_TOKEN = process.env['TELEGRAM_BOT_TOKEN'];

if (!TELEGRAM_BOT_TOKEN) throw new Error('You must provide telegram bot token');

const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, {polling: true});

Object.keys(BOT_COMMANDS).forEach(command => BOT_COMMANDS[command](bot));

mongoose.connect(process.env['MONGODB_URI']);

User.find({}, (error, users) => {
  if (error) throw new Error(error);

  users.forEach(user => {
    new GitHubNotifications(user.username, user.token).on('notification', data => {
      bot.sendMessage(user.telegramId, `You have unread notification - ${data}`);
    });
  });
});

http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Bot is working\n');
}).listen(process.env['PORT']);

"use strict";

const http = require('http');
const mongoose = require('mongoose');
const requireAll = require('require-all');
const TelegramBot = require('node-telegram-bot-api');
const GitHubNotifications = require('./services/GitHubNotifications');
const User = require('./models/User');

const BOT_COMMANDS = requireAll({dirname: `${__dirname}/commands`});
const TELEGRAM_BOT_TOKEN = process.env['TELEGRAM_BOT_TOKEN'];

if (!TELEGRAM_BOT_TOKEN) throw new Error('You must provide telegram bot token');

const telegramBotConfig = process.env.NODE_ENV === 'production' ? {webHook: true} : {polling: true};
const bot = new TelegramBot(TELEGRAM_BOT_TOKEN, telegramBotConfig);

Object.keys(BOT_COMMANDS).forEach(command => BOT_COMMANDS[command](bot));

mongoose.connect(process.env['MONGODB_URI']);

User.find({}, (error, users) => {
  if (error) throw new Error(error);

  users.forEach(user => {
    new GitHubNotifications(user.username, user.token).on('notification', data => {
      bot.sendMessage(user.telegramId, `You have unread notification - ${data}`);
    });
  });
});

http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Bot is working\n');
}).listen(process.env['PORT']);

Implement switching to webhooks in production


'use strict';

require('foundation-sites/scss/foundation.scss')
require('./styles.scss');
require('font-awesome/css/font-awesome.css');

// Require index.html so it gets copied to dist
require('./index.html');

var Elm = require('./Main.elm');
var mountNode = document.getElementById('main');

// The third value on embed are the initial values for incomming ports into Elm
var app = Elm.Main.embed(mountNode);

'use strict';

require('./styles.scss');
require('font-awesome/css/font-awesome.css');

// Require index.html so it gets copied to dist
require('./index.html');

var Elm = require('./Main.elm');
var mountNode = document.getElementById('main');

// The third value on embed are the initial values for incomming ports into Elm
var app = Elm.Main.embed(mountNode);

Remove foundation-sites require as foundation is not used anymore.


export default function enhancer() {
    return (next) => (reducer, preloadedState) => {
        const initialState = Object.assign({}, preloadedState, loadState(restoreState));
        const store = next(reducer, initialState);
        store.subscribe(() => saveState(store.getState()));
        return store;
    }
}

const restoreState = (state) => {
    return {
        misc: state
    };
}

const loadState = (transform) => {
    const state = {
        locked: true
    };
    return transform(state);
}

const saveState = (state) => {
    if (state.misc) {
        console.log(state.misc);
    }
}

export default function enhancer() {
    return (next) => (reducer, preloadedState) => {
        const initialState = Object.assign({}, preloadedState, loadState(restoreState));
        const store = next(reducer, initialState);
        store.subscribe(() => saveState(store.getState(), filterState));
        return store;
    }
}

const restoreState = (state) => {
    return {
        misc: state
    };
}

const filterState = (state) => {
    return state.misc;
}

const storageKey = 'sample';

const loadState = (transform) => {
    const saved = window.localStorage.getItem(storageKey);
    if (saved) {
        return transform(JSON.parse(saved));
    }
}

const saveState = (state, transform) => {
    const saving = transform(state);
    if (saving) {
        window.localStorage.setItem(storageKey, JSON.stringify(saving));
    }
}

Tweak sample for react-redux in order to use local storage


/* global legacyConvert, module, project */

module.exports = function(grunt) {
	grunt.registerTask('convertLegacy', function(task) {
		var dest = legacyConvert[task],
			content = grunt.file.read(dest),
			rootSize = project.style.legacy.rootSize,
			rootValue = 10;

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

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

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

/* global legacyConvert, module, project */

module.exports = function(grunt) {
	grunt.registerTask('convertLegacy', function(task) {
		var dest = legacyConvert[task],
			content = grunt.file.read(dest),
			rootSize = project.style.legacy.rootSize,
			rootValue = 10;

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

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

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

Replace :: with : in IE8 for backward compatibility with element pseudo selectors


/* eslint-disable import/no-named-as-default */
/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import { Stepper } from './Stepper';
import { TabNavigator } from './TabNavigator';
import DataTablePageView from './DataTablePageView';

import { WizardActions } from '../actions/WizardActions';
import { selectCurrentTab } from '../selectors/wizard';

/**
 * Layout component for a Tracker and TabNavigator, displaying steps
 * to completion for completion. See TabNavigator and StepsTracker
 * for individual component implementation.
 */
const WizardComponent = ({ tabs, titles, currentTab, nextTab }) => (
  <DataTablePageView>
    <Stepper
      numberOfSteps={tabs.length}
      currentStep={currentTab}
      onPress={nextTab}
      titles={titles}
    />
    <TabNavigator tabs={tabs} currentTabIndex={currentTab} />
  </DataTablePageView>
);

WizardComponent.propTypes = {
  tabs: PropTypes.array.isRequired,
  titles: PropTypes.array.isRequired,
  nextTab: PropTypes.func.isRequired,
  currentTab: PropTypes.number.isRequired,
};

const mapStateToProps = state => {
  const currentTab = selectCurrentTab(state);
  return { currentTab };
};

const mapDispatchToProps = dispatch => ({
  nextTab: tab => dispatch(WizardActions.switchTab(tab)),
});

export const Wizard = connect(mapStateToProps, mapDispatchToProps)(WizardComponent);

/* eslint-disable import/no-named-as-default */
/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';

import { Stepper } from './Stepper';
import { TabNavigator } from './TabNavigator';
import DataTablePageView from './DataTablePageView';

import { WizardActions } from '../actions/WizardActions';
import { selectCurrentTab } from '../selectors/wizard';

/**
 * Layout component for a Tracker and TabNavigator, displaying steps
 * to completion for completion. See TabNavigator and StepsTracker
 * for individual component implementation.
 */
const WizardComponent = ({ tabs, titles, currentTab, switchTab }) => (
  <DataTablePageView>
    <Stepper
      numberOfSteps={tabs.length}
      currentStep={currentTab}
      onPress={switchTab}
      titles={titles}
    />
    <TabNavigator tabs={tabs} currentTabIndex={currentTab} />
  </DataTablePageView>
);

WizardComponent.propTypes = {
  tabs: PropTypes.array.isRequired,
  titles: PropTypes.array.isRequired,
  switchTab: PropTypes.func.isRequired,
  currentTab: PropTypes.number.isRequired,
};

const mapStateToProps = state => {
  const currentTab = selectCurrentTab(state);
  return { currentTab };
};

const mapDispatchToProps = dispatch => ({
  switchTab: tab => dispatch(WizardActions.switchTab(tab)),
});

export const Wizard = connect(mapStateToProps, mapDispatchToProps)(WizardComponent);

Add renaming of nextTab -> switchTab


module.exports = {
  'ar': require('../../i18n/ar.json'),
  'da': require('../../i18n/da.json'),
  'de': require('../../i18n/de.json'),
  'en': require('../../i18n/en.json'),
  'es': require('../../i18n/es.json'),
  'fr': require('../../i18n/fr-FR.json'),
  'fr-FR': require('../../i18n/fr-FR.json'),
  'he': require('../../i18n/he.json'),
  'it': require('../../i18n/it.json'),
  'ja': require('../../i18n/ja.json'),
  'ko': require('../../i18n/ko.json'),
  'nb-NO': require('../../i18n/nb-NO.json'),
  'nl': require('../../i18n/nl-NL.json'),
  'nl-NL': require('../../i18n/nl-NL.json'),
  'pt': require('../../i18n/pt.json'),
  'pt-BR': require('../../i18n/pt-BR.json'),
  'ru': require('../../i18n/ru.json'),
  'sv': require('../../i18n/sv.json'),
  'tlh': require('../../i18n/tlh.json'),
  'tr': require('../../i18n/tr.json'),
  'zh': require('../../i18n/zh.json'),
  'zh-TW': require('../../i18n/zh-TW.json')
}

module.exports = {
  'ar': require('../../i18n/ar.json'),
  'da': require('../../i18n/da.json'),
  'de': require('../../i18n/de.json'),
  'en': require('../../i18n/en.json'),
  'es': require('../../i18n/es.json'),
  'fr': require('../../i18n/fr-FR.json'),
  'fr-FR': require('../../i18n/fr-FR.json'),
  'he': require('../../i18n/he.json'),
  'it': require('../../i18n/it.json'),
  'ja': require('../../i18n/ja.json'),
  'ko': require('../../i18n/ko.json'),
  'nb-NO': require('../../i18n/nb-NO.json'),
  'nl': require('../../i18n/nl-NL.json'),
  'nl-NL': require('../../i18n/nl-NL.json'),
  'pl': require('../../i18n/pl.json'),
  'pt': require('../../i18n/pt.json'),
  'pt-BR': require('../../i18n/pt-BR.json'),
  'ru': require('../../i18n/ru.json'),
  'sv': require('../../i18n/sv.json'),
  'tlh': require('../../i18n/tlh.json'),
  'tr': require('../../i18n/tr.json'),
  'zh': require('../../i18n/zh.json'),
  'zh-TW': require('../../i18n/zh-TW.json')
}

Add polish dict to base code