/**
 * @license
 * Copyright (c) 2016 The IBM Research Emergent Solutions authors. All rights reserved.
 * This code may only be used under the MIT style license found at https://ibmresearch.github.io/LICENSE.txt
 * The complete set of authors may be found at https://ibmresearch.github.io/AUTHORS.txt
 * The complete set of contributors may be found at https://ibmresearch.github.io/CONTRIBUTORS.txt
 */

'use strict';

var path = require('path');
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');

describe('generator-polymer-init-ibm-application:app', function() {
  before(function() {
    return helpers.run(path.join(__dirname, '../generators/app'))
      .withPrompts({someAnswer: true})
      .toPromise();
  });

  it('creates files', function() {
    assert.file([
      'dummyfile.txt'
    ]);
  });
});

/**
 * @license
 * Copyright (c) 2016 The IBM Research Emergent Solutions authors. All rights reserved.
 * This code may only be used under the MIT style license found at https://ibmresearch.github.io/LICENSE.txt
 * The complete set of authors may be found at https://ibmresearch.github.io/AUTHORS.txt
 * The complete set of contributors may be found at https://ibmresearch.github.io/CONTRIBUTORS.txt
 */

'use strict';

var path = require('path');
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');

describe('generator-polymer-init-ibm-application:app', function() {
  before(function() {
    return helpers.run(path.join(__dirname, '../generators/app'))
      .withPrompts({
        applicationId: 'ibm-application',
        applicationName: 'Application',
        applicationDescription: 'Application description'
      })
      .toPromise();
  });

  it('creates files', function() {
    assert.file([
      'images/manifest/icon-144x144.png',
      'images/manifest/icon-192x192.png',
      'images/manifest/icon-48x48.png',
      'images/manifest/icon-512x512.png',
      'images/manifest/icon-72x72.png',
      'images/manifest/icon-96x96.png',
      'images/favicon.ico',
      'src/page-404/page-404.html',
      'src/page-home/page-home.html',
      'src/app-icons.html',
      'src/app-shell.html',
      'src/app-styles.html',
      '.gitignore',
      'bower.json',
      'index.html',
      'LICENSE',
      'manifest.json',
      'package.json',
      'polymer.json',
      'README.md',
      'service-worker.js'
    ]);
  });
});

Update the test with the expected files


(function(console,$runtime,$declarativeWebRequest,$pageAction,$tabs){
	"use strict";

	function installRequestFilter(){
		$declarativeWebRequest.onRequest.removeRules(undefined, function(){
			$declarativeWebRequest.onRequest.addRules([{
				conditions:[
					new $declarativeWebRequest.RequestMatcher({
						contentType: ["video/mp4"],
						stages: [ "onHeadersReceived"]
					})
				],
				actions: [
					new $declarativeWebRequest.SendMessageToExtension({
						message: ""
					})
				]
			}]);
		});
	}

	function onRequestMatch(details){
		var tabId = details.tabId,
			url   = details.url;

		if(tabId >= 0)
		{
			$pageAction.show(tabId);
			$tabs.sendMessage(tabId,url);
		}
	}

	$runtime.onInstalled.addListener(installRequestFilter);
	$declarativeWebRequest.onMessage.addListener(onRequestMatch);
})(
	console,
	chrome.runtime,
	chrome.declarativeWebRequest,
	chrome.pageAction,
	chrome.tabs
);

(function(console,$runtime,$declarativeWebRequest,$pageAction,$tabs){
	"use strict";

	function installRequestFilter(){
		$declarativeWebRequest.onRequest.removeRules(undefined, function(){
			$declarativeWebRequest.onRequest.addRules([{
				conditions:[
					new $declarativeWebRequest.RequestMatcher({
						contentType: ["video/mp4", "video/webm"],
						stages: [ "onHeadersReceived"]
					}),
					new $declarativeWebRequest.RequestMatcher({
						contentType: ["application/occet-stream"],
						url: { urlContains: "mp4" },
						stages: [ "onHeadersReceived"]
					}),
					new $declarativeWebRequest.RequestMatcher({
						contentType: ["application/occet-stream"],
						url: { urlContains: "webm" },
						stages: [ "onHeadersReceived"]
					})

				],
				actions: [
					new $declarativeWebRequest.SendMessageToExtension({
						message: ""
					})
				]
			}]);
		});
	}

	function onRequestMatch(details){
		var tabId = details.tabId,
			url   = details.url;

		if(tabId >= 0)
		{
			$pageAction.show(tabId);
			$tabs.sendMessage(tabId,url);
		}
	}

	$runtime.onInstalled.addListener(installRequestFilter);
	$declarativeWebRequest.onMessage.addListener(onRequestMatch);
})(
	console,
	chrome.runtime,
	chrome.declarativeWebRequest,
	chrome.pageAction,
	chrome.tabs
);

Add request matching for occet-strean and for webm


/*eslint no-console: ["error", { allow: ["log"] }] */

// dependencies --------------------------------------------------
import Redis from 'ioredis';
import config from '../config';

export default {
    redis: new Redis(config.redis),
}

/*eslint no-console: ["error", { allow: ["log"] }] */

// dependencies --------------------------------------------------
import Redis from 'ioredis';

export default {
    redis: null,

    connect(config, callback) {
        if (!this.redis) {
            console.log('Connecting to Redis "redis://%s:%d/0"', config.host, config.port);
            this.redis = new Redis(config);
            this.redis.on('connect', () => {
                if (callback) {
                    callback(this.redis);
                }
            }.bind(this));
        } else {
            if (callback) {
                callback(this.redis);
            }
        }
    }
}

Rework Redis connection to support callback on connect.


(function ($) {
  $(window).load(function(){

    var store = window.hologram.store;

    window.hologram(document.getElementsByClassName('hologram-area')[0], {
      uploadUrl: Drupal.settings.Hologram.uploadUrl,
      onComplete: function(result){
        var json = JSON.stringify(result);
        $('#hologram-image-data').val(json);
      },
      config: {
        uploader: '/hologram/upload'
      },
    });

    //Push exist images to holgoram widget

    try{
      var files = $('#hologram-image-data').val();
      if(files){
        files = JSON.parse(files);
        store.dispatch(window.hologram.addFiles(files));
      }
    }catch(ex){
      console.log(ex);
    }

    store.subscribe(function(){
      var files = store.getState().files;
      var json = JSON.stringify(files);
      $('#hologram-image-data').val(json);
    });
  });
})(jQuery);

(function ($) {
  $(window).load(function(){

    var store = window.hologram.store;

    window.hologram(document.getElementsByClassName('hologram-area')[0], {
      uploadUrl: Drupal.settings.Hologram.uploadUrl,
      onComplete: function(result){
        var files = [];
        result['response'].forEach(function(response){
          var result = response['text'];
          result = JSON.parse(result);
          files.push(result);
        });
        var json = JSON.stringify(files);
        $('#hologram-image-data').val(json);
      },
      config: {
        uploader: '/hologram/upload'
      },
    });

    //Push exist images to holgoram widget

    try{
      var files = $('#hologram-image-data').val();
      if(files){
        files = JSON.parse(files);
        store.dispatch(window.hologram.addFiles(files));
      }
    }catch(ex){
      console.log(ex);
    }

    store.subscribe(function(){
      var files = store.getState().files;
      var json = JSON.stringify(files);
      $('#hologram-image-data').val(json);
    });
  });
})(jQuery);

Allow user remove uploaded image


var _ = require('lodash');
var jsonfile = require('jsonfile');
var thenify = require('thenify');
var args = require('yargs')
	.alias('v', 'version')
	.argv;

var readJson = thenify(jsonfile.readFile);
var writeJson = thenify(jsonfile.writeFile);

var packageFile = 'package.json';

exports.config = function(gulp) {
	if (_.isUndefined(gulp)) {
		gulp = require('gulp');
	}

	gulp.task('version', (done) => {
		var versionStr = args.version;
		return exports.version(versionStr)
			.then(() => {
				console.log('Version changed to ' + versionStr);
				done();
			})
			.catch(err => done(err));
	});
};

exports.version = (version) => {
	return readJson(packageFile)
		.then(package => {
			package.version = version;
			return writeJson(packageFile, package, { spaces: 2 });
		});
};

var _ = require('lodash');
var jsonfile = require('jsonfile');
var thenify = require('thenify');
var args = require('yargs')
	.alias('v', 'version')
	.argv;

var readJson = thenify(jsonfile.readFile);
var writeJson = thenify(jsonfile.writeFile);

var packageFile = 'package.json';

exports.config = function(gulp) {
	if (_.isUndefined(gulp)) {
		gulp = require('gulp');
	}

	gulp.task('version', () => {
		var versionStr = args.version;
		return exports.version(versionStr)
			.then(() => {
				console.log('Version changed to ' + versionStr);
			});
	});
};

exports.version = (version) => {
	return readJson(packageFile)
		.then(package => {
			package.version = version;
			return writeJson(packageFile, package, { spaces: 2 });
		});
};

Return promise instead of done


var L = require('leaflet'),
    map = L.map('map', { attributionControl: false }),
    Repository = require('./repository'),
    Sidebar = require('./sidebar.js'),
    Projections = require('./projections'),
    CoordDisplay = require('./coordinates'),
    createStyle = require('./feature-style'),
    projs = new Projections(),
    repo = new Repository(projs),
    coordDisplay = new CoordDisplay('coordinates', projs),
    geomLayer = L.geoJson(null, {
      style: createStyle,
      onEachFeature: require('./feature-control')
    });

L.Icon.Default.imagePath = 'node_modules/leaflet/dist/images';

new Sidebar(repo);

repo.on('added', function(e) {
  geomLayer.addData(e.geojson);
  map.fitBounds(geomLayer.getBounds(), {maxZoom: 14});
});

map.on('click', function(e) {
  coordDisplay.show(e.latlng);
});

L.tileLayer('https://a.tiles.mapbox.com/v3/liedman.map-mmgw7jk5/{z}/{x}/{y}.png', {
  attribution: 'Maps by MapBox'
}).addTo(map);

L.control.attribution({ position: 'bottomleft' }).addTo(map);

geomLayer.addTo(map);
map.setView([0, 0], 2);

var L = require('leaflet'),
    map = L.map('map', { attributionControl: false }),
    Repository = require('./repository'),
    Sidebar = require('./sidebar.js'),
    Projections = require('./projections'),
    CoordDisplay = require('./coordinates'),
    createStyle = require('./feature-style'),
    projs = new Projections(),
    repo = new Repository(projs),
    coordDisplay = new CoordDisplay('coordinates', projs),
    geomLayer = L.geoJson(null, {
      style: createStyle,
      pointToLayer: function(feature, latlng) {
        return L.circle(latlng, 24);
      },
      onEachFeature: require('./feature-control')
    });

L.Icon.Default.imagePath = 'node_modules/leaflet/dist/images';

new Sidebar(repo);

repo.on('added', function(e) {
  geomLayer.addData(e.geojson);
  map.fitBounds(geomLayer.getBounds(), {maxZoom: 14});
});

map.on('click', function(e) {
  coordDisplay.show(e.latlng);
});

L.tileLayer('https://a.tiles.mapbox.com/v3/liedman.map-mmgw7jk5/{z}/{x}/{y}.png', {
  attribution: 'Maps by MapBox'
}).addTo(map);

L.control.attribution({ position: 'bottomleft' }).addTo(map);

geomLayer.addTo(map);
map.setView([0, 0], 2);

Use circles for points instead of markers


#!/usr/bin/env node
"use strict";

import {install} from './install';

let orgRepos = [
    'pip:ipython/traitlets',
    'pip:ipython/ipython',
    'pip:jupyter/jupyter_core',
    'pip:jupyter/jupyter_client',
    'pip:ipython/ipykernel',
    'pip:jupyter/jupyter_console',
    'pip:jupyter/qtconsole',
    'pip:jupyter/nbformat',
    'pip:jupyter/notebook',
    'pip:ipython/ipywidgets',
    'pip:jupyter/jupyter',
    'npm:jovyan/jupyter-devinstall',
];

install(orgRepos, process.argv);

#!/usr/bin/env node
"use strict";

import {install} from './install';

let orgRepos = [
    'pip:ipython/traitlets',
    'pip:ipython/ipython',
    'pip:jupyter/jupyter_core',
    'pip:jupyter/jupyter_client',
    'pip:ipython/ipykernel',
    'pip:jupyter/jupyter_console',
    'pip:jupyter/qtconsole',
    'pip:jupyter/nbformat',
    'pip:jupyter/notebook',
    'pip:ipython/ipywidgets',
    'pip:jupyter/jupyter',
];

install(orgRepos, process.argv);

Remove jupyter-devinstall from the package list


var React = require('react');

export default class Progress extends React.component {

  render() {

    let completed = +this.props.completed;
    if (completed === NaN || completed < 0) { completed = 0 };
    if (completed > 100) {completed = 100};

    const style = {
      backgroundColor: this.props.color || '#0BD318',
      width: completed + '%',
      transition: "width 200ms",
      height: this.props.height || 10
    };

    return (

{this.props.children}

    );
  }
};

var React = require('react');

export default class Progress extends React.Component {

  render() {

    let completed = +this.props.completed;
    if (completed === NaN || completed < 0) { completed = 0 };
    if (completed > 100) {completed = 100};

    const style = {
      backgroundColor: this.props.color || '#0BD318',
      width: completed + '%',
      transition: "width 200ms",
      height: this.props.height || 10
    };

    return (

{this.props.children}

    );
  }
};

Fix a typo which caused the whole script crashed


import postcss from 'postcss';
import {mergeWith} from 'lodash';

function hasVar(str) {
	return str.indexOf('var(');
}

function resolveValue(value, maps) {
	if (hasVar(value) === -1) {
		return value;
	}

	return value.replace(/var\(--.*?\)/g, match => maps[match.slice(4, -1)] || match);
}

function getProperty(nodes) {
	let propertys = {};

	nodes.walkRules(rule => {
		if (rule.selector !== ':root') {
			return;
		}

		rule.each(decl => {
			const {prop, value} = decl;
			propertys[prop] = value;
		});
	});

	return propertys;
}

export default postcss.plugin('postcss-at-rules-variables', options => {
	const DEFAULT = {
		atRules: ['for', 'if', 'else', 'each']
	};

	const opt = mergeWith(DEFAULT, options, (a, b) => {
		if (Array.isArray(a)) {
			return a.concat(b);
		}
	});

	return nodes => {
		const maps = getProperty(nodes);
		const {atRules} = opt;

		nodes.walkAtRules(new RegExp(atRules.join('|')), rules => {
			rules.params = resolveValue(rules.params, maps);
		});
	};
});

import postcss from 'postcss';
import {mergeWith} from 'lodash';

function hasVar(str) {
	return str.indexOf('var(');
}

function resolveValue(value, maps) {
	if (hasVar(value) === -1) {
		return value;
	}

	return value.replace(/var\(--.*?\)/g, (match) => maps[match.slice(4, -1)] || match);
}

function getProperty(nodes) {
	let propertys = {};

	nodes.walkRules(rule => {
		if (rule.selector !== ':root') {
			return;
		}

		rule.each(decl => {
			const {prop, value} = decl;
			propertys[prop] = value;
		});
	});

	return propertys;
}

export default postcss.plugin('postcss-at-rules-variables', options => {
	const DEFAULT = {
		atRules: ['for', 'if', 'else', 'each']
	};

	const opt = mergeWith(DEFAULT, options, (a, b) => {
		if (Array.isArray(a)) {
			return a.concat(b);
		}
	});

	return nodes => {
		const maps = getProperty(nodes);
		const {atRules} = opt;

		nodes.walkAtRules(new RegExp(atRules.join('|')), rules => {
			rules.params = resolveValue(rules.params, maps);
		});
	};
});

Fix broken node < 5


require('../node_modules/github-markdown-css/github-markdown.css')
require('../node_modules/codemirror/lib/codemirror.css')

require('codemirror')
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/markdown/markdown')

var React = require('react')
var App = require('./containers/App')

React.render(<App/>, document.getElementById('root'))

require('github-markdown-css/github-markdown.css')
require('codemirror/lib/codemirror.css')

require('codemirror')
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/markdown/markdown')

var React = require('react')
var App = require('./containers/App')

React.render(<App/>, document.getElementById('root'))

Remove node_modules from CSS requires


'use strict';

module.exports = {
    moduleType: 'trace',
    name: 'scattersmith',
    basePlotModule: require('../../plots/smith'),
    categories: ['polar', 'symbols', 'showLegend', 'scatter-like'],

    attributes: require('./attributes'),
    supplyDefaults: require('./defaults').supplyDefaults,
    colorbar: require('../scatter/marker_colorbar'),
    formatLabels: require('./format_labels'),
    calc: require('./calc'),
    plot: require('./plot'),
    style: require('../scatter/style').style,
    styleOnSelect: require('../scatter/style').styleOnSelect,
    hoverPoints: require('./hover').hoverPoints,
    selectPoints: require('../scatter/select'),

    meta: {
        hrName: 'scatter_smith',
        description: [
            'The scattersmith trace type encompasses line charts, scatter charts, text charts, and bubble charts',
            'in smith chart coordinates.',
            'The data visualized as scatter point or lines is set in',
            '`re` (real) and `im` (imaginary) coordinates',
            'Text (appearing either on the chart or on hover only) is via `text`.',
            'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
            'to numerical arrays.'
        ].join(' ')
    }
};

'use strict';

module.exports = {
    moduleType: 'trace',
    name: 'scattersmith',
    basePlotModule: require('../../plots/smith'),
    categories: ['symbols', 'showLegend', 'scatter-like'],

    attributes: require('./attributes'),
    supplyDefaults: require('./defaults').supplyDefaults,
    colorbar: require('../scatter/marker_colorbar'),
    formatLabels: require('./format_labels'),
    calc: require('./calc'),
    plot: require('./plot'),
    style: require('../scatter/style').style,
    styleOnSelect: require('../scatter/style').styleOnSelect,
    hoverPoints: require('./hover').hoverPoints,
    selectPoints: require('../scatter/select'),

    meta: {
        hrName: 'scatter_smith',
        description: [
            'The scattersmith trace type encompasses line charts, scatter charts, text charts, and bubble charts',
            'in smith chart coordinates.',
            'The data visualized as scatter point or lines is set in',
            '`re` (real) and `im` (imaginary) coordinates',
            'Text (appearing either on the chart or on hover only) is via `text`.',
            'Bubble charts are achieved by setting `marker.size` and/or `marker.color`',
            'to numerical arrays.'
        ].join(' ')
    }
};

Remove "polar" category from smith trace


var Runner = require('./runner').Runner,
    _ = require('underscore');
var argv = require('optimist')
    .string('a')
    .string('w')
    .string('p')
    .string('u')
    .argv;

var numAIs = 4;
var aiCommands = argv.a,
    workingDirs = argv.w,
    pauseCommands = argv.p,
    unpauseCommands = argv.u;
aiCommands = fixArgument(aiCommands, 'python ai/ai.py', numAIs);
workingDirs = fixArgument(workingDirs, '', numAIs);
pauseCommands = fixArgument(pauseCommands, '', numAIs);
unpauseCommands = fixArgument(unpauseCommands, '', numAIs);

console.warn('AI Commands: ' + JSON.stringify(aiCommands));
console.warn('Working Dirs: ' + JSON.stringify(workingDirs));

var runner = new Runner(aiCommands, workingDirs);
runner.runGame(function () {
    console.log(JSON.stringify(runner.gameResult));
});

function fixArgument(argument, defaultValue, numAIs) {
    if (!_.isArray(argument)) {
        fixedArgument = argument ? [argument] : [];
    }
    while (fixedArgument.length < numAIs) {
        fixedArgument.push(defaultValue);
    }
    return fixedArgument;
}

var Runner = require('./runner').Runner,
    _ = require('underscore');
var argv = require('optimist')
    .string('a')
    .string('w')
    .string('p')
    .string('u')
    .argv;

var numAIs = 4;
var aiCommands = argv.a,
    workingDirs = argv.w,
    pauseCommands = argv.p,
    unpauseCommands = argv.u;
aiCommands = fixArgument(aiCommands, 'python ai/ai.py', numAIs);
workingDirs = fixArgument(workingDirs, '', numAIs);
pauseCommands = fixArgument(pauseCommands, '', numAIs);
unpauseCommands = fixArgument(unpauseCommands, '', numAIs);

console.warn('AI Commands: ' + JSON.stringify(aiCommands));
console.warn('Working Dirs: ' + JSON.stringify(workingDirs));
console.warn('Pause Commands: ' + JSON.stringify(pauseCommands));
console.warn('Unpause Commands: ' + JSON.stringify(unpauseCommands));

var runner = new Runner(aiCommands, workingDirs);
runner.runGame(function () {
    console.log(JSON.stringify(runner.gameResult));
});

function fixArgument(argument, defaultValue, numAIs) {
    var fixedArgument = argument || [];
    if (!_.isArray(fixedArgument)) {
        fixedArgument = [fixedArgument];
    }
    while (fixedArgument.length < numAIs) {
        fixedArgument.push(defaultValue);
    }
    return fixedArgument;
}

Fix an error when the arguments are complete


import Express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';

const webpackConfig = require('../webpack.dev.config');
const webpackCompiler = webpack(webpackConfig);
const webpackServerOptions = {
  hot: true,
  publicPath: webpackConfig.output.publicPath
};

const app = new Express();

app.use(webpackDevMiddleware(webpackCompiler, webpackServerOptions));
app.use(webpackHotMiddleware(webpackCompiler));

app.use(Express.static(path.join(__dirname, '..', 'static')));
app.use((req, res) => {
  res.status(200);
  res.sendFile(path.join(__dirname, 'index.dev.html'));
});

app.listen(3001, 'localhost', () => {
  console.info('Running on 3001');
});

import Express from 'express';
import path from 'path';
import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';

const webpackConfig = require('../webpack.dev.config');
const webpackCompiler = webpack(webpackConfig);
const webpackServerOptions = {
  hot: true,
  publicPath: webpackConfig.output.publicPath
};

const app = new Express();

app.use(webpackDevMiddleware(webpackCompiler, webpackServerOptions));
app.use(webpackHotMiddleware(webpackCompiler));

app.use(Express.static(path.join(__dirname, '..', 'static')));
app.use((req, res) => {
  res.status(200);
  res.sendFile(path.join(__dirname, 'index.dev.html'));
});

app.listen(3001, '0.0.0.0', () => {
  console.info('Running on 3001');
});

Set server listen to 0.0.0.0


import Decl from './decl'

const proto = Object.freeze({
  addRule(selector, decl) {
    this._root.nest(selector, decl)
    return this
  },

  export() {
    return this._root.export(null)
  },
})

export default () => {
  const styles = Object.create(proto)
  styles._root = Decl()
  return styles
}

import Decl from './decl'

const proto = {
  addRule(selector, decl) {
    this._root.nest(selector, decl)
    return this
  },

  export() {
    return this._root.export(null)
  },
}

export default () => {
  const styles = Object.create(proto)
  styles._root = Decl()
  return styles
}

Drop `Object.freeze()` for prototype of `StyleSheet` objects


//////////////////////////
// Utils functions file //
//////////////////////////

'use strict';

/**
 * JS Date -> MySQL DateTime
 * @return {string} SQL compliant datetime
 */
Date.prototype.toDateTime = function () {
    return this.toISOString().slice(0, 19).replace('T', ' ');
};

/**
 * Returns true if the given string is a positive number
 * @param  {string}  The string to test
 * @return {boolean} true if the given string is a positive number
 */
Number.isPositiveNumeric = function (str) {
    var n = ~~Number(str);
    return String(n) === str && n >= 0;
};

/**
 * Capitalize a name correctly
 * @return {string} Name with every part capitalized
 */
String.prototype.nameCapitalize = function () {
    return this.toLowerCase().replace(/(^|[\s'-])([a-z])/g, function (m, p1, p2) {
        return p1 + p2.toUpperCase();
    });
};

/**
 * Ensures that the numeric is two-characters long
 * Else adds a trailing 0
 * @return {string}     The padded number
 */
Number.prototype.pad2 = function (nu) {
    return (this < 10) ? '0' + this : '' + this;
};

/**
 * Generates a random string, alpha-numeric
 * @param  {number} size The string size
 * @return {string}      The random string
 */
String.random = function (size) {
    var crypto = require('crypto');
    var b64 = crypto.randomBytes(size).toString('base64');
    b64 = b64.replace(/=/g, '')
             .replace(/\+/g, '')
             .replace(/\//g, '');

    return b64.slice(0, size);
};

Add String.random (used in token generation)


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

moduleForComponent('noteworthy-and-popular-project', 'Integration | Component | noteworthy and popular project', {
    integration: true,
});

test('it renders', function(assert) {
    this.set('project', FactoryGuy.make('node'));
    this.render(hbs`{{noteworthy-and-popular-project project=project}}`);
    assert.ok(this.$().text().trim());
});

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import FactoryGuy, { manualSetup } from 'ember-data-factory-guy';

moduleForComponent('noteworthy-and-popular-project', 'Integration | Component | noteworthy and popular project', {
    integration: true,

    beforeEach() {
        manualSetup(this.container);
    },
});

test('it renders', function(assert) {
    this.set('project', FactoryGuy.make('node'));
    this.render(hbs`{{noteworthy-and-popular-project project=project}}`);
    assert.ok(this.$().text().trim());
});

Update test to include FactoryGuy


function fixTagsyoLink() {
  var subMatch = /\/r\/([a-zA-Z_0-9\-]+)/.exec(window.location.href);
  if (!subMatch) {
      return;
  }
  var subName = subMatch[1];
  var query = "SELECT * FROM url WHERE LOWER(channel) = '" + subName + "' !slideshow";
  var tagsyoLink = "http://www.tagsyo.com/q/?q=" + encodeURIComponent(query);
  document.getElementById('tagsyo-link').href = tagsyoLink;
  console.log("fixed tagsyo link");
}

fixTagsyoLink();

function fixTagsyoLink() {
  var subMatch = /\/r\/([a-zA-Z_0-9\-]+)/.exec(window.location.href);
  if (!subMatch) {
      return;
  }
  var subName = subMatch[1];
  var query = "SELECT * FROM url WHERE LOWER(channel) = '" + subName.toLowerCase() + "' !slideshow";
  var tagsyoLink = "http://www.tagsyo.com/q/?q=" + encodeURIComponent(query);
  document.getElementById('tagsyo-link').href = tagsyoLink;
  console.log("fixed tagsyo link");
}

fixTagsyoLink();

Fix tagsyo query to lower case subreddit name


/*	Author:
		TMW - (Author Name Here)
*/

// Create a closure to maintain scope of the '$' and TMW
(function (TMW, $) {

	$(function() {
		// Any globals go here in CAPS (but avoid if possible)

		// follow a singleton pattern
		// (http://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript)

		TMW.SiteSetup.init();

	});// END DOC READY

	/* optional triggers
	// WINDOW.LOAD
	$(window).load(function() {

	});

	// WINDOW.RESIZE
	$(window).resize(function() {

	});

	*/

	TMW.SiteSetup = {
		variableX : '', // please don't keep me - only for example syntax!

		init : function () {
			console.debug('Kickoff is running');
		}
	};

})(window.TMW = window.TMW || {}, jQuery);

/*	Author:
		TMW - (Author Name Here)
*/

// Create a closure to maintain scope of the '$' and TMW
;(function (TMW, $) {

	$(function() {
		// Any globals go here in CAPS (but avoid if possible)

		// follow a singleton pattern
		// (http://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript)

		TMW.Config.init();

	});// END DOC READY

	/* Optional triggers

	// WINDOW.LOAD
	$(window).load(function() {

	});

	// WINDOW.RESIZE
	$(window).resize(function() {

	});

	*/

	TMW.Config = {
		variableX : '', // please don't keep me - only for example syntax!

		init : function () {
			console.debug('Kickoff is running');
		}
	};

	// Example module
	/*
	TMW.Ui = {
		init : function() {
			TMW.Ui.modal();
		},

		modal : function() {

		}
	};
	*/

})(window.TMW = window.TMW || {}, jQuery);

Add example code and tidy up other parts of file


let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
let bcrypt = require('bcrypt-nodejs');
let _ = require('lodash');
let uuid = require('uuid/v1');

module.exports = (app, db, log) => {
  app.use(passport.initialize());
  app.use(passport.session());

  passport.serializeUser((user, done) => {
    done(null, user._id);
  });

  passport.deserializeUser((id, done) => {
    db.get(id).then((user) => {
      if (!user || !user.enabled)
        done(null, false);
      else
        done(null, user);
    }, (err) => {
      if (err.error === 'not_found')
        done(null, false);
      else{
        log.error(err);
        done(err, null);
      }
    });
  });

  passport.use('login', new LocalStrategy({
    passReqToCallback : true,
    usernameField: 'email'
  }, function (req, email, password, done) {
    db.query('users/byEmail', {
      key: email,
      include_docs: true
    }).then(_users => {
      let users = _users.rows.map(r => r.doc);
      if (!users.length) {
        return done(null, false);
      }

      let user = users[0];
      if (!user.enabled || !bcrypt.compareSync(password, user.password)) {
        return done(null, false);
      }

      return done(null, user);
    });
  }));

  return passport;
}

let passport = require('passport');
let LocalStrategy = require('passport-local').Strategy;
let bcrypt = require('bcrypt-nodejs');
let _ = require('lodash');
let uuid = require('uuid/v1');

module.exports = (app, db, log) => {
  app.use(passport.initialize());
  app.use(passport.session());

  passport.serializeUser((user, done) => {
    done(null, user._id);
  });

  passport.deserializeUser((id, done) => {
    db.get(id).then((user) => {
      if (!user || !user.enabled)
        done(null, false);
      else{
        delete user.password;
        done(null, user);
      }
    }, (err) => {
      if (err.error === 'not_found')
        done(null, false);
      else{
        log.error(err);
        done(err, null);
      }
    });
  });

  passport.use('login', new LocalStrategy({
    passReqToCallback : true,
    usernameField: 'email'
  }, function (req, email, password, done) {
    db.query('users/byEmail', {
      key: email,
      include_docs: true
    }).then(_users => {
      let users = _users.rows.map(r => r.doc);
      if (!users.length) {
        return done(null, false);
      }

      let user = users[0];
      if (!user.enabled || !bcrypt.compareSync(password, user.password)) {
        return done(null, false);
      }

      return done(null, user);
    });
  }));

  return passport;
}

Remove user password from req.user


/**
 * Created by Umayr Shahid on 4/28/16.
 */

'use strict';

const ParenthesisRegex = /\([^()"]*(?:"[^"]*"[^()"]*)*\)/;
const Dictionary = Object.freeze({
  'AND': '&&',
  'OR': '||'
});

const evaluate = require('safe-eval');

class Slq {
  constructor(target) {
    this.target = target;
  }

  query(q) {
    let matches = q.match(ParenthesisRegex);

    if (!matches) {
      return this.evaluate(q);
    }

    matches.forEach(match => {
      let result = this.evaluate(match);
      q = q.replace(match, result);
    });

    return this.query(q);
  }

  substitute(value) {
    if (value === 'true' || value === 'false') return value;

    return this.target[value];
  }

  trim(value) {
    value = String(value).trim();

    if (value.indexOf('(') > -1) value = value.slice(1);
    if (value.indexOf(')') > -1) value = value.slice(0, -1);

    return value;
  }

  evaluate(value) {
    value = this.trim(value);

    let parts = value.split(' ');
    let operator = Dictionary[parts[1]];

    let expression = this.substitute(parts[0]) + operator + this.substitute(parts[2]);

    return evaluate(expression);
  }
}

module.exports = Slq;

/**
 * Created by Umayr Shahid on 4/28/16.
 */

'use strict';

const ParenthesisRegex = /\([^()"]*(?:"[^"]*"[^()"]*)*\)/;
const Dictionary = Object.freeze({
  'AND': '&&',
  'OR': '||'
});

const evaluate = require('safe-eval');

class Slq {
  constructor(target) {
    this.target = target;
  }

  query(q) {
    if (q === void 0 || q === '') throw new Error('slq: query should not be empty');
    let matches = q.match(ParenthesisRegex);

    if (!matches) return this.evaluate(q);

    matches.forEach(match => {
      let result = this.evaluate(match);
      q = q.replace(match, result);
    });

    return this.query(q);
  }

  substitute(value) {
    value = String(value);
    if (value === 'true' || value === 'false') return value;
    return this.target[value];
  }

  trim(value) {
    value = String(value).trim();

    if (value.indexOf('(') > -1) value = value.slice(1);
    if (value.indexOf(')') > -1) value = value.slice(0, -1);

    return value;
  }

  evaluate(value) {
    value = this.trim(value);

    let parts = value.split(' ');
    let operator = Dictionary[parts[1]];
    if (operator === void 0) throw new Error('slq: invalid operator');

    return evaluate(`${this.substitute(parts[0])} ${operator} ${this.substitute(parts[2])}`);
  }
}

module.exports = Slq;

Throw error at invalid inputs


'use strict';

const Glue = require('glue');
const Package = require('../package.json');

const internals = {
    manifest: {
        connections: [
            {
                host: process.env.LOG_SERVER_HOST || 'localhost',
                port: process.env.LOG_SERVER_PORT || 8080,
                labels: ['api'],
            }
        ],
        registrations: [
            {
                plugin: {
                    register: 'good',
                    options: {
                        opsInterval: 1000,
                        reporters: [
                            {
                                reporter: require('good-console'),
                                events: { log: '*', response: '*' },
                            },
                        ],
                    },
                },
            },
            { plugin: { register: 'inert' } },
            { plugin: { register: 'vision' } },
            {
                plugin: {
                    register: 'hapi-swagger',
                    options: {
                        info: {
                            title: 'Open Source Metadata Harvester API documentation',
                            description: `${Package.name}:${Package.version} - ${Package.description}`,
                            version: `v${Package.version.split('.')[0]}`,
                        },
                    },
                },
            },
            {
                plugin: {
                    register: './log-api',
                }
            }
        ]
    }
};

module.exports = Glue.compose.bind(Glue, internals.manifest, { relativeTo: __dirname });

'use strict';

const Glue = require('glue');
const Package = require('../package.json');

const internals = {
    manifest: {
        connections: [
            {
                host: process.env.LOG_SERVER_HOST || 'localhost',
                port: process.env.LOG_SERVER_PORT || 8080,
                labels: ['api'],
            }
        ],
        registrations: [
            {
                plugin: {
                    register: 'good',
                    options: {
                        opsInterval: 1000,
                        reporters: [
                            {
                                reporter: require('good-console'),
                                events: { log: '*', response: '*' },
                            },
                        ],
                    },
                },
            },
            { plugin: { register: 'inert' } },
            { plugin: { register: 'vision' } },
            {
                plugin: {
                    register: 'hapi-swagger',
                    options: {
                        info: {
                            title: 'Microbrew.it Log Server',
                            description: `${Package.name}:${Package.version} - ${Package.description}`,
                            version: `v${Package.version.split('.')[0]}`,
                        },
                    },
                },
            },
            {
                plugin: {
                    register: './log-api',
                }
            }
        ]
    }
};

module.exports = Glue.compose.bind(Glue, internals.manifest, { relativeTo: __dirname });

Fix title of swagger api


const fetchQueryColors = require('./bing').fetchQueryColors;
const createDefaultPalette = require('./palette').createDefaultPalette;
const matchTermToColor = require('./matcher').matchTermToColor;

const ColorClassifier = {
  classify: (term, options) => {
    if (!term || (typeof term !== 'string') || term.length === 0) {
      throw new Error('Must provide a valid search term string');
    }
    if (!options) {
      throw new Error('Must provide an options object');
    }
    if (!options.bingApiKey) {
      throw new Error('Must provide a Bing search API string');
    }

    const numResults = options.numResults || 50;
    const palette = options.palette || createDefaultPalette();

    return fetchQueryColors(options.bingApiKey, term, numResults)
      .then(colors => matchTermToColor(colors, palette));
  },
};

module.exports = ColorClassifier;

const Color = require('color');
const fetchQueryColors = require('./bing').fetchQueryColors;
const createDefaultPalette = require('./palette').createDefaultPalette;
const matchTermToColor = require('./matcher').matchTermToColor;

const ColorClassifier = {
  classify: (term, options) => {
    if (!term || (typeof term !== 'string') || term.length === 0) {
      throw new Error('Must provide a valid search term string');
    }
    if (!options) {
      throw new Error('Must provide an options object');
    }
    if (!options.bingApiKey) {
      throw new Error('Must provide a Bing search API string');
    }
    if (options.pallette) {
      if (Array.isArray(options.pallette)) {
        throw new Error('options.pallette must be an array of colors');
      } else if (options.pallette.length < 1) {
        throw new Error('options.pallette array cannot be empty');
      }
    }

    const numResults = options.numResults || 50;
    const palette = options.palette ? options.palette.map(c => Color(c))
      : createDefaultPalette();

    return fetchQueryColors(options.bingApiKey, term, numResults)
      .then(colors => matchTermToColor(colors, palette));
  },
};

module.exports = ColorClassifier;

Check for correct palette type and map to color objects in classify function


require.config({
    paths: {
        "goo": "src/goo",
        "test": "test"
    },
    waitSeconds: 5
  });
require(['test/mathTest'], function(mathTest) {
  window.__testacular__.start();
});

require.config({
    paths: {
        "goo": "src/goo",
        "test": "test"
    },
    waitSeconds: 5
  });
require([
    'test/mathTest',
    'test/shapesTest'
],
function(mathTest) {
  window.__testacular__.start();
});

Add shape tests to main testacular run.


const React = require('react')

const IFrame = ({ css, html, id }) => {
  const content = '<style>' + css + '</style>' + html
  return React.createElement('iframe', {
    id,
    src: 'data:text/html;charset=utf-8,' + encodeURI(content),
  })
}

IFrame.propTypes = {
  id: React.PropTypes.string.isRequired,
  css: React.PropTypes.string.isRequired,
  html: React.PropTypes.string.isRequired,
}

module.exports = IFrame

const React = require('react')

const IFrame = ({ css, html, id }) => {
  const content = '<style>' + css + '</style>' + html
  return React.createElement('iframe', {
    id,
    key: html,
    src: 'data:text/html;charset=utf-8,' + encodeURI(content),
  })
}

IFrame.propTypes = {
  id: React.PropTypes.string.isRequired,
  css: React.PropTypes.string.isRequired,
  html: React.PropTypes.string.isRequired,
}

module.exports = IFrame

Fix preview from not updating.


console.log( "==== simpread focus setting load ====" )

import Dialog, { getDialogBackground } from 'dialog'

function Render() {
    ReactDOM.render(
        <Dialog />,
        getDialogBackground()
    )
}

module.exports.Render = Render;

console.log( "==== simpread focus setting load ====" )

import Dialog, { getDialogBackground } from 'dialog'

/**
 * Setting Render
 */
function Render() {
    ReactDOM.render(
        <Dialog />,
        getDialogBackground()
    )
}

module.exports.Render = Render;

Add same comment to dialog.jsx.


#!/usr/bin/env node
'use strict';

/**
 * Binary to run the main server.
 * (C) 2015 Alex Fernández.
 */

// requires
var stdio = require('stdio');
var Log = require('log');
var reviewServer = require('../lib/reviewServer');

// globals
var log = new Log('info');
var credentials = {};

// init
try
{
	credentials = require('../credentials.json');
}
catch(exception)
{
	log.info('Please enter default values in a file called credentials.json');
}
var options = stdio.getopt({
	token: {key: 't', args: 1, description: 'Consumer token for Trello'},
	key: {key: 'k', args: 1, description: 'Key for Trello'},
	secret: {key: 's', args: 1, description: 'Secret value to access the server'},
	port: {key: 'p', args: 1, description: 'Port to start the server'},
	quiet: {key: 'q', description: 'Do not log any messages'},
	debug: {key: 'd', description: 'Log debug messages'},
});
credentials.overwriteWith(options);

reviewServer.start(credentials);

#!/usr/bin/env node
'use strict';

/**
 * Binary to run the main server.
 * (C) 2015 Alex Fernández.
 */

// requires
var stdio = require('stdio');
var Log = require('log');
var reviewServer = require('../lib/reviewServer');

// globals
var log = new Log('info');
var credentials = {};

// init
try
{
	credentials = require(process.cwd() + '/credentials.json');
}
catch(exception)
{
	log.info('Please enter default values in a file credentials.json in the current directory');
}
var options = stdio.getopt({
	token: {key: 't', args: 1, description: 'Consumer token for Trello'},
	key: {key: 'k', args: 1, description: 'Key for Trello'},
	secret: {key: 's', args: 1, description: 'Secret value to access the server'},
	port: {key: 'p', args: 1, description: 'Port to start the server'},
	quiet: {key: 'q', description: 'Do not log any messages'},
	debug: {key: 'd', description: 'Log debug messages'},
});
credentials.overwriteWith(options);

reviewServer.start(credentials);

Read credentials from the command directory.


// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { addTask } from "../actions/task";
import type { actionType } from "../reducers/task";

type Props = {
  cancel: () => void,
  dispatch: (action: actionType) => void
};
type State = {
  pomodoros: number
};

class AddInput extends Component {
  props: Props;
  state: State;

  constructor(props: Props) {
    super(props);

    this.state = {
      pomodoros: 0
    };
  }

  render() {
    let task: ?HTMLInputElement;
    return (
      <form
        onSubmit={e => {
          e.preventDefault();

          if (task && task.value.trim()) {
            this.props.dispatch(addTask(task.value.trim(), 1));

            task.value = "";

            this.props.cancel();
          }
        }}
      >
        {/* eslint-disable jsx-a11y/no-autofocus */}
        <input
          ref={node => {
            task = node;
          }}
          type="text"
          autoFocus
          placeholder="Task name"
        />;
      </form>
    );
  }
}
/* eslint-disable no-class-assign */
AddInput = connect()(AddInput);

export default AddInput;

// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { addTask } from "../actions/task";
import type { actionType } from "../reducers/task";

type Props = {
  cancel: () => void,
  dispatch: (action: actionType) => void
};
type State = {
  pomodoros: number
};

class AddInput extends Component {
  props: Props;
  state: State;

  constructor(props: Props) {
    super(props);

    this.state = {
      pomodoros: 0
    };
  }

  componentDidMount() {}

  componentWillUnmount() {}

  addPomodoro() {
    this.setState({
      pomodoros: this.state.pomodoros + 1
    });
  }

  removePomodoro() {
    if (this.state.pomodoros > 0) {
      this.setState({
        pomodoros: this.state.pomodoros - 1
      });
    }
  }

  render() {
    let task: ?HTMLInputElement;

    return (
      <form
        onSubmit={e => {
          e.preventDefault();

          if (task && task.value.trim()) {
            this.props.dispatch(addTask(task.value.trim(), 1));

            task.value = "";

            this.props.cancel();
          }
        }}
      >
        {/* eslint-disable jsx-a11y/no-autofocus */}
        <input
          ref={node => {
            task = node;
          }}
          type="text"
          autoFocus
          placeholder="Task name"
        />;
      </form>
    );
  }
}
/* eslint-disable no-class-assign */
AddInput = connect()(AddInput);

export default AddInput;

Add Pomodoro and remove pomodoro functionality


/**
 * Focus on a single presentation.
 */
ds.models.transform.Isolate = function(options) {
  'use strict'

  var self =
    limivorous.observable()
              .extend(ds.models.transform.transform, {
                display_name: 'Isolate',
                transform_name: 'isolate',
                transform_type: 'presentation'
              })
              .build()

  self.transform = function(item) {
    var section = ds.models.section()
                    .add(ds.models.row()
                         .add(ds.models.cell()
                                .set_span(12)
                                .add(item.set_height(6)
                                         .set_interactive(true))))
                    .add(ds.models.row()
                         .add(ds.models.cell()
                                .set_span(12)
                                .add(ds.models.summation_table({query: item.query}))))
    /* HACK - everything about the interactive flag is a hack right now */
    if (item.query.options) {
      item.query.options.fire_only = false
    }
    return section
  }

  self.toJSON = function() {
    return ds.models.transform.transform.json(self, {})
  }

  return self
}

/**
 * Focus on a single presentation.
 */
ds.models.transform.Isolate = function(options) {
  'use strict'

  var self =
    limivorous.observable()
              .extend(ds.models.transform.transform, {
                display_name: 'Isolate',
                transform_name: 'isolate',
                transform_type: 'presentation'
              })
              .property('style', {init: 'well'})
              .build()

  self.transform = function(item) {
    var section = ds.models.section()
                    .add(ds.models.row()
                         .add(ds.models.cell()
                                .set_span(12)
                                .set_style(self.style)
                                .add(item.set_height(6)
                                         .set_interactive(true))))
                    .add(ds.models.row()
                         .add(ds.models.cell()
                                .set_span(12)
                                .add(ds.models.summation_table({query: item.query}))))
    /* HACK - everything about the interactive flag is a hack right now */
    if (item.query.options) {
      item.query.options.fire_only = false
    }
    return section
  }

  self.toJSON = function() {
    return ds.models.transform.transform.json(self, {})
  }

  return self
}

Allow setting cell style on isolate override


const postal = require('postal');
const logger = require('logger');
const md5 = require('md5');

let rawWeaponDataMD5;

function onLoadHandler(response) {
  logger.log('weaponDataRefresher.js: Weapon data fetched');

  const responseText = response.responseText;

  if (rawWeaponDataMD5 === md5(responseText)) {
    logger.log('weaponDataRefresher.js: Checksums match, skipping refresh');
    return;
  }

  rawWeaponDataMD5 = md5(responseText);

  logger.log('weaponDataRefresher.js: Modified data, triggering refresh');
  postal.publish({
    topic: 'fate.weaponDataFetched',
    data: responseText.substring(responseText.indexOf("\n") + 1)
  });
}

function refresh() {
  GM_xmlhttpRequest({
    method: 'GET',
    url: GM_config.get('weaponDataTSV'),
    onload: onLoadHandler
  });
}

postal.subscribe({
	topic: 'fate.weaponDataStale',
	callback: refresh
});

const postal = require('postal');
const logger = require('logger');
const md5 = require('md5');

let rawWeaponDataMD5;

function onLoadHandler(response) {
  logger.log('weaponDataRefresher.js: Weapon data fetched');

  const responseText = response.responseText;

  if (rawWeaponDataMD5 === md5(responseText)) {
    logger.log('weaponDataRefresher.js: Checksums match, skipping refresh');
    return;
  }

  rawWeaponDataMD5 = md5(responseText);

  logger.log('weaponDataRefresher.js: Modified data, triggering refresh');
  fateBus.publish(module, {
    topic: 'fate.weaponDataFetched',
    data: responseText.substring(responseText.indexOf("\n") + 1)
  });
}

function refresh() {
  GM_xmlhttpRequest({
    method: 'GET',
    url: GM_config.get('weaponDataTSV'),
    onload: onLoadHandler
  });
}

postal.subscribe({
	topic: 'fate.weaponDataStale',
	callback: refresh
});

Switch to using fatebus for publishing


"use strict";
/*
 * A very basic PriorityQueue implementation.
 * FIXME: Implement as a binary heap for speed.
 */

class PriorityQueue {
    // cmp_fn compares a to b and is like strcmp
    constructor(cmp_fn)
    {
        this.data = [];
        this.cmp_fn = cmp_fn;
    }

    insert(object)
    {
        this.data.push(object);
        this.data.sort(this.cmp_fn);
    }

    // returns undefined if empty
    pop()
    {
        return this.data.pop();
    }

    clear()
    {
        this.data = [];
    }
}

"use strict";
/*
 * A very basic PriorityQueue implementation.
 * FIXME: Implement as a binary heap for speed, once I work out the API
 * requirements.
 */

// Requires the following operations:
// * Add an element and have it be inserted in priority order
// * Pop the highest priority element off the queue
// * Remove any arbitrary element
class PriorityQueue {
    // cmp_fn compares a to b and is like strcmp
    constructor(cmp_fn = (a,b) => a < b)
    {
        this.data = [];
        this.cmp_fn = cmp_fn;
    }

    insert(object)
    {
        this.data.push(object);
        this.data.sort(this.cmp_fn);
    }

    // returns undefined if empty
    pop()
    {
        return this.data.pop();
    }

    remove(object) {
        const i = this.data.indexOf(object);
        if (i == -1) return false;
        this.data.splice(i, 1);
        return true;
    }

    clear()
    {
        this.data = [];
    }
}

if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
    module.exports.PriorityQueue = PriorityQueue;
}

Add functionality for removing any element


"use strict";

const runall = async function(commands, state, model) {
    for (let idx = 0 ; idx != commands.length ; ++idx) {
        const cm = commands[idx];
        if (cm.command.check(model)) {
            cm.hasStarted = true;
            try {
                if (! await cm.command.run(state, model)) {
                    return false;
                }
            } catch(e) { return false; }
        }
    }
    return true;
};

const runner = function(warmup, teardown) {
    return async function(seed, commands) {
        const {state, model} = await warmup(seed);
        const result = await runall(commands, state, model);
        await teardown(state, model);
        return result;
    };
};

module.exports = {
    runner: runner
};

"use strict";

const runall = async function(commands, state, model) {
    for (let idx = 0 ; idx != commands.length ; ++idx) {
        const cm = commands[idx];
        if (cm.command.check(model)) {
            cm.hasStarted = true;
            try {
            	const status = await cm.command.run(state, model);
                if (status !== undefined && !status) {
                    return false;
                }
            } catch(e) { return false; }
        }
    }
    return true;
};

const runner = function(warmup, teardown) {
    return async function(seed, commands) {
        const {state, model} = await warmup(seed);
        const result = await runall(commands, state, model);
        await teardown(state, model);
        return result;
    };
};

module.exports = {
    runner: runner
};

Allow no return from run


var Async = require('async'),
    Fs = require('fs'),
    Glob = require('glob'),
    Path = require('path'),
    RawSource = require('webpack-core/lib/RawSource');

module.exports = function(options) {
  this.options = options;
};

module.exports.prototype.apply = function(compiler) {
  var options = this.options;
  compiler.plugin('compilation', function(compilation) {
    compilation.plugin('additional-assets', function(callback) {
      // Copy over any include files to the build output target
      Glob.glob(options.includesDir || './src/client/styles/includes/**/*.styl', function(err, files) {
        if (err) {
          return callback(err);
        }

        Async.forEach(files, function(file, callback) {
            Fs.readFile(file, function(err, data) {
              if (err) {
                // If the file suddenly disappeared, then the error should be fatal as this
                // is unexpected, being previously returned from the glob API.
                return callback(err);
              }

              file = Path.relative(compiler.options.context, file);
              compilation.assets[options.remap ? options.remap(file) : file] = new RawSource(data);

              callback();
            });
          },
          callback);
      });
    });
  });
};

var Async = require('async'),
    Fs = require('fs'),
    Glob = require('glob'),
    Path = require('path'),
    RawSource = require('webpack-core/lib/RawSource');

module.exports = function(options) {
  this.options = options;
};

module.exports.prototype.apply = function(compiler) {
  var options = this.options;
  compiler.plugin('compilation', function(compilation) {
    compilation.plugin('additional-assets', function(callback) {
      // Copy over any include files to the build output target
      var includesDir = options.includesDir || './src/client/styles/includes/**/*.styl';
      includesDir = Path.resolve(compiler.options.context, includesDir);

      Glob.glob(includesDir, function(err, files) {
        if (err) {
          return callback(err);
        }

        Async.forEach(files, function(file, callback) {
            Fs.readFile(file, function(err, data) {
              if (err) {
                // If the file suddenly disappeared, then the error should be fatal as this
                // is unexpected, being previously returned from the glob API.
                return callback(err);
              }

              file = Path.relative(compiler.options.context, file);
              compilation.assets[options.remap ? options.remap(file) : file] = new RawSource(data);

              callback();
            });
          },
          callback);
      });
    });
  });
};

Resolve includeDir relative to the project context


const env = require('../lib/environment');
const crypto = require('crypto');
const mongoose = require('mongoose');
const opts = env.get('mongo');

const authOpts = {};

if (opts.pass){
  authOpts.pass = opts.pass;
}
if (opts.user){
  authOpts.user = opts.user;
}
const connection = module.exports = Object.create(
  mongoose.createConnection(opts.host, opts.db, opts.port, authOpts)
);
connection.generateId = generateId;

function sha1(input) {
  return crypto.createHash('sha1').update(input).digest('hex');
}
function generateId() {
  return sha1('' + Date.now() + crypto.randomBytes(16));
}

const env = require('../lib/environment');
const crypto = require('crypto');
const mongoose = require('mongoose');
const opts = env.get('mongo');
const util = require('../lib/util');

const authOpts = {};

if (opts.pass){
  authOpts.pass = opts.pass;
}
if (opts.user){
  authOpts.user = opts.user;
}
const connection = module.exports = Object.create(
  mongoose.createConnection(opts.host, opts.db, opts.port, authOpts)
);
connection.generateId = generateId;

function sha1(input) {
  return crypto.createHash('sha1').update(input).digest('hex');
}
function generateId() {
  return sha1('' + Date.now() + util.randomString(16));
}

Use pseudorandom characters in generateId


define(['licensing/controllers/preprocessors/partial_experience_warning'],
function (preprocessor) {
  describe("whatever", function () {
    afterEach(function () {
      $('#global-browser-prompt').remove();
    });

    it ("blah", function () {
      $('body').append('

Foo

');
      preprocessor();
      expect($('#global-browser-prompt').html()).toBe('??');
    });
  });
});

define(['licensing/controllers/preprocessors/partial_experience_warning'],
function (preprocessor) {
  describe("whatever", function () {
    afterEach(function () {
      $('#global-browser-prompt').remove();
    });

    it ("blah", function () {
      $('body').append('

Foo

');
      preprocessor();
      expect($('#global-browser-prompt').html()).toBe('
Your browser is unable to display some of the content on this page.

Foo
');
    });
  });
});

Fix test for browser warning preprocessor


// grab the things we need
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

// create a schema
var photoSchema = new Schema({
  title: String,
  slug: String,
  status: String,
  description: String,
  author: {
    name: String,
    email: String,
    username: String
  },
  meta: {
    year: Number,
    location: String,
    caption: String
  },
  gallery: [{ name: String, slug: String }],
  tags: [{ name: String, slug: String }],
  created_at: Date,
  updated_at: Date,
});

// the schema is useless so far
// we need to create a model using it
var Photo = mongoose.model('Photo', photoSchema);

// make this available to our users in our Node applications
module.exports = Photo;

Update comments in Photo model


'use strict';

module.exports = function () {
	var map, iterator, result;
	if (typeof Map !== 'function') return false;
	if (String(Map.prototype) !== '[object Map]') return false;
	try {
		// WebKit doesn't support arguments and crashes
		map = new Map([['raz', 'one'], ['dwa', 'two'], ['trzy', 'three']]);
	} catch (e) {
		return false;
	}
	if (map.size !== 3) return false;
	if (typeof map.clear !== 'function') return false;
	if (typeof map.delete !== 'function') return false;
	if (typeof map.entries !== 'function') return false;
	if (typeof map.forEach !== 'function') return false;
	if (typeof map.get !== 'function') return false;
	if (typeof map.has !== 'function') return false;
	if (typeof map.keys !== 'function') return false;
	if (typeof map.set !== 'function') return false;
	if (typeof map.values !== 'function') return false;

	iterator = map.entries();
	result = iterator.next();
	if (result.done !== false) return false;
	if (!result.value) return false;
	if (result.value[0] !== 'raz') return false;
	if (result.value[1] !== 'one') return false;

	if (!map) return false;
	if (map.size !== 3) return false;

	return true;
};

'use strict';

module.exports = function () {
	var map, iterator, result;
	if (typeof Map !== 'function') return false;
	if (String(Map.prototype) !== '[object Map]') return false;
	try {
		// WebKit doesn't support arguments and crashes
		map = new Map([['raz', 'one'], ['dwa', 'two'], ['trzy', 'three']]);
	} catch (e) {
		return false;
	}
	if (map.size !== 3) return false;
	if (typeof map.clear !== 'function') return false;
	if (typeof map.delete !== 'function') return false;
	if (typeof map.entries !== 'function') return false;
	if (typeof map.forEach !== 'function') return false;
	if (typeof map.get !== 'function') return false;
	if (typeof map.has !== 'function') return false;
	if (typeof map.keys !== 'function') return false;
	if (typeof map.set !== 'function') return false;
	if (typeof map.values !== 'function') return false;

	iterator = map.entries();
	result = iterator.next();
	if (result.done !== false) return false;
	if (!result.value) return false;
	if (result.value[0] !== 'raz') return false;
	if (result.value[1] !== 'one') return false;

	return true;
};

Remove leftovers after logic cleanup


/**
 * jQuery if-else plugin
 *
 * Creates if(), else() and fi() methods that can be used in
 * a chain of methods on jQuery objects
 *
 * @author Vegard Løkken <vegard@headspin.no>
 * @copyright 2013
 * @version 0.1
 * @licence MIT
 */
;(function( $ ) {

    /* Undef object that all chained jQuery methods work on
     * if they should not be executed */
    var $undef = $();

    /* The original object is stored here so we can restore
     * it later */
    var orig;

    /* We store the condition given in the if() method */
    var condition;

    $.fn["if"] = function(options) {
        orig = this;
        condition = !!options;

        if (!condition) {
            return $undef;
        } else {
            return this;
        }
    };

    $.fn["else"] = function( options) {
        if (orig === undefined)
            throw "else() can't be used before if()";

        return this === $undef ? orig : $undef;
    };

    $.fn["fi"] = function(options) {
        if (orig === undefined)
            throw "fi() can't be used before if()";

        var toReturn = orig;
        orig = undefined;

        return toReturn;
    };

})(jQuery);

/**
 * jQuery if-else plugin
 *
 * Creates if(), else() and fi() methods that can be used in
 * a chain of methods on jQuery objects
 *
 * @author Vegard Løkken <vegard@headspin.no>
 * @copyright 2013
 * @version 0.2
 * @licence MIT
 */
;(function( $ ) {

    /* Undef object that all chained jQuery methods work on
     * if they should not be executed */
    var $undef = $();

    /* The original object is stored here so we can restore
     * it later */
    var orig;

    /* We store the condition given in the if() method */
    var condition;

    $.fn["if"] = function(options) {
        orig = this;
        condition = !!options;

        if (!condition) {
            return $undef;
        } else {
            return this;
        }
    };

    $.fn["else"] = function( options) {
        if (orig === undefined)
            throw "else() can't be used before if()";

        return this === $undef ? orig : $undef;
    };

    $.fn["fi"] = function(options) {
        if (orig === undefined)
            throw "fi() can't be used before if()";

        return orig;
    };

})(jQuery);

Make it possible to chain if's


function NewsControl() {
    var self = this;

    self.init = function() {
        // Make sure we can log without breaking old browsers
        if (typeof(window.console) === 'undefined') {
            window.console = {
                log: function() {},
                error: function(exception) { alert(exception); }
            };
        }

        // Handle unsuccessful requests
        $(document).ajaxError(function (e, r, ajaxOptions, thrownError) {
            switch (r.status) {
                case 401:
                    self.showInformationModal('You are not authorized.');
                    break;
                case 403:
                    // Logged out
                    Modal.showLogin();
                    break;
                case 404:
                    Modal.showInformation('A resource cannot be found (' + ajaxOptions.url + ')');
                    break;
                case 409:
                    Modal.showInformation('The item is not unique.');
                    break;
                case 500:
                    // Server error
                    Modal.showError(r.responseText);
                    break;
            }
        });

        // Setup user, news, feeds and tags

        Modal.init(self);

        self.loadingBar = new LoadingBar();
        self.news = new News(self);
        self.feeds = new Feeds(self);
        self.tags = new Tags(self);
        self.user = new User();
        self.topBar = new TopBar(self);
    };
}

function NewsControl() {
    var self = this;

    self.init = function() {
        // Make sure we can log without breaking old browsers
        if (typeof(window.console) === 'undefined') {
            window.console = {
                log: function() {},
                error: function(exception) { alert(exception); }
            };
        }

        // Handle unsuccessful requests
        $(document).ajaxError(function (e, r, ajaxOptions, thrownError) {
            switch (r.status) {
                case 401:
                    Model.showInformation('You are not authorized.');
                    break;
                case 403:
                    // Logged out
                    Modal.showLogin();
                    break;
                case 404:
                    Modal.showInformation('A resource cannot be found (' + ajaxOptions.url + ')');
                    break;
                case 409:
                    Modal.showInformation('The item is not unique.');
                    break;
                case 500:
                    // Server error
                    Modal.showError(r.responseText);
                    break;
            }
        });

        // Setup user, news, feeds and tags

        Modal.init(self);

        self.loadingBar = new LoadingBar();
        self.news = new News(self);
        self.feeds = new Feeds(self);
        self.tags = new Tags(self);
        self.user = new User();
        self.topBar = new TopBar(self);
    };
}

Fix bug when getting 'Unauthorized'


Drupal.behaviors.jqPlot = function(context) {
  var replace = ['renderer', 'markerRenderer', 'labelRenderer', 'parseX',
    'parseY', 'scrapeSingle', 'scrapeMultiple', 'processSeries'];

  $.each(Drupal.settings.jqPlot, function(selector, settings) {
    settings = Drupal.jqPlot.replaceFunctions(settings, replace);
    $(selector).tablechart(settings);
  });
}

Drupal.jqPlot = {};

Drupal.jqPlot.replaceFunctions = function(obj, replace) {
  $.each(obj, function(key, val) {
    if (typeof val == 'object') {
      obj[key] = Drupal.jqPlot.replaceFunctions(val, replace);
    }
    else if (typeof val == 'string' && $.inArray(key, replace) > -1) {
      namespaces = val.split(".");
      func = namespaces.pop();
      context = window;
      for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
      }
      obj[key] = context[func];
    }
  });
  return obj;
}

Drupal.behaviors.jqPlot = function(context) {
  if (Drupal.settings.jqPlot) {
    var replace = ['renderer', 'markerRenderer', 'labelRenderer', 'parseX',
      'parseY', 'scrapeSingle', 'scrapeMultiple', 'processSeries'];

    $.each(Drupal.settings.jqPlot, function(selector, settings) {
      settings = Drupal.jqPlot.replaceFunctions(settings, replace);
      $(selector).tablechart(settings);
    });
  }
}

Drupal.jqPlot = {};

Drupal.jqPlot.replaceFunctions = function(obj, replace) {
  $.each(obj, function(key, val) {
    if (typeof val == 'object') {
      obj[key] = Drupal.jqPlot.replaceFunctions(val, replace);
    }
    else if (typeof val == 'string' && $.inArray(key, replace) > -1) {
      namespaces = val.split(".");
      func = namespaces.pop();
      context = window;
      for (var i = 0; i < namespaces.length; i++) {
        context = context[namespaces[i]];
      }
      obj[key] = context[func];
    }
  });
  return obj;
}

Add conditional in case no settings exist.


define(
    [
        'jquery',
        'backbone',
        'underscore',
        'moment'
    ],
    function ($, Backbone, _, moment) {
        "use strict";

        return Backbone.Model.extend({

            url : function() {
                var base = $('body').data('api-url') + '/repos';

                return this.isNew() ? base : base + '/' + this.id;
            },

            presenter: function () {
                return _.extend(this.toJSON(), {
                    status: this.getStatus(),
                    travisUrl: this.getTravisUrl(),
                    githubUrl: this.getGithubUrl(),
                    lastBuildFinishedAt: this.getLastBuildFinishedAt(),
                    humanizedLastBuildFinishedAt: this.getHumanizedBuildFinishedAt()
                });
            },

            getStatus: function () {
                var lastBuildStatus = this.get('last_build_status');

                if (0 === lastBuildStatus) {
                    return 'passing';
                } else if (1 === lastBuildStatus) {
                    return 'failing';
                }

                return 'unknown';
            },

            getTravisUrl: function () {
                return 'https://travis-ci.org/' + this.get('slug') + '/builds/' + this.get('last_build_id');
            },

            getGithubUrl: function () {
                return 'https://github.com/' + this.get('slug');
            },

            getLastBuildFinishedAt: function () {
                return this.get('last_build_finished_at');
            },

            getHumanizedBuildFinishedAt: function () {
                if (undefined !== this.getLastBuildFinishedAt()) {
                    return moment(this.getLastBuildFinishedAt()).fromNow();
                }

                return '';
            }
        });
    }
);

define(
    [
        'jquery',
        'backbone',
        'underscore',
        'moment'
    ],
    function ($, Backbone, _, moment) {
        "use strict";

        return Backbone.Model.extend({

            url : function() {
                var base = $('body').data('api-url') + '/repos';

                return this.isNew() ? base : base + '/' + this.id;
            },

            presenter: function () {
                return _.extend(this.toJSON(), {
                    status: this.getStatus(),
                    travisUrl: this.getTravisUrl(),
                    githubUrl: this.getGithubUrl(),
                    lastBuildFinishedAt: this.getLastBuildFinishedAt(),
                    humanizedLastBuildFinishedAt: this.getHumanizedBuildFinishedAt()
                });
            },

            getStatus: function () {
                var lastBuildStatus = this.get('last_build_status');

                if (0 === lastBuildStatus) {
                    return 'passing';
                } else if (1 === lastBuildStatus) {
                    return 'failing';
                }

                return 'unknown';
            },

            getTravisUrl: function () {
                return 'https://travis-ci.org/' + this.get('slug') + '/builds/' + this.get('last_build_id');
            },

            getGithubUrl: function () {
                return 'https://github.com/' + this.get('slug');
            },

            getLastBuildFinishedAt: function () {
                return this.get('last_build_finished_at');
            },

            getHumanizedBuildFinishedAt: function () {
                if (this.getLastBuildFinishedAt()) {
                    return moment(this.getLastBuildFinishedAt()).fromNow();
                }

                return '';
            }
        });
    }
);

Fix getter if no date found


// @flow

import tinycolor from 'tinycolor2';

const BASE_COLOR = tinycolor('aliceblue')
  .spin(40)
  .toHexString();
const BASE_COLOR2 = tinycolor('aliceblue')
  .spin(10)
  .toHexString();
const COLORS = {
  light: BASE_COLOR,
  lightAlt: BASE_COLOR2,
  medium: tinycolor(BASE_COLOR)
    .darken(5)
    .toHexString(),
  mediumAlt: tinycolor(BASE_COLOR2)
    .darken(5)
    .toHexString(),
  dark: tinycolor(BASE_COLOR)
    .darken(10)
    .toHexString(),
  darkest: tinycolor(BASE_COLOR)
    .darken(65)
    .toHexString(),
  dim: '#999',
  accent: 'darkred',
};

const LANG_OPTIONS = [
  { value: 'en', label: 'English' },
  { value: 'es', label: 'Español' },
  { value: 'ca', label: 'Català' },
];

// ==========================================
// Public API
// ==========================================
export { COLORS, LANG_OPTIONS };

// @flow

/* eslint-env browser */

import tinycolor from 'tinycolor2';

// Detect theme
let THEME;
try {
  THEME = new URL(document.location).searchParams.get('theme');
} catch (err) {
  /* ignore */
}

const BASE_COLOR = tinycolor('aliceblue')
  .spin(40)
  .toHexString();
const BASE_COLOR2 = tinycolor('aliceblue')
  .spin(10)
  .toHexString();
const COLORS =
  THEME === 'embedded'
    ? {
        light: undefined,
        lightAlt: BASE_COLOR2,
        medium: '#f0f0f0',
        mediumAlt: '#f8f8f8',
        dark: '#e0e0e0',
        darkest: '#888',
        dim: '#999',
        accent: 'darkred',
      }
    : {
        light: BASE_COLOR,
        lightAlt: BASE_COLOR2,
        medium: tinycolor(BASE_COLOR)
          .darken(5)
          .toHexString(),
        mediumAlt: tinycolor(BASE_COLOR2)
          .darken(5)
          .toHexString(),
        dark: tinycolor(BASE_COLOR)
          .darken(10)
          .toHexString(),
        darkest: tinycolor(BASE_COLOR)
          .darken(65)
          .toHexString(),
        dim: '#999',
        accent: 'darkred',
      };

const LANG_OPTIONS = [
  { value: 'en', label: 'English' },
  { value: 'es', label: 'Español' },
  { value: 'ca', label: 'Català' },
];

// ==========================================
// Public API
// ==========================================
export { THEME, COLORS, LANG_OPTIONS };

Allow some theming via URL


import yargs from 'yargs';
import { version } from '../../package.json';

export default function appendCommon() {
  yargs.usage(`CSS Band Aid v${version}`.magenta + ` - Tools to ensure CSS files meet IE 6-9 selector limit restrictions.`)
    .epilogue('For additional information see http://blesscss.com')
    .wrap(null);
}

import yargs from 'yargs';
import { version } from '../../package.json';

export default function appendCommon() {
  yargs.usage(`BlessCSS v${version}`.magenta + ` - Tools to ensure CSS files meet IE 6-9 selector limit restrictions.`)
    .epilogue('For additional information see http://blesscss.com')
    .wrap(null);
}

Fix Missed CSS Band-aid to BlessCSS


import React from 'react'
import PlayerListRow from './PlayerListRow'
import UserColor from './UserColor'
import UserName from './Username'
import './PlayerList.css'

const colors = [
  'firebrick',
  'hotpink',
  'tomato',
  'peachpuff',
  'thistle',
  'darkorchid',
  'plategreen',
  'mediumaquamarine',
  'plateturquoise',
  'lightsteelblue',
  'wheat',
  'mistyrose'
]

const PlayerList = ({ userIds }) => (

Current Players

      {userIds && userIds.length > 0
        ? userIds.map(userId =>

            <UserColor userId={userId} />
            <UserName userId={userId} />

)
        :
Game currently has no players. Share the game code with your friends!

      }

)

export default PlayerList

import React from 'react'
import PlayerListRow from './PlayerListRow'
import './PlayerList.css'

/*const colors = [
  'firebrick',
  'hotpink',
  'tomato',
  'peachpuff',
  'thistle',
  'darkorchid',
  'plategreen',
  'mediumaquamarine',
  'plateturquoise',
  'lightsteelblue',
  'wheat',
  'mistyrose'
]*/

const PlayerList = ({ userIds }) => (

Current Players

      {userIds && userIds.length > 0
        ? userIds.map(userId =>
          <PlayerListRow userId={userId}/>)
        :
Game currently has no players. Share the game code with your friends!

      }

)

export default PlayerList

Fix some warnings about playerlist


var pkg = require('./package.json');
var node_modules = __dirname + '/node_modules';
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var environment = process.env.NODE_ENV;

module.exports = {
  devtool: 'inline-source-map',
  cache: true,
  resolve: {
    extensions: ['', '.jsx', '.scss', '.js', '.json']
  },
  context: __dirname,
  entry: {
    commons: ['./components/commons'],
    test: ['webpack/hot/dev-server', './spec/index.jsx']
  },
  output: {
    path: environment === 'production' ? './dist' : './build',
    filename: pkg.name + '.[name].js',
    publicPath: '/build/'
  },
  devServer: {
    host: '0.0.0.0',
    port: 8080,
    inline: true
  },
  module: {
    noParse: [node_modules + '/react/dist/*.js'],
    loaders: [
      { test: /(\.js|\.jsx)$/, exclude: /(node_modules)/, loaders: ['babel'] },
      { test: /(\.scss|\.css)$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]&sourceMap!postcss-loader!sass?sourceMap') }
    ]
  },
  postcss: [require('autoprefixer-core')],
  plugins: [new ExtractTextPlugin(pkg.name + '.[name].css', {allChunks: true})]
};

var pkg = require('./package.json');
var node_modules = __dirname + '/node_modules';
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var environment = process.env.NODE_ENV;

module.exports = {
  cache: true,
  resolve: {
    extensions: ['', '.jsx', '.scss', '.js', '.json']
  },
  context: __dirname,
  entry: {
    commons: ['./components/commons'],
    test: ['webpack/hot/dev-server', './spec/index.jsx']
  },
  output: {
    path: environment === 'production' ? './dist' : './build',
    filename: pkg.name + '.[name].js',
    publicPath: '/build/'
  },
  devServer: {
    host: '0.0.0.0',
    port: 8080,
    inline: true
  },
  module: {
    noParse: [node_modules + '/react/dist/*.js'],
    loaders: [
      { test: /(\.js|\.jsx)$/, exclude: /(node_modules)/, loaders: ['babel'] },
      { test: /(\.scss|\.css)$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader!sass') }
    ]
  },
  postcss: [require('autoprefixer-core')],
  plugins: [new ExtractTextPlugin(pkg.name + '.[name].css', {allChunks: true})]
};

Disable source mapping to speed up build time


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

// sass-loader needs this
require('es6-promise').polyfill();

module.exports = {
    entry: [
        'webpack-hot-middleware/client', // WebpackDevServer host and port
        'babel-polyfill',
        './ui/js/willow-main'
    ],
    output: {
        publicPath: '/',
        path: path.join(__dirname, '/ui'),
        filename: 'willow-main.js'
    },

    resolve: {
        extensions: ['', '.jsx', '.js', '.json'],
        modulesDirectories: ['node_modules', 'ui/js']
    },

    module: {
        loaders: [
            {
                loaders: [
                    'react-hot',
                    'babel?' + JSON.stringify({
                        plugins: [['transform-runtime']],
                        presets: ['stage-0', 'es2015', 'react']
                    })
                ],

                // Skip any files outside of your project's `src` directory
                include: [
                    path.resolve(__dirname, "ui"),
                ],

                // Only run `.js` and `.jsx` files through Babel
                test: /\.jsx?$/,
            },
            {
                test: /\.scss$/,
                loader: 'style!css!sass'
            }
        ]
    },
    devtool: 'source-map',
    debug: true,
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}

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

// sass-loader needs this
require('es6-promise').polyfill();

module.exports = {
    entry: [
        'webpack-hot-middleware/client', // WebpackDevServer host and port
        'babel-polyfill',
        './ui/js/willow-main'
    ],
    output: {
        publicPath: '/',
        path: path.join(__dirname, '/dist/js'),
        filename: 'willow-main.js'
    },

    resolve: {
        extensions: ['', '.jsx', '.js', '.json'],
        modulesDirectories: ['node_modules', 'ui/js']
    },

    module: {
        loaders: [
            {
                loaders: [
                    'react-hot',
                    'babel?' + JSON.stringify({
                        plugins: [['transform-runtime']],
                        presets: ['stage-0', 'es2015', 'react']
                    })
                ],

                // Skip any files outside of your project's `src` directory
                include: [
                    path.resolve(__dirname, "ui"),
                ],

                // Only run `.js` and `.jsx` files through Babel
                test: /\.jsx?$/,
            },
            {
                test: /\.scss$/,
                loader: 'style!css!sass'
            }
        ]
    },
    devtool: 'source-map',
    debug: true,
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}

Create final willow-main.js under dist/


// webpack.config.js
var Encore = require('@symfony/webpack-encore');

Encore
    // directory where all compiled assets will be stored
    .setOutputPath('web/assets/js/')
    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/js')
    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()
    // will output as web/build/app.js
    .addEntry('base', ['babel-polyfill', './app/Resources/client/jsx/base.jsx'])
    .addEntry('helpers', ['./app/Resources/client/jsx/helpers.jsx'])
    .addEntry('project/details', ['./app/Resources/client/jsx/project/details.jsx'])
    .addEntry('project/helpers', ['./app/Resources/client/jsx/project/helpers.jsx'])
    .addEntry('project/traitDetails', ['./app/Resources/client/jsx/project/traitDetails.jsx'])
    .addEntry('organism/details', ['./app/Resources/client/jsx/organism/details.jsx'])
    .addEntry('organism/search', ['./app/Resources/client/jsx/organism/search.jsx'])
    .addEntry('trait/browse', ['./app/Resources/client/jsx/trait/browse.jsx'])
    .addEntry('trait/search', ['./app/Resources/client/jsx/trait/search.jsx'])
    .enableSourceMaps(!Encore.isProduction())
;

// export the final configuration
module.exports = Encore.getWebpackConfig();

// webpack.config.js
var Encore = require('@symfony/webpack-encore');

Encore
    // directory where all compiled assets will be stored
    .setOutputPath('web/assets/js')
    // what's the public path to this directory (relative to your project's document root dir)
    .setPublicPath('/assets/js')
    // empty the outputPath dir before each build
    .cleanupOutputBeforeBuild()
    // will output as web/build/app.js
    .addEntry('project/details', ['./app/Resources/client/jsx/project/details.jsx'])
    .addEntry('project/helpers', ['./app/Resources/client/jsx/project/helpers.jsx'])
    .addEntry('project/traitDetails', ['./app/Resources/client/jsx/project/traitDetails.jsx'])
    .addEntry('organism/details', ['./app/Resources/client/jsx/organism/details.jsx'])
    .addEntry('organism/search', ['./app/Resources/client/jsx/organism/search.jsx'])
    .addEntry('trait/browse', ['./app/Resources/client/jsx/trait/browse.jsx'])
    .addEntry('trait/search', ['./app/Resources/client/jsx/trait/search.jsx'])
    .enableSassLoader()
    .createSharedEntry('global', [
        'babel-polyfill',
        'lodash',
        'jquery',
        './app/Resources/client/jsx/base.jsx',
        './app/Resources/client/jsx/helpers.jsx',
        './app/Resources/client/scss/base.scss'
    ])
    .autoProvidejQuery()
    .enableSourceMaps(!Encore.isProduction())
;

// export the final configuration
module.exports = Encore.getWebpackConfig();

Create shared global js/css via webpack


'use strict'
var webpack = require('webpack')

var reactExternal = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
}

module.exports = {
  externals: {
    'react': reactExternal
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'ReduxForm',
    libraryTarget: 'umd'
  },
  resolve: {
    extensions: ['', '.js']
  }
}

'use strict'
var webpack = require('webpack')

var reactExternal = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
}

var reduxExternal = {
  root: 'Redux',
  commonjs2: 'redux',
  commonjs: 'redux',
  amd: 'redux'
}

var reactReduxExternal = {
  root: 'ReactRedux',
  commonjs2: 'react-redux',
  commonjs: 'react-redux',
  amd: 'react-redux'
}

module.exports = {
  externals: {
    'react': reactExternal,
    'redux': reduxExternal,
    'react-redux': reactReduxExternal
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'ReduxForm',
    libraryTarget: 'umd'
  },
  resolve: {
    extensions: ['', '.js']
  }
}

Add Redux and React Redux as external dependencies


var ws = require('nodejs-websocket');

/**
 * Triggers when connections is established
 * @param connection
 * @private
 */
function _onConnection(connection) {
  connection.on('close', console.log.bind(console.log, 'Connection is closed -'));
}

/**
 * Returns Server
 * @param {String} port
 * @returns {Object}
 */
function WebSocketServer(port) {
  this._setServer(ws.createServer().listen(port));
  this._getServer().on('connection', _onConnection);
}

/**
 * Get native server
 * @returns {*}
 * @private
 */
WebSocketServer.prototype._getServer = function () {
  return this._server;
};

/**
 * Set new native server
 * @param server
 * @returns {WebSocketServer}
 * @private
 */
WebSocketServer.prototype._setServer = function (server) {
  this._server = server;
  return this;
};

/**
 * Send message to all connections
 * @param {*} data
 * @returns {WebSocketServer}
 */
WebSocketServer.prototype.send = function (data) {
  this._getServer().connections.forEach(function (connection) {
    connection.sendText(JSON.stringify(data));
  });

  return this;
};

module.exports = WebSocketServer;

var ws = require('nodejs-websocket');

/**
 * Triggers when connections is established
 * @param connection
 * @private
 */
function _onConnection(connection) {
  console.log('Connections is established');
  connection.on('error', console.error.bind(console.error));
  connection.on('close', console.log.bind(console.log, 'Connection is closed -'));
}

/**
 * Returns Server
 * @param {String} port
 * @returns {Object}
 */
function WebSocketServer(port) {
  this._setServer(ws.createServer().listen(port));
  this._getServer().on('connection', _onConnection);
  this._getServer().on('error', console.error.bind(console.error));
}

/**
 * Get native server
 * @returns {*}
 * @private
 */
WebSocketServer.prototype._getServer = function () {
  return this._server;
};

/**
 * Set new native server
 * @param server
 * @returns {WebSocketServer}
 * @private
 */
WebSocketServer.prototype._setServer = function (server) {
  this._server = server;
  return this;
};

/**
 * Send message to all connections
 * @param {*} data
 * @returns {WebSocketServer}
 */
WebSocketServer.prototype.send = function (data) {
  this._getServer().connections.forEach(function (connection) {
    connection.sendText(JSON.stringify(data));
  });

  return this;
};

module.exports = WebSocketServer;

Add error listeners to socket server


var _ = require('lodash');

/**
 * Create base social instance
 * @param {Object} [_config]
 * @constructor
 */
function BaseSocial(_config) {
  this._config = {};

  _.forOwn(_config, function (value, key) {
    this.set(key, value);
  }.bind(this));
}

/**
 * Get configuration value
 * @param {String} [path]
 * @returns {*}
 */
BaseSocial.prototype.get = function (path) {
  return typeof path === 'undefined' ? this._config : _.get(this._config, path);
};

/**
 * Set configuration value
 * @param {String} path
 * @param {*} value
 * @returns {BaseSocial}
 */
BaseSocial.prototype.set = function (path, value) {
  _.set(this._config, path, value);
  return this;
};

/**
 * Get provider for sending notifications
 * @returns {*}
 */
BaseSocial.prototype.getProvider = function () {
  return this._provider;
};

/**
 * Set new provider to this pusher
 * @param {*} provider
 * @returns {BaseSocial}
 */
BaseSocial.prototype.setProvider = function (provider) {
  this._provider = provider;
  return this;
};

BaseSocial.prototype.friends = _;
BaseSocial.prototype.photos = _;

module.exports = BaseSocial;

var _ = require('lodash');

/**
 * Create base social instance
 * @param {Object} [_config]
 * @constructor
 */
function BaseSocial(_config) {
  this._config = {};

  _.forOwn(_config, function (value, key) {
    this.set(key, value);
  }.bind(this));
}

/**
 * Get configuration value
 * @param {String} [path]
 * @returns {*}
 */
BaseSocial.prototype.get = function (path) {
  return typeof path === 'undefined' ? this._config : _.get(this._config, path);
};

/**
 * Set configuration value
 * @param {String} path
 * @param {*} value
 * @returns {BaseSocial}
 */
BaseSocial.prototype.set = function (path, value) {
  _.set(this._config, path, value);
  return this;
};

/**
 * Get provider for sending notifications
 * @returns {*}
 */
BaseSocial.prototype.getProvider = function () {
  return this._provider;
};

/**
 * Set new provider to this pusher
 * @param {*} provider
 * @returns {BaseSocial}
 */
BaseSocial.prototype.setProvider = function (provider) {
  this._provider = provider;
  return this;
};

BaseSocial.prototype.getFriends = _;
BaseSocial.prototype.getPhotos = _;

module.exports = BaseSocial;

Update interface implementation in baseSocial


define({
	plugins: [
		{ module: 'wire/debug' },
		{ module: 'wire/dojo/pubsub' }
	],
	// Create a logger object, in this case an AlertLogger
	logger: {
		create: 'test/test1/AlertLogger'
		// if you want a less noisy test, wire in a ConsoleLogger instead!
		// create: 'test/test1/ConsoleLogger'
	},
	// Create a publisher Thing that will publish a topic when its doSomething
	// method is called
	thing1: {
		create: "test/pubsub1/Thing",
		properties: {
			name: "Thing 1",
			logger: { $ref: 'logger' }
		},
		publish: {
			"doSomething": "thing/did-something"
		}
	},
	// Create a subscriber Thing whose doSomething method will be called
	// when the topic is published
	thing2: {
		create: "test/pubsub1/Thing",
		properties: {
			name: "Thing 2",
			logger: { $ref: 'logger' }
		},
		subscribe: {
			"thing/did-something": "doSomething"
		},
	}
});

define({
	plugins: [
		{ module: 'wire/debug' },
		{ module: 'wire/dojo/pubsub' }
	],
	// Create a logger object, in this case an AlertLogger
	logger: {
		create: 'test/test1/AlertLogger'
		// if you want a less noisy test, wire in a ConsoleLogger instead!
		// create: 'test/test1/ConsoleLogger'
	},
	// Create a publisher Thing that will publish a topic when its doSomething
	// method is called
	thing1: {
		create: "test/pubsub1/Thing",
		properties: {
			name: "Thing 1",
			logger: { $ref: 'logger' }
		},
		publish: {
			"doSomething": "thing/did-something"
		}
	},
	// Create a subscriber Thing whose doSomething method will be called
	// when the topic is published
	thing2: {
		create: "test/pubsub1/Thing",
		properties: {
			name: "Thing 2",
			logger: { $ref: 'logger' }
		},
		subscribe: {
			"thing/did-something": "doSomething"
		}
	}
});

Remove trailing comma, thanks @scothis


'use strict';

var express = require('express'),
	constants = require('../../app/config/constants'),
	config = require('../../app/config/config'),
	should = require('should'),
	cookieParser = require('cookie-parser'),
	routes = require('../../app/routes'),
	request = require('supertest')('http://localhost:3000');

describe('Local routing', function(){

	var server;

	beforeEach(function(){
		var app = express();
		app.use(cookieParser());
		app.use(constants.LOCAL_PATH, routes.local);
		server = app.listen(3005);
	});

	afterEach(function(){
		server.close();
	});

	it('should return local config object', function(done){
		request
			.get(constants.LOCAL_PATH + constants.CLIENT_CONFIG_PATH)
			.expect(200, function(err, res){
				should.not.exist(err);
				should(res.body).containDeep(config.clientConfig);
				done();
			});
	});

	it('should remove acces_token cookie', function(done){
		request
			.get(constants.LOCAL_PATH + constants.SIGN_OUT_PATH)
			.expect('set-cookie', /access_token=; Path=\/api;/)
			.expect(200, done);
	});

});

'use strict';

var express = require('express'),
	constants = require('../../app/config/constants'),
	config = require('../../app/config/config'),
	should = require('should'),
	cookieParser = require('cookie-parser'),
	routes = require('../../app/routes'),
	request = require('supertest')('http://localhost:3000');

describe('Local routing', function(){

	var server;

	beforeEach(function(){
		var app = express();
		app.use(cookieParser());
		app.use(constants.LOCAL_PATH, routes.local);
		server = app.listen(3000);
	});

	afterEach(function(){
		server.close();
	});

	it('should return local config object', function(done){
		request
			.get(constants.LOCAL_PATH + constants.CLIENT_CONFIG_PATH)
			.expect(200, function(err, res){
				should.not.exist(err);
				should(res.body).containDeep(config.clientConfig);
				done();
			});
	});

	it('should remove acces_token cookie', function(done){
		request
			.get(constants.LOCAL_PATH + constants.SIGN_OUT_PATH)
			.expect('set-cookie', /access_token=; Path=\/api;/)
			.expect(200, done);
	});

});

Undo - some expectation expects this port.


//= require action_cable
//= require_self
//= require_tree .

this.App = {};

App.cable = ActionCable.createConsumer();

App.messages = App.cable.subscriptions.create('MessagesChannel', {
  received: function(data) {
    console.log(data)
    $('#messages').removeClass('hidden')
    // append message
    $('#messages').append(data.message);
    // scroll down to latest message
    $("#messages").scrollTop($('#messages')[0].scrollHeight);
  }
});

//= require action_cable
//= require_self
//= require_tree .

this.App = {};

App.cable = ActionCable.createConsumer();

App.messages = App.cable.subscriptions.create('MessagesChannel', {
  received: function(data) {
    console.log(data)
    $('#messages').removeClass('hidden')
    // append message
    $('#messages').append(data.message);
    // scroll down to latest message
    $("#messages").scrollTop($('#messages')[0].scrollHeight);
    // clear #message_content input field
    $('#message_content').val('');
  }
});

Clear input field when receiving


/* global Showdown, Handlebars, html_sanitize*/
import cajaSanitizers from 'ghost/utils/caja-sanitizers';

var showdown,
    formatMarkdown;

showdown = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm']});

formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
    var escapedhtml = '';

    // convert markdown to HTML
    escapedhtml = showdown.makeHtml(markdown || '');

    // replace script and iFrame
    // jscs:disable
    escapedhtml = escapedhtml.replace(/

/* global Showdown, Handlebars, html_sanitize*/
import cajaSanitizers from 'ghost/utils/caja-sanitizers';

var showdown,
    formatMarkdown;

showdown = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm', 'footnotes']});

formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
    var escapedhtml = '';

    // convert markdown to HTML
    escapedhtml = showdown.makeHtml(markdown || '');

    // replace script and iFrame
    // jscs:disable
    escapedhtml = escapedhtml.replace(/

Add footnotes extension to showdown


'use strict';
// This file contains controllers of base pages attributes: header, footer, body, common menu and so on

(function() {
  angular.module('ncsaas')
    .controller('HeaderContoller', ['$scope', 'currentStateService', 'customersService', HeaderContoller]);

  function HeaderContoller($scope, currentStateService, customersService) {
    var vm = this;

    vm.customers = customersService.getCustomersList();
    vm.getUser = currentStateService.getUser;
    vm.getCustomer = currentStateService.getCustomer;
    vm.menuToggle = menuToggle;
    vm.setCurrentCustomer = currentStateService.setCustomer;
    // top-level menu
    vm.menuState = {
      addSomethingMenu : false,
      combineMenu : false,
      customerMenu : false,
      profileMenu : false
    };

    function menuToggle(active) {
      for (var property in vm.menuState) {
        if (vm.menuState.hasOwnProperty(property)) {
          if (property !== active) {
            vm.menuState[property] = false;
          }
        }
      }
      event.stopPropagation();
      vm.menuState[active] = !vm.menuState[active];
    }

    window.onclick = function() {
      for (var property in vm.menuState) {
        if (vm.menuState.hasOwnProperty(property)) {
          vm.menuState[property] = false;
        }
      }
      $scope.$apply();
    };

  }

})();

'use strict';
// This file contains controllers of base pages attributes: header, footer, body, common menu and so on

(function() {
  angular.module('ncsaas')
    .controller('HeaderController', ['$scope', 'currentStateService', 'customersService', HeaderController]);

  function HeaderController($scope, currentStateService, customersService) {
    var vm = this;

    vm.customers = customersService.getCustomersList();
    vm.getUser = currentStateService.getUser;
    vm.getCustomer = currentStateService.getCustomer;
    vm.menuToggle = menuToggle;
    vm.setCurrentCustomer = currentStateService.setCustomer;
    // top-level menu
    vm.menuState = {
      addSomethingMenu : false,
      combineMenu : false,
      customerMenu : false,
      profileMenu : false
    };

    function menuToggle(active) {
      for (var property in vm.menuState) {
        if (vm.menuState.hasOwnProperty(property)) {
          if (property !== active) {
            vm.menuState[property] = false;
          }
        }
      }
      event.stopPropagation();
      vm.menuState[active] = !vm.menuState[active];
    }

    window.onclick = function() {
      for (var property in vm.menuState) {
        if (vm.menuState.hasOwnProperty(property)) {
          vm.menuState[property] = false;
        }
      }
      $scope.$apply();
    };

  }

})();

Fix controller name after merge