var keystone = require('keystone'),
	Types = keystone.Field.Types;

var Station = new keystone.List('Station', {
	autokey: { from: 'name', path: 'key' }
});

Station.add({
	name: { type: String, default: Date.now },
	location: { type: Types.Location }
});

Station.register();

var keystone = require('keystone'),
	Types = keystone.Field.Types;

var Station = new keystone.List('Station', {
	autokey: { from: 'name', path: 'key' }
});

Station.add({
	name: { type: String },
	location: { type: Types.Location }
});

Station.register();

Fix for silly default in Station name field


"use strict";
const fs = require("fs");

const prettyDate = function(date) {
	const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

	return months[date.getUTCMonth()] + " " + date.getUTCDate() + ", " + date.getUTCFullYear();
};

const log = function(text) {
	const message = prettyDate(new Date(Date.now())) + ": " + text + "\n";

	console.log(message); // eslint-disable-line no-console

	fs.appendFile("log.txt", message, function(err) {
		if (err) {
			return console.log(err); // eslint-disable-line no-console
		}
	});
};

const ip2Hex = function(address) {
	return address.split(".").map(function(octet) {
		let hex = parseInt(octet, 10).toString(16);

		if (hex.length === 1) {
			hex = "0" + hex;
		}

		return hex;
	}).join("");
};

module.exports = {
	log,
	prettyDate,
	ip2Hex,
};

"use strict";
const fs = require("fs");

const prettyDate = function(date) {
	const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun",
		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];

	return months[date.getUTCMonth()] + " " + date.getUTCDate() + ", " + date.getUTCFullYear();
};

const log = function(text) {
	const message = prettyDate(new Date(Date.now())) + ": " + text;

	console.log(message); // eslint-disable-line no-console

	fs.appendFile("log.txt", message, function(err) {
		if (err) {
			return console.log(err); // eslint-disable-line no-console
		}
	});
};

const ip2Hex = function(address) {
	return address.split(".").map(function(octet) {
		let hex = parseInt(octet, 10).toString(16);

		if (hex.length === 1) {
			hex = "0" + hex;
		}

		return hex;
	}).join("");
};

module.exports = {
	log,
	prettyDate,
	ip2Hex,
};

Remove extra new line from log


define(function (require) {

	// Dependencies
	var $ = require('jquery')
		, _ = require('lodash')
		, Backbone = require('backbone')
	;

	/**
	 * Setup view
	 */
	var View = {};
	View.initialize = function() {
		_.bindAll(this);

		// Cache
		this.$customize = this.$('[name="_custom_permissions"]');
		this.$permissions = this.$('.permissions-list');
		this.$permissions_inner = this.$('.permissions-list-inner');
		this.$controllers = this.$permissions.find('.controller');

		// Listen for clicks on the override checkbox
		this.$customize.on('change', this.togglePermissionsOptions);

	};

	/**
	 * Toggle the permissions options
	 */
	View.togglePermissionsOptions = function() {

		// Inspect the clicked box
		var show = this.$customize.is(':checked');

		// Manually set the height whenever it's moving and then clear it when
		// animation is done.  The animation is defined in CSS.
		this.$permissions.height(this.$permissions_inner.outerHeight());
		_.delay(_.bind(function() { this.$permissions.height(''); }, this), 300);

		// Toggle the open state of the permissions
		_.defer(_.bind(function() { this.$el.toggleClass('closed', !show); }, this));
	};

	// Return view class
	return Backbone.View.extend(View);
});

define(function (require) {

	// Dependencies
	var $ = require('jquery')
		, _ = require('lodash')
		, Backbone = require('backbone')
	;

	/**
	 * Setup view
	 */
	var View = {};
	View.initialize = function() {
		_.bindAll(this);

		// Cache
		this.$role = $('[name="role"]');
		this.$customize = this.$('[name="_custom_permissions"]');
		this.$permissions = this.$('.permissions-list');
		this.$permissions_inner = this.$('.permissions-list-inner');
		this.$controllers = this.$permissions.find('.controller');

		// Listen for clicks on the override checkbox
		this.$customize.on('change', this.togglePermissionsOptions);

		// Check for the role to change and clear the custom permissions
		this.$role.on('change', this.clearCustomPermissions);

	};

	/**
	 * Toggle the permissions options
	 */
	View.togglePermissionsOptions = function() {

		// Inspect the clicked box
		var show = this.$customize.is(':checked');

		// Manually set the height whenever it's moving and then clear it when
		// animation is done.  The animation is defined in CSS.
		this.$permissions.height(this.$permissions_inner.outerHeight());
		_.delay(_.bind(function() { this.$permissions.height(''); }, this), 300);

		// Toggle the open state of the permissions
		_.defer(_.bind(function() { this.$el.toggleClass('closed', !show); }, this));
	};

	/**
	 * Clear permissions customizations
	 */
	View.clearCustomPermissions = function() {
		this.$customize.attr('checked', false).trigger('change');
	};

	// Return view class
	return Backbone.View.extend(View);
});

Clear the overriden permissions if the role is changed


(function rocketbelt(window, document) {
  window.rb = window.rb || {};

  window.rb.getShortId = function getShortId() {
    // Break the id into 2 parts to provide enough bits to the random number.
    // This should be unique up to 1:2.2 bn.
    var firstPart = (Math.random() * 46656) | 0;
    var secondPart = (Math.random() * 46656) | 0;
    firstPart = ('000' + firstPart.toString(36)).slice(-3);
    secondPart = ('000' + secondPart.toString(36)).slice(-3);
    return firstPart + secondPart;
  };

  window.rb.onDocumentReady = function onDocumentReady(fn) {
    if (
      document.readyState === 'complete' ||
      (document.readyState !== 'loading' && !document.documentElement.doScroll)
    ) {
      fn();
    } else {
      document.addEventListener('DOMContentLoaded', fn);
    }
  };
})(window, document);

(function rocketbelt(window, document) {
  window.rb = window.rb || {};

  window.rb.getShortId = function getShortId() {
    // Break the id into 2 parts to provide enough bits to the random number.
    // This should be unique up to 1:2.2 bn.
    var firstPart = (Math.random() * 46656) | 0;
    var secondPart = (Math.random() * 46656) | 0;
    firstPart = ('000' + firstPart.toString(36)).slice(-3);
    secondPart = ('000' + secondPart.toString(36)).slice(-3);
    return firstPart + secondPart;
  };

  window.rb.onDocumentReady = function onDocumentReady(fn) {
    if (
      document.readyState === 'complete' ||
      (document.readyState !== 'loading' && !document.documentElement.doScroll)
    ) {
      fn();
    } else {
      document.addEventListener('DOMContentLoaded', fn);
    }
  };

  window.rb.aria = {
    'current':     'aria-current',
    'describedby': 'aria-describedby',
    'disabled':    'aria-disabled',
    'expanded':    'aria-expanded',
    'haspopup':    'aria-haspopup',
    'hidden':      'aria-hidden',
    'invalid':     'aria-invalid',
    'label':       'aria-label',
    'labelledby':  'aria-labelledby',
    'live':        'aria-live',
    'role':        'role'
  };
})(window, document);

Add aria key-value pairs so that a bunch of magic strings can be removed.


module("About Strings (topics/about_strings.js)");

test("delimiters", function() {
    var singleQuotedString = 'apple';
    var doubleQuotedString = "apple";
    equal(__, singleQuotedString === doubleQuotedString, 'are the two strings equal?');
});

test("concatenation", function() {
    var fruit = "apple";
    var dish = "pie";
    equal(__, fruit + " " + dish, 'what is the value of fruit + " " + dish?');
});

test("character Type", function() {
    var characterType = typeof("Amory".charAt(1)); // typeof will be explained in about reflection
    equal(__, characterType, 'Javascript has no character type');
});

test("escape character", function() {
    var stringWithAnEscapedCharacter  = "\u0041pple";
    equal(__, stringWithAnEscapedCharacter, 'what  is the value of stringWithAnEscapedCharacter?');
});

test("string.length", function() {
    var fruit = "apple";
    equal(__, fruit.length, 'what is the value of fruit.length?');
});

test("slice", function() {
    var fruit = "apple pie";
    equal(__, fruit.slice(0,5), 'what is the value of fruit.slice(0,5)?');
});

module("About Strings (topics/about_strings.js)");

test("delimiters", function() {
    var singleQuotedString = 'apple';
    var doubleQuotedString = "apple";
    equal(true, singleQuotedString === doubleQuotedString, 'are the two strings equal?');
});

test("concatenation", function() {
    var fruit = "apple";
    var dish = "pie";
    equal("apple pie", fruit + " " + dish, 'what is the value of fruit + " " + dish?');
});

test("character Type", function() {
    var characterType = typeof("Amory".charAt(1)); // typeof will be explained in about reflection
    equal('string', characterType, 'Javascript has no character type');
});

test("escape character", function() {
    var stringWithAnEscapedCharacter  = "\u0041pple";
    equal("Apple", stringWithAnEscapedCharacter, 'what  is the value of stringWithAnEscapedCharacter?');
});

test("string.length", function() {
    var fruit = "apple";
    equal(5, fruit.length, 'what is the value of fruit.length?');
});

test("slice", function() {
    var fruit = "apple pie";
    equal("apple", fruit.slice(0,5), 'what is the value of fruit.slice(0,5)?');
});

Complete string tests to pass


var data = require('../../../data/titles');
var search = require('../../../data/search');

// Use this space to insert any prototype specific entries onto the available
// set of data.
// For example:
data.push({
  data: {},
  title_number: 'FAKE123123',
  address: [
    'Seaton Court',
    '2',
    'William Prance Rd',
    'Plymouth',
    'PL6 5WS'
  ]
});

module.exports = function(searchTerm, callback) {
  search(data, searchTerm, function(results) {

    // Limit the results returned to 50
    // (This limit is performed here rather than in the search so that future prototypes
    // can more easily experiment with derestricting the results)
    results = results.slice(0, 50);

    callback(results);
  });
};

var data = require('../../../data/titles');
var search = require('../../../data/search');

// Use this space to insert any prototype specific entries onto the available
// set of data.
// To inspect the structure of the data, uncomment the following line. This will
// log the data structure to your console which you can then copy and paste here
// before making any modifications you wish to.

// console.log(data[0]);

module.exports = function(searchTerm, callback) {
  search(data, searchTerm, function(results) {

    // Limit the results returned to 50
    // (This limit is performed here rather than in the search so that future prototypes
    // can more easily experiment with derestricting the results)
    results = results.slice(0, 50);

    callback(results);
  });
};

Add instructions for custom titles


// Avoid jslint errors for known globals
/*global L*/
var LocationMap = {
  'initialize': function initialize() {
    // Map centered in NowSecure HQ by default
    this.map = L.map('map').setView([40.2001925,-89.0876265], 3);
    this.markerCluster = L.markerClusterGroup();

    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '© OpenStreetMap contributors'
    }).addTo(this.map);
    this.map.addLayer(this.markerCluster);
  },
  'addMarkers': function addMarkers(markersData) {
    console.log('Adding ' + markersData.length + ' markers');
    markersData.forEach(function(markerData) {
        var marker = L.marker([markerData.latitude, markerData.longitude]);
        var text = 'Filename: ' + markerData.filename;
        if (markerData.datetime) {
          text += '
GPS datetime: ' + markerData.datetime;
        }

        marker.bindPopup(text);
        this.markerCluster.addLayer(marker);
    }, this);
  }
};

Use global directive to avoid jslint errors


const _ = {
  pick: require('lodash.pick'),
};
const express = require('express');
const fs = require('fs');
const path = require('path');

module.exports = () => {
  const router = new express.Router();
  const version = require('@maxdome/version')();
  router.get('/version', (req, res) => {
    res.send(version);
  });
  let env = process.env;
  try {
    const keys = fs
      .readFileSync(path.join(process.cwd(), '.env.example'), 'utf-8')
      .split('\n')
      .map(line => {
        const matches = line.match(/([A-Z_]*)=.*? #info/);
        if (matches) {
          return matches[1];
        }
      })
      .filter(key => key);
    env = _.pick(env, keys);
  } catch (e) {
    if (e.code !== 'ENOENT') {
      throw e;
    }
  }
  router.get('/env', (req, res) => {
    res.send(env);
  });
  return router;
};

const _ = {
  pick: require('lodash.pick'),
};
const express = require('express');
const fs = require('fs');
const path = require('path');

module.exports = () => {
  const router = new express.Router();

  const version = require('@maxdome/version')();
  router.get('/version', (req, res) => {
    res.send(version);
  });

  let env = {};
  try {
    const keys = fs
      .readFileSync(path.join(process.cwd(), '.env.example'), 'utf-8')
      .split('\n')
      .map(line => {
        const matches = line.match(/([A-Z_]*)=.*? #info/);
        if (matches) {
          return matches[1];
        }
      })
      .filter(key => key);
    env = _.pick(process.env, keys);
  } catch (e) {
    if (e.code !== 'ENOENT') {
      throw e;
    }
  }

  router.get('/env', (req, res) => {
    res.send(env);
  });

  return router;
};

Remove default output of all env vars


const childProcess = require('child_process')
const command = 'wmic logicaldisk get caption'

module.exports = function () {
  return new Promise((resolve, reject) => {
    childProcess.exec(command, (err, stdout) => {
      if (err) {
        return reject(err)
      }

      const rows = stdout.split(/\r?\n/)
      resolve(rows)
    })
  })
}

const childProcess = require('child_process')
const command = 'wmic logicaldisk get caption'

module.exports = function () {
  return new Promise((resolve, reject) => {
    childProcess.exec(command, (err, stdout) => {
      if (err) {
        return reject(err)
      }

      const rows = stdout.split(/\r?\n/).filter(row => row.trim().endsWith(':'))
      resolve(rows.map(r => r.trim()))
    })
  })
}

Clean up output from wmic


import cozydb from 'cozydb';
import invariant from 'invariant';
import logger from 'debug';
import hasValue from '../hasValue';

const debug = logger('app:model:favorite_tag');

const FavoriteTag = cozydb.getModel('FavoriteTag', {
    'label': String,
    'application': String,
});

export default FavoriteTag;

FavoriteTag.allForTasky = (callback) => {
    invariant(hasValue(callback), '`callback` is a mandatory parameter');
    invariant(typeof callback === 'function', '`callback` must be a function');

    debug('Retrieve all favorite tag for app Tasky.');
    FavoriteTag.request('allByApp', {key: 'tasky'}, (err, tags) => {
        const error = err || tags.error;
        if (hasValue(error)) {
            callback(error);
        } else {
            const labels = tags.map(tag => tag.label);
            callback(null, labels);
        }
    });
};

FavoriteTag.ByLabelForTasky = (label, callback) => {
    invariant(hasValue(label), '`label` is a mandatory parameter');
    invariant(hasValue(callback), '`callback` is a mandatory parameter');
    invariant(typeof label === 'string', '`label` must be a string');
    invariant(typeof callback === 'function', '`callback` must be a function');

    debug('Retrieve a favorite tag given a label, for app Tasky.');
    const options = {
        key: ['tasky', label],
    };
    FavoriteTag.request('byAppByLabel', options, callback);
};

import cozydb from 'cozydb';
import invariant from 'invariant';
import logger from 'debug';
import hasValue from '../hasValue';

const debug = logger('app:model:favorite_tag');

const FavoriteTag = cozydb.getModel('FavoriteTag', {
    'label': String,
    'application': String,
});

export default FavoriteTag;

FavoriteTag.allForTasky = (callback) => {
    invariant(hasValue(callback), '`callback` is a mandatory parameter');
    invariant(typeof callback === 'function', '`callback` must be a function');

    debug('Retrieve all favorite tag for app Tasky.');
    FavoriteTag.request('allByApp', {key: 'tasky'}, (err, tags) => {
        const error = err || tags.error;
        if (hasValue(error)) {
            callback(error);
        } else {
            const labels = tags.map(tag => tag.label);
            callback(null, labels);
        }
    });
};

FavoriteTag.byLabelForTasky = (label, callback) => {
    invariant(hasValue(label), '`label` is a mandatory parameter');
    invariant(hasValue(callback), '`callback` is a mandatory parameter');
    invariant(typeof label === 'string', '`label` must be a string');
    invariant(typeof callback === 'function', '`callback` must be a function');

    debug('Retrieve a favorite tag given a label, for app Tasky.');
    const options = {
        key: ['tasky', label],
    };
    FavoriteTag.request('byAppByLabel', options, callback);
};

Fix typo in function name


/*
  tags: basic, lines
<p> This example demonstrates how you can use `elements` to draw lines. </p>
 */

const regl = require('../regl')()

regl.clear({
  color: [0, 0, 0, 1],
  depth: 1
})

var lineWidth = 3
if (lineWidth > regl.limits.lineWidthDims[1]) {
  lineWidth = regl.limits.lineWidthDims[1]
}

regl({
  frag: `
    precision mediump float;
    uniform vec4 color;
    void main() {
      gl_FragColor = color;
    }`,

  vert: `
    precision mediump float;
    attribute vec2 position;
    void main() {
      gl_Position = vec4(position, 0, 1);
    }`,

  attributes: {
    position: (new Array(5)).fill().map((x, i) => {
      var theta = 2.0 * Math.PI * i / 5
      return [ Math.sin(theta), Math.cos(theta) ]
    })
  },

  uniforms: {
    color: [1, 0, 0, 1]
  },

  elements: [
    [0, 1],
    [0, 2],
    [0, 3],
    [0, 4],
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [2, 4],
    [3, 4]
  ],

  lineWidth: lineWidth
})()

/*
  tags: basic, lines
<p> This example demonstrates how you can use `elements` to draw lines. </p>
 */

const regl = require('../regl')()

regl.clear({
  color: [0, 0, 0, 1],
  depth: 1
})

var lineWidth = Math.max(3, regl.limits.lineWidthDims[1])

regl({
  frag: `
    precision mediump float;
    uniform vec4 color;
    void main() {
      gl_FragColor = color;
    }`,

  vert: `
    precision mediump float;
    attribute vec2 position;
    void main() {
      gl_Position = vec4(position, 0, 1);
    }`,

  attributes: {
    position: (new Array(5)).fill().map((x, i) => {
      var theta = 2.0 * Math.PI * i / 5
      return [ Math.sin(theta), Math.cos(theta) ]
    })
  },

  uniforms: {
    color: [1, 0, 0, 1]
  },

  elements: [
    [0, 1],
    [0, 2],
    [0, 3],
    [0, 4],
    [1, 2],
    [1, 3],
    [1, 4],
    [2, 3],
    [2, 4],
    [3, 4]
  ],

  lineWidth: lineWidth
})()

Simplify Elements example by using Math.max


import Backbone from 'backbone';

import {
  configurationContainer,
  entryTypeEditorControllerUrls,
  failureTracking,
  delayedDestroying,
  ForeignKeySubsetCollection
} from 'pageflow/editor';

export const Chapter = Backbone.Model.extend({
  mixins: [
    configurationContainer({
      autoSave: true,
      includeAttributesInJSON: ['position']
    }),
    delayedDestroying,
    entryTypeEditorControllerUrls.forModel({resources: 'chapters'}),
    failureTracking
  ],

  initialize(attributes, options) {
    this.sections = new ForeignKeySubsetCollection({
      parent: options.sections,
      parentModel: this,
      foreignKeyAttribute: 'chapterId',
      parentReferenceAttribute: 'chapter'
    });
    this.entry = options.entry;
  },

  addSection(attributes) {
    const section = this.sections.create({
      position: this.sections.length,
      chapterId: this.id,
      ...attributes
    }, {
      contentElements: this.entry.contentElements
    });

    section.once('sync', () => {
      section.contentElements.create({
        typeName: 'editableTextBlock',
        configuration: {
        }
      });
    });
  }
});

import Backbone from 'backbone';

import {
  configurationContainer,
  entryTypeEditorControllerUrls,
  failureTracking,
  delayedDestroying,
  ForeignKeySubsetCollection
} from 'pageflow/editor';

export const Chapter = Backbone.Model.extend({
  mixins: [
    configurationContainer({
      autoSave: true,
      includeAttributesInJSON: ['position']
    }),
    delayedDestroying,
    entryTypeEditorControllerUrls.forModel({resources: 'chapters'}),
    failureTracking
  ],

  initialize(attributes, options) {
    this.sections = new ForeignKeySubsetCollection({
      parent: options.sections,
      parentModel: this,
      foreignKeyAttribute: 'chapterId',
      parentReferenceAttribute: 'chapter'
    });
    this.entry = options.entry;
  },

  addSection(attributes) {
    const section = this.sections.create({
      position: this.sections.length,
      chapterId: this.id,
      ...attributes
    }, {
      contentElements: this.entry.contentElements
    });

    section.once('sync', () => {
      section.contentElements.create({
        typeName: 'textBlock',
        configuration: {
        }
      });
    });
  }
});

Fix type name of initial content element of new sections


define([
    'zepto',
    'Underscore',
    'Backbone',
    'models/expenses',
    'text!../../tpl/home.html' ],
    function ($, _, Backbone, Expenses, template) {
        var HomeView = Backbone.View.extend({

            events:{
                "click #get":"refresh"
            },

            initialize: function(){
                this.bind();
                this.refresh();
            },

            render: function () {
                this.el=_.template(template,{'models':this.model.toJSON()});
                this.slot.html(this.el);
                return this;
            },

            refresh: function(){
                this.model.fetch();
            },

            bind: function(){
                this.model.on('reset',this.render,this);
                this.model.on('add', this.render,this);
                this.model.on('remove',this.render, this);
            }
        });

        return new HomeView({model:new Expenses()});
    });

define([
    'zepto',
    'Underscore',
    'Backbone',
    'models/expenses',
    'text!../../tpl/home.html' ],
    function ($, _, Backbone, Expenses, template) {
        var HomeView = Backbone.View.extend({

            events:{
                "click #get":"refresh",
                "click tr": "navigate_row"

            },
            navigate_row: function (event){
                $(event.currentTarget).find('a')[0].click();
            },
            initialize: function(){
                this.bind();
                this.refresh();
            },

            render: function () {
                this.$el.html(_.template(template,{'models':this.model.toJSON()}));
                this.slot.html(this.el);
                return this;
            },

            refresh: function(){
                this.model.fetch();
            },

            bind: function(){
                this.model.on('reset',this.render,this);
                this.model.on('add', this.render,this);
                this.model.on('remove',this.render, this);
            }
        });

        return new HomeView({model:new Expenses()});
    });

Make sure events are working correctly on front page


/**
 * External dependencies.
 */

var Formatter = require('hydro-formatter');

/**
 * Dot formatter.
 *
 * @constructor
 */

var Dot = Formatter.extend();

/**
 * Before all tests.
 *
 * @param {Array} tests
 * @api public
 */

Dot.prototype.beforeAll = function(tests) {
  this.println();
  this.print(this.padding);
};

/**
 * After each test.
 *
 * @param {Object} test
 * @api public
 */

Dot.prototype.afterTest = function(test) {
  var status = test.failed ? 'red' : 'green';
  this.print(this.color(status, '.'));
};

/**
 * After all tests.
 *
 * @param {Result} test result
 * @api public
 */

Dot.prototype.afterAll = function(result) {
  this.println();
  this.displayResult(result);
  this.displayFailed(result);
};

/**
 * Primary export.
 */

module.exports = Dot;

/**
 * External dependencies.
 */

var Formatter = require('hydro-formatter');

/**
 * Dot formatter.
 *
 * @constructor
 */

var Dot = Formatter.extend();

/**
 * Before all tests.
 *
 * @api public
 */

Dot.prototype.beforeAll = function() {
  this.println();
  this.print(this.padding);
};

/**
 * After each test.
 *
 * @param {Object} test
 * @api public
 */

Dot.prototype.afterTest = function(test) {
  if (test.skipped) return;
  var status = test.failed ? 'red' : 'green';
  this.print(this.color(status, '.'));
};

/**
 * After all tests.
 *
 * @api public
 */

Dot.prototype.afterAll = function() {
  this.println();
  this.displayResult();
  this.displayFailed();
};

/**
 * Primary export.
 */

module.exports = Dot;

Make compatible with hydro 0.6


/* jshint node: true */

module.exports = function (environment) {
	var ENV = {
		modulePrefix: "dummy",
		environment: environment,
		baseURL: "/",
		locationType: "auto",
		EmberENV: {
			FEATURES: {
				// Here you can enable experimental features on an ember canary build
				// e.g. "with-controller": true
			}
		},

		APP: {
			// Here you can pass flags/options to your application instance
			// when it is created
		}
	};

	if (environment === "development") {
		// ENV.APP.LOG_RESOLVER = true;
		// ENV.APP.LOG_ACTIVE_GENERATION = true;
		// ENV.APP.LOG_TRANSITIONS = true;
		// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
		// ENV.APP.LOG_VIEW_LOOKUPS = true;
	}

	if (environment === "test") {
		// Testem prefers this...
		ENV.baseURL = "/";
		ENV.locationType = "none";

		// keep test console output quieter
		ENV.APP.LOG_ACTIVE_GENERATION = false;
		ENV.APP.LOG_VIEW_LOOKUPS = false;

		ENV.APP.rootElement = "#ember-testing";
	}

	if (environment === "production") {

	}

	return ENV;
};

/* jshint node: true */

module.exports = function (environment) {
	var ENV = {
		modulePrefix: "dummy",
		environment: environment,
		baseURL: "/",
		locationType: "auto",
		EmberENV: {
			FEATURES: {
				// Here you can enable experimental features on an ember canary build
				// e.g. "with-controller": true
			}
		},

		APP: {
			// Here you can pass flags/options to your application instance
			// when it is created
		}
	};

	if (environment === "development") {
		// ENV.APP.LOG_RESOLVER = true;
		// ENV.APP.LOG_ACTIVE_GENERATION = true;
		// ENV.APP.LOG_TRANSITIONS = true;
		// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
		// ENV.APP.LOG_VIEW_LOOKUPS = true;
	}

	if (environment === "test") {
		// Testem prefers this...
		ENV.baseURL = "/";
		ENV.locationType = "none";

		// keep test console output quieter
		ENV.APP.LOG_ACTIVE_GENERATION = false;
		ENV.APP.LOG_VIEW_LOOKUPS = false;

		ENV.APP.rootElement = "#ember-testing";
	}

	if (environment === "production") {

		var name = this.project.pkg.name;
		ENV.locationType = "hash";
		ENV.baseURL = "/" + name + "/";
	}

	return ENV;
};

Fix addon page with wrong baseURL


/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    contentSecurityPolicy: {
      'img-src': "'self' data: emberjs.com assets-cdn.github.com",
    },
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {
    ENV.baseURL = '/ember-bulma';
  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    contentSecurityPolicy: {
      'img-src': "'self' data: emberjs.com assets-cdn.github.com",
    },
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {
    ENV.baseURL = '/ember-bulma';
    ENV.locationType = 'hash';
  }

  return ENV;
};

Fix refresh 404 with hash URL


var Rx = require('rx'),
    _ = require('lodash');

function receiveMessage(sqs, params, callback) {
    sqs.receiveMessage(params, function (err, data) {
        callback(err, data);
        receiveMessage(sqs, params, callback);
    });
}

exports.observerFromQueue = function (sqs, params) {
    return Rx.Observer.create(function (messageParams) {
        sqs.sendMessage(_.defaults(messageParams, params), function (err, data) {

        });
    });
};

exports.observableFromQueue = function (sqs, params) {
    return Rx.Observable.create(function (observer) {
        receiveMessage(sqs, params, function (err, data) {

            if (err) {
                observer.onError(err);
            } else if (data && data.Messages) {
                _.forEach(data.Messages, function (message) {
                    observer.onNext(message);
                });
            }

            return function () {
                /* Clean up */
            };
        });
    });
};

exports.subjectFromQueue = function (sqs, sendParams, receiveParams) {
    return Rx.Subject.create(
        exports.observerFromQueue(sqs, sendParams),
        exports.observableFromQueue(sqs, receiveParams)
    );
};

var Rx = require('rx'),
    _ = require('lodash');

function receiveMessage(sqs, params, callback) {
    sqs.receiveMessage(params, function (err, data) {
        callback(err, data);
        receiveMessage(sqs, params, callback);
    });
}

exports.observerFromTopic = function (sns, params) {
    return Rx.Observer.create(function (messageParams) {
        sns.publish(_.defaults(messageParams, params), function (err, data) {

        });
    });
};

exports.observerFromQueue = function (sqs, params) {
    return Rx.Observer.create(function (messageParams) {
        sqs.sendMessage(_.defaults(messageParams, params), function (err, data) {

        });
    });
};

exports.observableFromQueue = function (sqs, params) {
    return Rx.Observable.create(function (observer) {
        receiveMessage(sqs, params, function (err, data) {

            if (err) {
                observer.onError(err);
            } else if (data && data.Messages) {
                _.forEach(data.Messages, function (message) {
                    observer.onNext(message);
                });
            }

            return function () {
                /* Clean up */
            };
        });
    });
};

exports.subjectFromQueue = function (sqs, sendParams, receiveParams) {
    return Rx.Subject.create(
        exports.observerFromQueue(sqs, sendParams),
        exports.observableFromQueue(sqs, receiveParams)
    );
};

Add support for observing an SNS topic.


export function CORDOVA_ASSET_TEMPLATE(assetType, platform, {src, d, w, h} = {}) {
    return `<${assetType} src="${src}" platform="${platform}"${d?` density="${d}"`:``}${w?` width="${w}"`:``}${h?` height="${h}`:``}" />`;
}
export function PGBUILD_ASSET_TEMPLATE(assetType, platform, {src, d, w, h} = {}) {
    return `<${assetType} src="${src}" gap:platform="${platform}"${d?` gap:qualifier="${d}"`:``}${w?` width="${w}"`:``}${h?` height="${h}`:``}" />`;
}

/**
 * Create a list of icons or splash screens
 * @param assetType {string} icon | splash
 * @param assetTemplate {function}     one of the above templates
 * @param cordova {*}
 */
export function transformCordovaAssets(assetType, assetTemplate, {cordova} = {cordova: {platforms: [], assets: {}}} ) {
    let {platforms} = cordova,
        assets = cordova[assetType];
    if (platforms instanceof Array && assets instanceof Object) {
        return platforms.map( platform => {
            let assetList = assets[platform];
            if (assetList instanceof Array) {
                return assetList.map(assetTemplate.bind(undefined, assetType, platform));
            } else {
                return "";
            }
        }).join("\n  ");
    } else {
        return "";
    }
}

export function CORDOVA_ASSET_TEMPLATE(assetType, platform, {src, d, w, h} = {}) {
    return `<${assetType} src="${src}" platform="${platform}"${d?` density="${d}"`:``}${w?` width="${w}"`:``}${h?` height="${h}"`:``} />`;
}
export function PGBUILD_ASSET_TEMPLATE(assetType, platform, {src, d, w, h} = {}) {
    return `<${assetType} src="${src}" gap:platform="${platform}"${d?` gap:qualifier="${d}"`:``}${w?` width="${w}"`:``}${h?` height="${h}"`:``} />`;
}

/**
 * Create a list of icons or splash screens
 * @param assetType {string} icon | splash
 * @param assetTemplate {function}     one of the above templates
 * @param cordova {*}
 */
export function transformCordovaAssets(assetType, assetTemplate, {cordova} = {cordova: {platforms: [], assets: {}}} ) {
    let {platforms} = cordova,
        assets = cordova[assetType];
    if (platforms instanceof Array && assets instanceof Object) {
        return platforms.map( platform => {
            let assetList = assets[platform];
            if (assetList instanceof Array) {
                return assetList.map(assetTemplate.bind(undefined, assetType, platform)).join("\n  ");
            } else {
                return "";
            }
        }).join("\n  ");
    } else {
        return "";
    }
}

Fix templates and add newlines


/**
 * Created by dell on 2015/7/20.
 * This is gulp init
 */
(function(){

    "use strict";

    var gulp = require('gulp');
    var loadPlugins = require('gulp-load-plugins');
    var plugins = loadPlugins();

    var Browsersync = require('browser-sync').create();
    var del = require('del');

    var paths = {
        src: 'app',
        dist: 'dist'
    };

    // 默认任务
    gulp.task('default', ["server","less","watch"]);

    // 搭建静态服务器
    gulp.task('server', function() {

        Browsersync.init({
            server: {
                baseDir: "./" +paths.src
            }
        });

    });

    // 编译Less文件
    gulp.task('less',function(){

        gulp.src([paths.src + '/less/style.less'])
            .pipe(plugins.less())
            .pipe(gulp.dest(paths.src + '/css'));

    });

    // 监控文件
    gulp.task('watch',function(){

        gulp.watch(paths.src + '/less/**/*.less', ['less']);

        gulp.watch([
                paths.src +"/**/*.html",
                paths.src + "/js/**/*.js",
                paths.src + "/lib/**/*.js",
                paths.src + "/css/**/*.css",
                paths.src + "/lib/**/*.css"
        ]).on("change", Browsersync.reload);

    });

}).call(this);

/**
 * Created by dell on 2015/7/20.
 * This is gulp init
 */
(function(){

    "use strict";

    var gulp = require('gulp');
    var loadPlugins = require('gulp-load-plugins');
    var plugins = loadPlugins();

    var Browsersync = require('browser-sync').create();
    var del = require('del');

    var paths = {
        src: 'app',
        dist: 'dist'
    };

    // 默认任务
    gulp.task('default', ["server","less","watch"]);

    // 搭建静态服务器
    gulp.task('server', function() {

        Browsersync.init({
            port: 3005,
            ui: {
                port: 3006
            },
            server: {
                baseDir: "./" +paths.src
            }
        });

    });

    // 编译Less文件
    gulp.task('less',function(){

        gulp.src([paths.src + '/less/style.less'])
            .pipe(plugins.less())
            .pipe(gulp.dest(paths.src + '/css'));

    });

    // 监控文件
    gulp.task('watch',function(){

        gulp.watch(paths.src + '/less/**/*.less', ['less']);

        gulp.watch([
                paths.src +"/**/*.html",
                paths.src + "/js/**/*.js",
                paths.src + "/lib/**/*.js",
                paths.src + "/css/**/*.css",
                paths.src + "/lib/**/*.css"
        ]).on("change", Browsersync.reload);

    });

}).call(this);

Add setting about server port


function Board(submitBtn, options) {
    this.submitBtn = submitBtn;
    this.options = options;
}

Board.prototype.prepareBoard = function() {
    this.hideButton(this.submitBtn);
    var board = this;
    this.options.forEach(function(option) {
        option.addCallBack(board.makeOnClick(option));
    });
};

Board.prototype.makeOnClick = function(option) {

};

Board.prototype.hideButton = function(btn) {
    btn.classList.add("hidden");
};

Board.prototype.disableOptions = function() {
    this.options.forEach(function(opt) {
        opt.disable();
    });
};

Board.prototype.enableOptions = function() {
    this.options.forEach(function(opt) {
        opt.enable();
    });
};

function Board(submitBtn, options) {
    this.submitBtn = submitBtn;
    this.options = options;
}

Board.prototype.prepareBoard = function() {
    this.hideButton(this.submitBtn);
    var board = this;
    this.options.forEach(function(option) {
        option.addCallBack(board.makeOnClick(option));
    });
};

Board.prototype.sendMove = function(move) {

};

Board.prototype.makeOnClick = function(option) {
    var move = option.value;
    var board = this;
    return function() {
        board.sendMove(move);
    };
};

Board.prototype.hideButton = function(btn) {
    btn.classList.add("hidden");
};

Board.prototype.disableOptions = function() {
    this.options.forEach(function(opt) {
        opt.disable();
    });
};

Board.prototype.enableOptions = function() {
    this.options.forEach(function(opt) {
        opt.enable();
    });
};

Implement the closure-generating click handler generator


'use strict';

export class PromiseQueue {
	constructor() {
		this.promises = [];
		this.endCallback;
		this.exceptionCallback;
		this.running;
	}
	run() {
		if(!this.running) {
			if(this.promises.isEmpty()) {
				if(this.endCallback) {
					this.endCallback();
				}
			}
			else {
				this.running = this.promises.shift();
				this.running.call()
					.then(() => {this.running = undefined; this.run();})
					.catch(exception => {if(this.exceptionCallback) {this.exceptionCallback(exception);}});
			}
		}
	}
	add(promise) {
		this.promises.push(promise);
		this.run();
		return this;
	}
	addAll(promises) {
		this.promises.pushAll(promises);
		this.run();
		return this;
	}
	clear() {
		this.promises = [];
		return this;
	}
	then(callback) {
		this.endCallback = callback;
		return this;
	}
	catch(callback) {
		this.exceptionCallback = callback;
		return this;
	}
}

export class PromiseQueue {
	constructor(result_callback) {
		this.promises = [];
		this.resultCallback = result_callback;
		this.endCallback;
		this.exceptionCallback;
		this.running;
	}
	run() {
		if(!this.running) {
			if(this.promises.isEmpty()) {
				if(this.endCallback) {
					this.endCallback();
				}
			}
			else {
				this.running = this.promises.shift();
				this.running.call()
					.then(result => {
						if(this.resultCallback) {
							this.resultCallback(result);
						}
						this.running = undefined;
						this.run();
					})
					.catch(exception => {
						if(this.exceptionCallback) {
							this.exceptionCallback(exception);
						}
					});
			}
		}
	}
	add(promise) {
		this.promises.push(promise);
		this.run();
		return this;
	}
	addAll(promises) {
		this.promises.pushAll(promises);
		this.run();
		return this;
	}
	clear() {
		this.promises = [];
		return this;
	}
	then(callback) {
		this.endCallback = callback;
		return this;
	}
	catch(callback) {
		this.exceptionCallback = callback;
		return this;
	}
}

Add callback to handle result of promises queued


// import external dependencies
import 'jquery';

// Import everything from autoload
import "./autoload/**/*"

// import local dependencies
import Router from './util/Router';
import common from './routes/common';
import home from './routes/home';
import aboutUs from './routes/about';

/** Populate Router instance with DOM routes */
const routes = new Router({
  // All pages
  common,
  // Home page
  home,
  // About Us page, note the change from about-us to aboutUs.
  aboutUs,
});

// Load Events
jQuery(document).ready(() => routes.loadEvents());

// import external dependencies
import 'jquery';
import 'foundation-sites';

// Import everything from autoload
import "./autoload/**/*"

// import local dependencies
import Router from './util/Router';
import common from './routes/common';
import home from './routes/home';
import aboutUs from './routes/about';

/** Populate Router instance with DOM routes */
const routes = new Router({
  // All pages
  common,
  // Home page
  home,
  // About Us page, note the change from about-us to aboutUs.
  aboutUs,
});

// Load Events
jQuery(document).ready(() => routes.loadEvents());

Switch bootstrap module import to foundation


const express = require('express');
const path = require('path');
const app = express();

app.use(express.static(path.join(__dirname, 'build')));

app.get('/', function (req, res) {
  res.sendFile(path.join(__dirname, '..', 'build', 'index.html'));
});

app.listen(80);
console.log('Listening to port 80');

const express = require('express');
const path = require('path');
const app = express();

const buildFolder = path.join(__dirname, '..', 'build');

app.use(express.static(buildFolder));

app.get('/', function (req, res) {
  res.sendFile(path.join(buildFolder, 'index.html'));
});

app.listen(3000);
console.log('Listening to port 3000');

Update server to run on port 3000


#!/usr/bin/env node

'use strict';

var stdin = process.openStdin();

var async = require('async');
var reachableUrl = require('reachable-url')

if (require.main === module) {
    main();
} else {
    module.exports = resolveUrls;
}

function main() {
    stdin.setEncoding('utf8');
    stdin.on('data', function(err, data) {
        if(err) {
            return console.error(err);
        }

        console.log(JSON.stringify(resolveUrls(JSON.parse(data)), null, 4));
    });
}

function resolveUrls(urls, cb) {
    async.mapLimit(urls, 20, resolveUrl, function(err, d) {
        if(err) {
            return cb(err);
        }

        cb(null, d.filter(id));
    });
}

function resolveUrl(d, cb) {
    reachableUrl(d.url).then(({ url }) => {
        d.url = url

        cb(null, d)
    }).catch(err => {
        console.error(err)

        cb();
    })
}

function id(a) {return a;}

#!/usr/bin/env node

'use strict';

var stdin = process.openStdin();

var async = require('async');
var reachableUrl = require('reachable-url')

if (require.main === module) {
    main();
} else {
    module.exports = resolveUrls;
}

function main() {
    stdin.setEncoding('utf8');
    stdin.on('data', function(err, data) {
        if(err) {
            return console.error(err);
        }

        console.log(JSON.stringify(resolveUrls(JSON.parse(data)), null, 4));
    });
}

function resolveUrls(urls, cb) {
    async.mapLimit(urls, 20, resolveUrl, function(err, d) {
        if(err) {
            return cb(err);
        }

        cb(null, d.filter(id));
    });
}

function resolveUrl(d, cb) {
    reachableUrl(d.url, { timeout: 10000 }).then(({ url }) => {
        d.url = url

        cb(null, d)
    }).catch(err => {
        console.error(err)

        cb();
    })
}

function id(a) {return a;}

Add a 10s timeout to reachable-url


var {JFrame, JButton, ImageIcon, JLabel} = javax.swing;
var {setInterval} = require('ringo/scheduler');
var n = 0;

function main() {
    var frame = new JFrame("Swing Demo");
    var button = new JButton(new ImageIcon("img/ringo-drums.png"));
    button.addActionListener(function(e) {
        setInterval(function() {
            if (n++ > 200) system.exit();
            frame.setLocation(200 + random(), 200 + random());
        }, 5);
    });
    frame.add("Center", button);
    frame.add("South", new JLabel("Click Button for Visual Drumroll!"));
    frame.setSize(300, 300);
    frame.setLocation(200, 200);
    frame.setVisible(true);
}

function random() (Math.random() - 0.5) * 50;

if (require.main == module) {
    main();
}

var {JFrame, JButton, ImageIcon, JLabel} = javax.swing;
var {setInterval} = require('ringo/scheduler');
var n = 0;

function main() {
    var frame = new JFrame("Swing Demo");
    var button = new JButton(new ImageIcon(module.resolve("img/ringo-drums.png")));
    button.addActionListener(function(e) {
        setInterval(function() {
            if (n++ > 200) system.exit();
            frame.setLocation(200 + random(), 200 + random());
        }, 5);
    });
    frame.add("Center", button);
    frame.add("South", new JLabel("Click Button for Visual Drumroll!"));
    frame.setSize(300, 300);
    frame.setLocation(200, 200);
    frame.setVisible(true);
}

function random() (Math.random() - 0.5) * 50;

if (require.main == module) {
    main();
}

Resolve image icon path relative to module


var PythonShell = require('python-shell');

var options = {
	scriptPath: 'realclearpolitics-scraper',
	args: [
		'http://www.realclearpolitics.com/epolls/2016/president/nv/nevada_democratic_presidential_caucus-5337.html',
		'test.json'
	]
}

PythonShell.run('scraper.py', options, function(err, results) {
	if (err) throw err;
	console.log(results);
});

var PythonShell = require('python-shell');

var options = {
	scriptPath: 'realclearpolitics-scraper',
	args: ['http://www.realclearpolitics.com/epolls/2016/president/nv/nevada_democratic_presidential_caucus-5337.html']
}

PythonShell.run('scraper.py', options, function(err, results) {
	if (err) throw err;
	console.log(results);
});

Update python script arguments in node script


var
	fs = require('fs')
	, path = require('path')
	, util = require('util')
	, events = require('events')
	, argv = require(path.resolve(__dirname, 'app', 'argv'))
	, client = require(path.resolve(__dirname, 'app', 'client'))
	, config = require(path.resolve(__dirname, 'app', 'config'))
	, logger = require(path.resolve(__dirname, 'lib', 'logger'))
	, app = new events.EventEmitter()
	, log = new logger(argv)
	, creds = {}
;

logger.default = log;
app.log = log;

app.on('error', function(err) {

	log.error(err);

	/**
	 * Do more stuff with errors.
	 * err should include .stack,
	 * which we could pipe to the cloud
	 * at some point, it would be useful!
	 */
});

var ninja = new client(argv, creds, app);

config(ninja, app);

/**
 * Note about apps (event emitters):
 *
 * We can instantiate multiple apps to
 * allow our modules to be namespaced/sandboxed
 * if we so desire. This allows us to provide
 * isolation without any additional infrastructure
 */

var
	fs = require('fs')
	, path = require('path')
	, util = require('util')
	, events = require('events')
	, argv = require(path.resolve(__dirname, 'app', 'argv'))
	, client = require(path.resolve(__dirname, 'app', 'client'))
	, config = require(path.resolve(__dirname, 'app', 'config'))
	, logger = require(path.resolve(__dirname, 'lib', 'logger'))
	, app = new events.EventEmitter()
	, log = new logger(argv)
	, creds = {}
;

logger.default = log;
app.log = log;

app.on('error', function(err) {

	log.error(err);

	/**
	 * Do more stuff with errors.
	 * err should include .stack,
	 * which we could pipe to the cloud
	 * at some point, it would be useful!
	 */
});

var ninja = new client(argv, creds, app);

if((!ninja) || !ninja.credentials.id) {

	log.error("Unable to create ninja client.");
	process.exit(1);
}

config(ninja, app);

/**
 * Note about apps (event emitters):
 *
 * We can instantiate multiple apps to
 * allow our modules to be namespaced/sandboxed
 * if we so desire. This allows us to provide
 * isolation without any additional infrastructure
 */

Exit if unable to create ninja.


const ChildProcess = require('child_process')
const path = require('path')

const version = require('../package').version + '.0'

const command = path.join(__dirname, '..', 'node_modules', '.bin', 'electron-windows-store.cmd')
const args = [
  '--input-directory',
  path.join(__dirname, '..', 'out', 'ElectronAPIDemos-win32-ia32'),
  '--output-directory',
  path.join(__dirname, '..', 'windows-store'),
  '--flatten',
  true,
  '--package-version',
  version,
  '--package-name',
  'ElectronAPIDemos'
]

const windowsStore = ChildProcess.spawn(command, args, {stdio: 'inherit'})
windowsStore.on('close', (code) => {
  process.exit(code)
})

const ChildProcess = require('child_process')
const path = require('path')

const version = require('../package').version + '.0'

const command = path.join(__dirname, '..', 'node_modules', '.bin', 'electron-windows-store.cmd')
const args = [
  '--input-directory',
  path.join(__dirname, '..', 'out', 'ElectronAPIDemos-win32-ia32'),
  '--output-directory',
  path.join(__dirname, '..', 'out', 'windows-store'),
  '--flatten',
  true,
  '--package-version',
  version,
  '--package-name',
  'ElectronAPIDemos'
]

const windowsStore = ChildProcess.spawn(command, args, {stdio: 'inherit'})
windowsStore.on('close', (code) => {
  process.exit(code)
})

Store appx in out folder


/**
 *    The "Initial"/"Main" prompts
 */
"use strict";
module.exports = [
  {
    type:     "list",
    name:     "main",
    message:  "Welcome to git-labelmaker!\nWhat would you like to do?",
    choices:  [ "Add Custom Labels", "Add Labels From Package", "Remove Labels", "Reset Token" ]
  }
];

/**
 *    The "Initial"/"Main" prompts
 */
"use strict";
module.exports = [
  {
    type:     "list",
    name:     "main",
    message:  "Welcome to git-labelmaker!\nWhat would you like to do?",
    choices:  [ "Add Custom Labels", "Add Labels From Package", "Remove Labels", "Remove All Labels", "Reset Token" ]
  }
];

Add Remove All labels prompt


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

// returns true if the image is loaded and decoded,
// or a number, if it didn't find one single image,
// or a helpful error if it wasn't an image,
// or the path, if it found some non-loaded image
module.exports = function imgLoaded(selector) {
  function describe(elem) {
    var tag = (elem.tagName || '').toLowerCase();
    if (elem.id) {
      tag += '#' + elem.id;
    }
    var classes = elem.className.replace(/^\s+|\s+$/g, '');
    if (classes) {
      tag += '.' + classes.replace(/\s+/g, '.');
    }
    return tag;
  }

  var imgs = document.querySelectorAll(selector);
  if (imgs.length !== 1) {
    return imgs.length;
  }
  var img = imgs[0];

  if (!img.src) {
    if ((img.tagName || '').match(/^img$/i)) {
      return 'src-less ' + describe(img);
    }
    return 'non-image ' + describe(img);
  }

  return img.complete && img.naturalWidth ? true : img.src;
};

Remove traces of jshint config


var OngoingGames = require("../models/OngoingGames");

var playerQueue = [];

exports.startGame = function(req, res) {

  var player1 = req.body.username;

  var game = OngoingGames.findGame(player1);

  // player has ongoing game
  if (game != null) {
    res.json(game);
  }

  // Start a new game if opponent exists. Pops the last element in queue.
  else if (playerQueue.length > 0) {
    OngoingGames.startGame(player1, playerQueue.pop());
    res.json({'message': 'Starting new game.'});
  }

  // If no players in queue, put this player in start of queue.
  else  {
    playerQueue.unshift(player1);
    res.json({'message': 'Waiting for opponent.'});
  }
};

var OngoingGames = require("../models/OngoingGames");

var playerQueue = [];

exports.startGame = function(req, res) {

  var player1 = req.body.username;

  var game = OngoingGames.findGame(player1);

  // player has ongoing game
  if (game != null) {
    res.json(game);
  }

  // Start a new game if opponent exists and opponent is not the same player. Pops the last element in queue.
  else if (playerQueue.length > 0 && playerQueue.indexOf(player1) === -1) {
    OngoingGames.startGame(player1, playerQueue.pop());
    res.json({'message': 'Starting new game.'});
  }

  // If no players in queue, put this player in start of queue.
  else  {
    playerQueue.unshift(player1);
    res.json({'message': 'Waiting for opponent.'});
  }
};

Fix issue-1: Keep waiting if the same user joins


const jsdom = require('jsdom');

const f = (context, cb) => {
  const wikipediaUrl = context.data['article-url'];
  jsdom.env({
    url: `${ wikipediaUrl }?printable=yes`,
    scripts: ['http://code.jquery.com/jquery.js'],
    done: (err, window) => {
      const $ = window.$;

      $('script').remove(); // remove all scripts
      $('.thumb').remove(); // remove all images
      $('#toc').remove(); // remove the TOC
      $('.mw-editsection').remove(); // remove the edit controls
      $('.reference').remove(); // remove all foot notes
      $('table').remove(); // inline tables are useless

      cb(null, $('#mw-content-text').text());
    }
  });
};

module.exports = f;

const jsdom = require('jsdom');

const f = (context, cb) => {
  const wikipediaUrl = context.data['article-url'];
  jsdom.env({
    url: `${ wikipediaUrl }?printable=yes`,
    scripts: ['http://code.jquery.com/jquery.js'],
    done: (err, window) => {
      const $ = window.$;

      $('script').remove(); // remove all scripts
      $('.thumb').remove(); // remove all images
      $('#toc').remove(); // remove the TOC
      $('.mw-editsection').remove(); // remove the edit controls
      $('.reference').remove(); // remove all foot notes
      $('table').remove(); // inline tables are useless

      // remove content at the bottom which we dont need
      $('.printfooter').remove();
      $('#catlinks').remove();
      $('noscript').remove();

      cb(null, $('#mw-content-text').text());
    }
  });
};

module.exports = f;

Remove more content from the wikipedia article, that we dont want.


export {default as name} from './name';
export {default as firstName} from './firstName';
export {default as lastName} from './lastName';

export {default as name} from './name';
export {default as gender} from './gender';
export {default as firstName} from './firstName';
export {default as lastName} from './lastName';

Fix gender definition not exists in zh-Hant-TW.


var fs          = require("fs");
var queryString = require("querystring");

function start(response, postData) {
  console.log("Request handler 'start' was called.");

  fs.readFile("./public/index.html", "utf8", function(error, data) {
    response.writeHead(200, {
    "Content-Type": "text/html"
  });
    response.write(data);
    response.end();
  });
}

function upload(response, postData) {
  console.log("Request handler 'upload' was called.");
  response.writeHead(200, {
    "Content-Type": "text/plain"
  });
  response.write("You have sent: " + queryString.parse(postData).text);
  response.end();
}

function show(response) {
  console.log("Request handler 'show' was called.");
  response.writeHead(200, {
    "Content-Type": "image/png"
  });
  fs.createReadStream("/tmp/text.png").pipe(response);
}

exports.start   = start;
exports.upload  = upload;
exports.show    = show;

var fs          = require("fs");
var queryString = require("querystring");

function start(response, postData) {
  console.log("Request handler 'start' was called.");

  fs.readFile("./public/index.html", "utf8", function(error, data) {
    response.writeHead(200, {
    "Content-Type": "text/html"
  });
    response.write(data);
    response.end();
  });
}

function upload(response, postData) {
  console.log("Request handler 'upload' was called.");
  response.writeHead(200, {
    "Content-Type": "text/plain"
  });
  response.write("You have sent: " + queryString.parse(postData).text);
  response.end();
}

function show(response) {
  console.log("Request handler 'show' was called.");
  response.writeHead(200, {
    "Content-Type": "image/png"
  });
  fs.createReadStream("./tmp/test.png").pipe(response);
}

exports.start   = start;
exports.upload  = upload;
exports.show    = show;

Fix bug in server image


Expression.prototype.polar = function() {
	var ri = this.realimag();
	var two = new Expression.Integer(2);
	return Expression.List.ComplexPolar([
		ri[0]['^'](two)['+'](ri[1]['^'](two)),
		Global.atan2.default(Expression.Vector([ri[1], ri[0]]))
	]);
};
Expression.prototype.abs = function() {
	console.warn('SLOW?');
	var ri = this.realimag();
	return ri[0]['*'](ri[0])['+'](ri[1]['*'](ri[1]));
};
Expression.prototype.arg = function() {
	console.warn('Slow?');
	var ri = this.realimag();
	return Global.atan2.default(Expression.Vector([ri[1], ri[0]]));
};

Expression.prototype.polar = function() {
	var ri = this.realimag();
	var two = new Expression.Integer(2);
	return Expression.List.ComplexPolar([
		Global.sqrt.default(ri[0]['^'](two)['+'](ri[1]['^'](two))),
		Global.atan2.default(Expression.Vector([ri[1], ri[0]]))
	]);
};
Expression.prototype.abs = function() {
	console.warn('SLOW?');
	var ri = this.realimag();
	var two = new Expression.Integer(2);
	return Global.sqrt.default(ri[0]['^'](two)['+'](ri[1]['^'](two)));
};
Expression.prototype.arg = function() {
	console.warn('Slow?');
	var ri = this.realimag();
	return Global.atan2.default(Expression.Vector([ri[1], ri[0]]));
};

Fix absolute value of cartesian (was previously x*x+y*y, but should be Sqrt[x^2+y^2])


/// <reference types="cypress" />

context('Actions', () => {
  beforeEach(() => {
    cy.visit('http://localhost:8000')
  });

  it('All + elements are clickable', () => {
    cy.get('.step-up').click( { multiple: true } );

    // This gets the "first" input from the sidebar. From clicking step up,
    // the Regional Population should increase from default 4119405 to 4219405.
    cy.get('input.st-al')
      .should('has.value', '4219405')
  })
});

/// <reference types="cypress" />

context('Actions', () => {
  beforeEach(() => {
    cy.visit('http://localhost:8000')
  });

  it('All + elements are clickable', () => {
    cy.get('.step-up').click( { multiple: true } );

    // This gets the "first" input from the sidebar. From clicking step up,
    // the Regional Population should increase from default 4119405 to 4219405.
    cy.get('input.st-al')
      .should('has.value', '4119406')
  })
});

Update cypress test expected value given new step value for regional pop


import React from 'react';
import Button from 'react-bootstrap/lib/Button';
import Panel from 'react-bootstrap/lib/Panel';

import Icon from './icon.react';

export default class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: true
    };
  }

  render() {
    return (
      <div>
        <Button onClick={ ()=> this.setState({ open: !this.state.open })}>
          click
        </Button>
        <Panel collapsible expanded={this.state.open}>
          Anim pariatur cliche reprehenderit, enim eiusmod high life accusamus terry richardson ad squid.
          Nihil anim keffiyeh helvetica, craft beer labore wes anderson cred nesciunt sapiente ea proident.
          <Button onClick={ ()=> this.setState({ open: !this.state.open })}>
            click
          </Button>
        </Panel>
      </div>
    );
  }
}

Fix syntax rules for npm test


import React, { Component } from 'react';
import Chart from 'chart.js';

class ChartComponent extends Component {

  componentDidMount() {
    this.renderChart(this.props.measurement.measurements);
  }

  componentWillUpdate(nextProps) {
    if (nextProps.measurement.createdAt !== this.props.measurement.createdAt) {
      this.updateChart(nextProps.measurement.measurements);
    }
  }

  updateChart(measurements) {
    this.chart.destroy();
    this.renderChart(measurements);
  }

  renderChart(measurements) {
    const data = measurements.map(measurement => measurement['Wasted time (ms)']);
    const labels = measurements.map(measurement => measurement['Owner > component']);
    this.chart = new Chart(document.getElementById('perf-tool-chart-ctx'), {
      type: 'bar',
      data: {
        labels,
        datasets: [{
          data,
          label: this.props.label,
          backgroundColor: 'rgba(75,192,192,0.4)',
        }],
      },
      options: {
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true,
            },
          }],
        },
      },
    });
  }

  render() {
    return (<div className="chart-container" style={{ maxWidth: '900px' }}>
      <canvas id="perf-tool-chart-ctx" style={{ width: `${this.props.width}px`, height: `${this.props.height}px` }} />
    </div>);
  }
}

export default ChartComponent;

import React, { Component } from 'react';
import Chart from 'chart.js';

class ChartComponent extends Component {

  componentDidMount() {
    this.renderChart(this.props.measurement.measurements);
  }

  componentWillUpdate(nextProps) {
    if (nextProps.measurement.createdAt !== this.props.measurement.createdAt) {
      this.updateChart(nextProps.measurement.measurements);
    }
  }

  updateChart(measurements) {
    this.chart.destroy();
    this.renderChart(measurements);
  }

  renderChart(measurements) {
    const data = measurements.map(measurement => measurement.inclusiveRenderDuration);
    const labels = measurements.map(measurement => measuremen.key);
    this.chart = new Chart(document.getElementById('perf-tool-chart-ctx'), {
      type: 'bar',
      data: {
        labels,
        datasets: [{
          data,
          label: this.props.label,
          backgroundColor: 'rgba(75,192,192,0.4)',
        }],
      },
      options: {
        scales: {
          yAxes: [{
            ticks: {
              beginAtZero: true,
            },
          }],
        },
      },
    });
  }

  render() {
    return (<div className="chart-container" style={{ maxWidth: '900px' }}>
      <canvas id="perf-tool-chart-ctx" style={{ width: `${this.props.width}px`, height: `${this.props.height}px` }} />
    </div>);
  }
}

export default ChartComponent;

Use correct keys for measurement & label


const path = require("path");

module.exports = function(config) {
    config.set({
        frameworks: ["jasmine"],
        proxies: {
            '/lib/css/': '/base/lib/css'
        },
        files: [
            { pattern: "./src/**/*.js", type: "module" },
            { pattern: "./test/**/*.js", type: "module" },
            { pattern: "./lib/css/*.css", type: 'css'}
        ],
        preprocessors: {
            "src/**/!(*.test).js": ["karma-coverage-istanbul-instrumenter"]
        },
        reporters: ["spec","junit", "coverage-istanbul"],
        junitReporter: {
            outputDir: './output',
            outputFile: undefined,
            suite: '',
            useBrowserName: false,
            nameFormatter: undefined,
            classNameFormatter: undefined,
            properties: {},
            xmlVersion: null
        },
        coverageIstanbulInstrumenter: {
            esModules: true
        },
        coverageIstanbulReporter: {
            reports: ["html", "text", "lcovonly"],
            dir: path.join(__dirname, "coverage"),
            skipFilesWithNoCoverage: true
        },
        browsers: ["ChromeHeadless"],
        singleRun: true
    });
};

const path = require("path");

module.exports = function(config) {
    config.set({
        frameworks: ["jasmine"],
        proxies: {
            '/lib/css/': '/base/lib/css'
        },
        files: [
            { pattern: "./src/**/*.js", type: "module" },
            { pattern: "./node_modules/@browser-modules/typescript.dictionary/lib/dictionary.js", type: "module" },
            { pattern: "./test/**/*.js", type: "module" },
            { pattern: "./lib/css/*.css", type: 'css'}
        ],
        preprocessors: {
            "src/**/!(*.test).js": ["karma-coverage-istanbul-instrumenter"]
        },
        reporters: ["spec","junit", "coverage-istanbul"],
        junitReporter: {
            outputDir: './output',
            outputFile: undefined,
            suite: '',
            useBrowserName: false,
            nameFormatter: undefined,
            classNameFormatter: undefined,
            properties: {},
            xmlVersion: null
        },
        coverageIstanbulInstrumenter: {
            esModules: true
        },
        coverageIstanbulReporter: {
            reports: ["html", "text", "lcovonly"],
            dir: path.join(__dirname, "coverage"),
            skipFilesWithNoCoverage: true
        },
        browsers: ["ChromeHeadless"],
        singleRun: true
    });
};

Add module as unit test dependency


import { Firebase, firebaseAuth, firebaseRef } from './firebase'

export const login = () => {
  const provider = new firebaseAuth.GithubAuthProvider()
  provider.addScope('repo')
  // TODO on mobile, sign in without redirect
  firebaseAuth().signInWithPopup(provider).then(function(result) {
    const user = result.user
    firebaseRef.child('users').child(user.uid).set({
      email: user.email,
      signedInAt: Firebase.database.ServerValue.TIMESTAMP,
    })
  }).catch(function(error) {
    console.error('login error', error)
    // TODO display the error
  })
}

export const logout = () => firebaseAuth().signOut()

export const onAuthStateChanged = (cb) =>
  firebaseAuth().onAuthStateChanged(cb)

import { Firebase, firebaseAuth, firebaseRef } from './firebase'

export const login = () => {
  const provider = new firebaseAuth.GithubAuthProvider()
  provider.addScope('repo')
  // TODO on mobile, sign in without redirect
  firebaseAuth().signInWithPopup(provider).then(function(result) {
    const user = result.user
    firebaseRef.child('users').child(user.uid).set({
      displayName: user.displayName,
      email: user.email,
      lastSignedInAt: Firebase.database.ServerValue.TIMESTAMP,
    })
  }).catch(function(error) {
    console.error('login error', error)
    // TODO display the error
  })
}

export const logout = () => firebaseAuth().signOut()

export const onAuthStateChanged = (cb) =>
  firebaseAuth().onAuthStateChanged(cb)

Save user displayName; rename signedInAt → lastSignedInAt


const MySql = require("./MySql.js");
const entities = require("entities");
const moment = require("moment");

class Meet{
  constructor(obj){
    Object.keys(obj).forEach(k=>this[k]=entities.decodeHTML(obj[k]));
  }

  asMarkdown(){
    return `[${this.post_title}](${this.guid}) _${moment(this.meet_start_time).calendar()}_`;
  }

}
Meet.fromObjArray = function(objArray){
  return objArray.map(o=>new Meet(o));
};

function getAllMeets(){
  return MySql.query(`SELECT * FROM wp_posts WHERE post_type = 'meet'`)
    .then(results=>Meet.fromObjArray(results.results));
}

function getUpcomingMeets(){
  return MySql.query(`
    SELECT CAST(meta_value AS DATE) AS meet_start_time, wp_posts.*
    FROM wp_postmeta LEFT JOIN wp_posts ON post_id=ID
    WHERE meta_key = 'meet_start_time' AND CAST(meta_value AS DATE) > CURDATE()
  `).then(results=>Meet.fromObjArray(results.results));
}

module.exports = {getAllMeets,getUpcomingMeets};

const MySql = require("./MySql.js");
const entities = require("entities");
const moment = require("moment");

class Meet{
  constructor(obj){
    Object.keys(obj).forEach(k=>this[k]=entities.decodeHTML(obj[k]));
  }

  asMarkdown(){
    return `[${this.post_title}](${this.guid}) _${moment(this.meet_start_time).calendar()}_`;
  }

}
Meet.fromObjArray = function(objArray){
  return objArray.map(o=>new Meet(o));
};

function getAllMeets(){
  return MySql.query(`SELECT * FROM wp_posts WHERE post_type = 'meet'`)
    .then(results=>Meet.fromObjArray(results.results));
}

function getUpcomingMeets(){
  return MySql.query(`
    SELECT meta_value AS meet_start_time, wp_posts.*
    FROM wp_postmeta LEFT JOIN wp_posts ON post_id=ID
    WHERE meta_key = 'meet_start_time'
    AND post_type = 'meet'
    AND post_status = 'publish'
    AND CAST(meta_value AS DATE) >= CURDATE();
  `).then(results=>Meet.fromObjArray(results.results));
}

module.exports = {getAllMeets,getUpcomingMeets};

Fix `/upcoming` getting drafts and unpulished meets


/**
 * Add targets -> node -> current as per this comment https://github.com/babel/babel/issues/5085#issuecomment-363242788
 */
module.exports = {
    env: {
        test: {
            presets: [
                [
                    '@babel/preset-env',
                    {
                        targets: {
                            node: 'current'
                        }
                    }
                ],
                '@babel/preset-react'
            ],
            plugins: [
                '@babel/plugin-syntax-dynamic-import',
                '@babel/plugin-proposal-class-properties',
                'dynamic-import-node'
            ]
        },
        production: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: [
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-syntax-dynamic-import'
            ]
        },
        development: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: [
                '@babel/plugin-proposal-class-properties',
                '@babel/plugin-syntax-dynamic-import',
            ]
        }
    }
};

/**
 * WSO2 NOTES:
 * Add targets -> node -> current for test config
 *      as per this comment https://github.com/babel/babel/issues/5085#issuecomment-363242788
 * Add minimum browser compatibility for production builds as per https://babeljs.io/docs/en/babel-preset-env#targets
 *      Related github issue: https://github.com/wso2/product-apim/issues/2661
 */
module.exports = {
    env: {
        test: {
            presets: [
                [
                    '@babel/preset-env',
                    {
                        targets: {
                            node: 'current',
                        },
                    },
                ],
                '@babel/preset-react',
            ],
            plugins: [
                '@babel/plugin-syntax-dynamic-import',
                '@babel/plugin-proposal-class-properties',
                'dynamic-import-node',
            ],
        },
        production: {
            presets: [
                [
                    '@babel/preset-env',
                    {
                        targets: {
                            chrome: '58',
                            ie: '11',
                        },
                    },
                ],
                '@babel/preset-react',
            ],
            plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-syntax-dynamic-import'],
        },
        development: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: ['@babel/plugin-proposal-class-properties', '@babel/plugin-syntax-dynamic-import'],
        },
    },
};

Add minimum target browser versions


function tryMe() {
  if (document.getElementsByClassName("_48e9").length < 1) {
    window.requestAnimationFrame(tryMe);
  } else {
    startBlock();
  }
}
tryMe();

function startBlock() {
  chrome.storage.sync.get("blind_messenger", function(data) {
  if (data["blind_messenger"]) {
      chrome.storage.sync.get("blind_names", function(data) {
        var list = document.getElementsByClassName("_48e9")[0].getElementsByClassName("_2il3");
        data = data["blind_names"].map(function(ob) {return ob.toLowerCase()});
        var data_href;
        var i;
        var j;
        for (i=0; i < data.length; i++) {
          for (j=0; j < list.length; j++) {
            data_href = list[j].getAttribute("data-href").toLowerCase();
            if (data_href === "https://www.messenger.com/t/" + data[i] ||
                data_href === "http://www.messenger.com/t/" + data[i]) {
              list[j].parentElement.parentElement.remove();
              break;
            }
          }
        }
      });
    }
  });
}

function startBlock() {
  "use strict";
  chrome.storage.sync.get("blind_messenger", function(data) {
    if (data["blind_messenger"]) {
      chrome.storage.sync.get("blind_names", function(data) {
        var list = document.getElementsByClassName("_4sp8")[0].getElementsByClassName("_2il3");
        data = data["blind_names"].map(function(ob) { return ob.toLowerCase(); });
        var chatList = document.querySelector("._3rh8 + div");

        var obr = new MutationObserver(function(mutation) {
            var i;
            var j;
            var data_href;
            for (i=0; i < data.length; i++) {
              for (j=0; j < list.length; j++) {
                data_href = list[j].getAttribute("data-href").toLowerCase();
                if (data_href === "https://www.messenger.com/t/" + data[i] ||
                    data_href === "http://www.messenger.com/t/" + data[i]) {
                  list[j].parentElement.parentElement.remove();
                  break;
                }
              }
          }
        });

        var config = { attributes: true, childList: true };
        obr.observe(chatList, config);
      });
    }
  });
}

function tryMe() {
  if (document.getElementsByClassName("_4sp8").length < 1) {
    window.requestAnimationFrame(tryMe);
  } else {
    startBlock();
  }
}
tryMe();

Fix reloading bug with MutationObserver


#!/usr/bin/env node

"use strict";

var path = require("path");
var fs = require("fs");

var commander = require("commander");

var libPath = path.join(path.dirname(fs.realpathSync(__filename)), "../lib/main.js");
var lib = require(libPath);

function collect(o, a) { a.push(o); return a; }

var packageJson = require("../package.json");

commander.description("CloudFormation Pre-Processor").version(packageJson.version)
.option("-r --region [region-name]", "AWS region. [eu-west-1]", "eu-west-1")
.option("-d --working-directory [working-directory]", "Working directory. [current working directory]")
.option("-f --config-file-pattern [config-file-pattern]", "Config file pattern. [*.cfnpp]", collect, [ ])
.option("-c --compact", "Compact template. [true]")
.option("-e --processed-template-extension [extension]", "Processed template extension. If blank, overwrites template. []", "")
.parse(process.argv);

console.log(commander.description() + " " + commander.version());

lib(commander.region, commander.configFilePattern, commander.workingDirectory, commander.compact, commander.processedTemplateExtension);

#!/usr/bin/env node

"use strict";

var path = require("path");
var fs = require("fs");

var commander = require("commander");

var libPath = path.join(path.dirname(fs.realpathSync(__filename)), "../lib/main.js");
var lib = require(libPath);

function collect(o, a) { a.push(o); return a; }

var packageJson = require("../package.json");

commander.description("CloudFormation Pre-Processor").version(packageJson.version)
.option("-r --region [region-name]", "AWS region. [eu-west-1]", "eu-west-1")
.option("-d --working-directory [working-directory]", "Working directory. [current working directory]")
.option("-f --config-file-pattern [config-file-pattern]", "Config file pattern. [*.cfnpp]", collect, [ ])
.option("-c --compact", "Compact template. [true]")
.option("-e --processed-template-extension [extension]", "Processed template extension. If blank, overwrites template. []", "")
.parse(process.argv);

console.log(commander.description() + " " + commander.version());

lib(commander.region,
	commander.configFilePattern,
	commander.workingDirectory,
	commander.compact,
	commander.processedTemplateExtension,
	function(err) {
		console.log("Done!");
	});

Add callback to call to process


const createConfig = (api) => {
  api.cache.never();
  return {
    presets: [
      '@babel/preset-react',
      [
        '@babel/env',
        {
          modules: false,
          loose: true,
          useBuiltIns: false,
          targets: {
            browsers: [
              'last 2 Chrome versions',
              'last 2 Firefox versions',
              'last 1 Safari versions',
              'last 1 ChromeAndroid versions',
              'last 1 Edge versions',
            ],
          },
        },
      ],
    ],
    plugins: ['@babel/syntax-dynamic-import'],
  };
};

module.exports = createConfig;

const createConfig = (api) => {
  api.cache.never();
  return {
    presets: [
      '@babel/preset-react',
      [
        '@babel/env',
        {
          modules: false,
          useBuiltIns: false,
          targets: {
            browsers: [
              'last 2 Chrome versions',
              'last 2 Firefox versions',
              'last 1 Safari versions',
              'last 1 ChromeAndroid versions',
              'last 1 Edge versions',
            ],
          },
        },
      ],
    ],
    plugins: ['@babel/syntax-dynamic-import'],
  };
};

module.exports = createConfig;

Remove loose mode from babel


/*!
 * JS-Tricks main script
 */

(function (w, d) {
  // Touch detection ( ͡ᵔ ͜ʖ ͡ᵔ)
  // @see http://localhost:8080/detect-touch-devices-using-javascript
  if('ontouchstart' in window) {
    var htmlEl = d.getElementsByTagName('html')[0];
    var htmlElClasses = htmlEl.className;
    htmlEl.className += (htmlElClasses.length ? ' ' : '') + 'touch';
  }

  // Add "language-*" classes to <pre> elements
  d.addEventListener('DOMContentLoaded', function () {
    Array.prototype.forEach.call(d.querySelectorAll('pre > code'), function (node) {
      var parentNode = node.parentNode;
      var nodeClasses = node.className.split(' ');
      for (var i = 0; i < nodeClasses.length; i++) {
        if (nodeClasses[i].match(/^language-/)) {
          // Native IE9 support for ClassList would be a dream here...
          var parentNodeClassName = parentNode.className;
          parentNode.className += (parentNodeClassName.length ? ' ' : '') + nodeClasses[i];
          break;
        }
      }
    });
  });
})(window, document);

/*!
 * JS-Tricks main script
 */

(function (w, d) {
  // Touch detection ( ͡ᵔ ͜ʖ ͡ᵔ)
  // @see http://js-tricks.com/detect-touch-devices-using-javascript
  if('ontouchstart' in window) {
    var htmlEl = d.getElementsByTagName('html')[0];
    var htmlElClasses = htmlEl.className;
    htmlEl.className += (htmlElClasses.length ? ' ' : '') + 'touch';
  }

  // Add "language-*" classes to <pre> elements
  d.addEventListener('DOMContentLoaded', function () {
    Array.prototype.forEach.call(d.querySelectorAll('pre > code'), function (node) {
      var parentNode = node.parentNode;
      var nodeClasses = node.className.split(' ');
      for (var i = 0; i < nodeClasses.length; i++) {
        if (nodeClasses[i].match(/^language-/)) {
          // Native IE9 support for ClassList would be a dream here...
          var parentNodeClassName = parentNode.className;
          parentNode.className += (parentNodeClassName.length ? ' ' : '') + nodeClasses[i];
          break;
        }
      }
    });
  });
})(window, document);

Fix wrong link in JS sources


import {subscribe, getTodo} from '../todo'
import renderGraph from './render'

let graphArea
const unsubscribe = {
  store: null,
  todo: null,
}

export default toggleGraph

function toggleGraph() {
  if (graphArea) {
    graphArea.remove()
    graphArea = null
    unsubscribe.store()
    unsubscribe.todo()
    return false
  } else {
    graphArea = document.createElement('div')
    document.body.querySelector('.graph-area-container').appendChild(graphArea)
    const {storage} = getTodo()
    renderGraph(graphArea, storage)
    updateTodoSubscription()
    updateStoreSubscription(storage)
    return true
  }
}

function updateTodoSubscription() {
  if (unsubscribe.todo) {
    unsubscribe.todo()
  }
  unsubscribe.todo = subscribe(function onTodoUpdate() {
    const {storage} = getTodo()
    updateStoreSubscription(storage)
    renderGraph(graphArea, storage)
  })
}

function updateStoreSubscription(store) {
  if (unsubscribe.store) {
    unsubscribe.store()
  }
  unsubscribe.store = store.subscribe(function onStoreUpdate() {
    renderGraph(graphArea, store)
  })
}

import {subscribe, getTodo} from '../todo'

let graphArea
const unsubscribe = {
  store: null,
  todo: null,
}

export default toggleGraph

function toggleGraph() {
  if (graphArea) {
    graphArea.remove()
    graphArea = null
    unsubscribe.store()
    unsubscribe.todo()
    return false
  } else {
    graphArea = document.createElement('div')
    document.body.querySelector('.graph-area-container').appendChild(graphArea)
    const {storage} = getTodo()
    loadAndRenderGraph(graphArea, storage)
    updateTodoSubscription()
    updateStoreSubscription(storage)
    return true
  }
}

function updateTodoSubscription() {
  if (unsubscribe.todo) {
    unsubscribe.todo()
  }
  unsubscribe.todo = subscribe(function onTodoUpdate() {
    const {storage} = getTodo()
    updateStoreSubscription(storage)
    loadAndRenderGraph(graphArea, storage)
  })
}

function updateStoreSubscription(store) {
  if (unsubscribe.store) {
    unsubscribe.store()
  }
  unsubscribe.store = store.subscribe(function onStoreUpdate() {
    loadAndRenderGraph(graphArea, store)
  })
}

function loadAndRenderGraph (graphArea, store) {
  System.import('./render').then(renderGraphComponent => {
    const renderGraph = renderGraphComponent.default
    renderGraph(graphArea, store)
  })
}

Use system import for code splitting


const renders = require('../test/renders');
const pretty = require('pretty');
import assert from 'power-assert';

const AllComponents = require('../lib/components').default;
const templates = require('../lib/templates').default;

describe('Rendering Tests', () => {
  Object.keys(templates).forEach(framework => {
    describe(`Framework ${framework}`, () => {
      Object.keys(AllComponents).forEach(component => {
        describe(`Component ${component}`, () => {
          it(`Renders ${component} for ${framework}`, (done) => {
            const instance = new AllComponents[component]();
            instance.id = 'abc123';
            assert.equal(renders[`${framework}-${component}`], pretty(instance.render()));
            done();
          });
          it(`Renders ${component} for ${framework} as required`, (done) => {
            const instance = new AllComponents[component]({
              validate: {
                required: true
              }
            });
            instance.id = 'abc123';
            assert.equal(renders[`${framework}-${component}-required`], pretty(instance.render()));
            done();
          });
          it(`Renders ${component} for ${framework} as multiple`, (done) => {
            const instance = new AllComponents[component]({
              multiple: true
            });
            instance.id = 'abc123';
            console.log(renders[`${framework}-${component}-multiple`], pretty(instance.render()));
            assert.equal(renders[`${framework}-${component}-multiple`], pretty(instance.render()));
            done();
          });
        });
      });
    });
  });
});

const renders = require('../test/renders');
const pretty = require('pretty');
import assert from 'power-assert';

const AllComponents = require('../lib/components').default;
const templates = require('../lib/templates').default;

describe('Rendering Tests', () => {
  Object.keys(templates).forEach(framework => {
    describe(`Framework ${framework}`, () => {
      Object.keys(AllComponents).forEach(component => {
        describe(`Component ${component}`, () => {
          it(`Renders ${component} for ${framework}`, (done) => {
            const instance = new AllComponents[component]();
            instance.id = 'abc123';
            assert.equal(renders[`component-${framework}-${component}`], pretty(instance.render()));
            done();
          });
          it(`Renders ${component} for ${framework} as required`, (done) => {
            const instance = new AllComponents[component]({
              validate: {
                required: true
              }
            });
            instance.id = 'abc123';
            assert.equal(renders[`component-${framework}-${component}-required`], pretty(instance.render()));
            done();
          });
          it(`Renders ${component} for ${framework} as multiple`, (done) => {
            const instance = new AllComponents[component]({
              multiple: true
            });
            instance.id = 'abc123';
            assert.equal(renders[`component-${framework}-${component}-multiple`], pretty(instance.render()));
            done();
          });
        });
      });
    });
  });
});

Update tests to match new render names.


import React from 'react'
import { Route, IndexRoute } from 'react-router'

import App from './app'

import VehicleLoader from './utilities/vehicle-loader'
import VehicleListContainer from './vehicle-list/container'
import VehicleContainer from './vehicle/container'

import UserEditor from './user-editor/editor'

import { requireAuthentication } from './profile/authentication'

export default (
  <Route path="/" component={App}>
    <IndexRoute component={VehicleListContainer} />

    <Route path="vehicles" component={VehicleLoader}>
      <Route path=":id" component={requireAuthentication(VehicleContainer)} />
      <IndexRoute component={VehicleListContainer} />
    </Route>

    <Route path="profile" component={requireAuthentication(UserEditor)} />
    <Route path="register" component={UserEditor} />
    <Route path="password" component={requireAuthentication(UserEditor)} />
  </Route>
)

import React from 'react'
import { Route, IndexRoute } from 'react-router'

import App from './app'

import VehicleLoader from './utilities/vehicle-loader'
import VehicleListContainer from './vehicle-list/container'
import VehicleContainer from './vehicle/container'

import UserEditor from './user-editor/editor'

import { requireAuthentication } from './profile/authentication'

export default (
  <Route path="/" component={App}>
    <Route component={VehicleLoader}>
      <IndexRoute component={VehicleListContainer} />
    </Route>

    <Route path="vehicles" component={VehicleLoader}>
      <Route path=":id" component={requireAuthentication(VehicleContainer)} />
      <IndexRoute component={VehicleListContainer} />
    </Route>

    <Route path="profile" component={requireAuthentication(UserEditor)} />
    <Route path="register" component={UserEditor} />
    <Route path="password" component={requireAuthentication(UserEditor)} />
  </Route>
)

Index route needs a vehicle loader as well


// Generated by CoffeeScript 1.10.0
(function() {
  $("blockquote").each((function(_this) {
    return function(i, element) {
      var contents;
      contents = $(element).contents();
      console.log(contents);
      contents.insertAfter($(element));
      return $(element).remove();
    };
  })(this));

}).call(this);

function filterF(i, el) {
  var pattern = /(From|To|Subject|Cc|Date):/i;
  return el.textContent.match(pattern);
}

$($("blockquote").get().reverse()).each(function(i, el) {
  var contents = $(el).contents();
  var matches = contents.find("*").filter(filterF).get().reverse();

  while (matches.length > 0) {
    matches[0].remove();
    matches = contents.find("*").filter(filterF).get().reverse();
  }

  // remove blockquotes but preserve contents
  contents.insertAfter($(el));
  $(el).remove();
});

Remove (From|To|Subject|Cc|Date) from the trace


'use strict';

require('dotenv').config({ path: __dirname + '/.env', silent: true });

// load deps
const lab = exports.lab = require('lab').script();
const chai = require('chai');

// chai plugins
chai.use(require('chai-things'));

global.expect = chai.expect;

// prepare environment
global. it = lab.it;
global.describe = lab.describe;
global.before = lab.before;
global.beforeEach = lab.beforeEach;

// get the server
global.server = require('../src/core/server');
global.db = global.server.database;

'use strict';

require('dotenv').config({ path: __dirname + '/.env', silent: true });

// load deps
const lab = exports.lab = require('lab').script();
const chai = require('chai');

// chai plugins
chai.use(require('chai-things'));

global.expect = chai.expect;

// prepare environment
global. it = lab.it;
global.describe = lab.describe;
global.before = lab.before;
global.beforeEach = lab.beforeEach;

// get the server
global.before((done) => {
  require('../src/core/bootstrap').start()
  .then(() => {
    global.server = require('../src/core/server');
    global.db = global.server.database;
    return done();
  });
});

Update tests for new bootstrap


// Mixin ############################################################################

/**
 * Mix a key-value into Storm, protecting Storm from
 * having a pre-existing key overwritten. Of course,
 * items can be directly assigned to Storm via Storm.foo = foo;
 * but in this framework, I'm considering it a bad practice
 * @param  {String} name
 * @param  {Value} prop
 * @private
 */
var _mixin = function(name, prop) {
	if (Storm[name] !== undefined) { return console.error(_errorMessage('mixin', 'Cannot mixin. "'+ name +'" already exists: '), name, Storm[name], prop); }
	Storm[name] = prop;
};

/**
 * Protect Storm from mixins that would overwrite pre-existing keys.
 * @param  {String||Object} name Name of the object
 * @param  {Object}         prop The object to mixin
 */
Storm.mixin = function(name, prop) {
	// Mix single
	if (_.isString(name)) {
		_mixin(name, prop);
	}

	// Mix multiple
	var key;
	for (key in name) {
		_mixin(key, name[key]);
	}
};

// Mixin ############################################################################

/**
 * Mix a key-value into Storm, protecting Storm from
 * having a pre-existing key overwritten. Of course,
 * items can be directly assigned to Storm via Storm.foo = foo;
 * but in this framework, I'm considering it a bad practice
 * @param  {String} name
 * @param  {Value} prop
 * @private
 */
var _mixin = function(name, prop) {
	if (Storm[name] !== undefined) { return console.error(_errorMessage('mixin', 'Cannot mixin. "'+ name +'" already exists: '), name, Storm[name], prop); }
	Storm[name] = prop;
};

/**
 * Protect Storm from mixins that would overwrite pre-existing keys.
 * @param  {String||Object} name Name of the object
 * @param  {Object}         prop The object to mixin
 */
Storm.mixin = function(name, prop) {
	// Mix single
	if (_.isString(name)) {
		return _mixin(name, prop);
	}

	// Mix multiple
	var key;
	for (key in name) {
		_mixin(key, name[key]);
	}
};

Stop mixing in each letter of strings


import get from 'lodash.get';
import isFunction from 'lodash.isfunction';

export function combineReducers(stateReducerMap, rootPath) {
  return function(state, action) {
    let changed = false;

    const nextState = {};
    Object.entries(stateReducerMap).forEach(([path, module]) => {
      const fullPath = rootPath ? `${rootPath}.${path}` : path;
      const ownState = get(state, path);

      if (isFunction(module.integrator)) {
        nextState[path] = module.integrator(fullPath)(ownState, action, fullPath);
      } else {
        nextState[path] = module(ownState, action, fullPath);
      }

      if (nextState[path] !== get(state, path)) {
        changed = true;
      }
    });

    return changed ? nextState : state;
  };
}

export function isString(str) {
  return typeof str === 'string';
}

import get from 'lodash.get';
import isFunction from 'lodash.isfunction';

export function combineReducers(stateReducerMap, rootPath) {
  return function(state, action) {
    let changed = false;

    const nextState = {};
    Object.entries(stateReducerMap).forEach(([path, module]) => {
      const fullPath = rootPath ? [rootPath, path] : path;
      const ownState = get(state, path);

      if (isFunction(module.integrator)) {
        nextState[path] = module.integrator(fullPath)(ownState, action, fullPath);
      } else {
        nextState[path] = module(ownState, action, fullPath);
      }

      if (nextState[path] !== get(state, path)) {
        changed = true;
      }
    });

    return changed ? nextState : state;
  };
}

export function isString(str) {
  return typeof str === 'string';
}

Fix the way the combineReducer handles paths.


if (! window._babelPolyfill) {
  require("babel-polyfill");
}

import reducers from './reducers';
import sagas from './sagas';
import {
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource
} from './actions';
import {
  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
} from './selectors';

export {
  reducers,
  sagas,
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource,

  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
};

if (! window._babelPolyfill) {
  require("babel-polyfill");
}

import reducers from './reducers';
import sagas from './sagas';
import {
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource,
  clearPagination
} from './actions';
import {
  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
} from './selectors';

export {
  reducers,
  sagas,
  getResource,
  listResource,
  allResource,
  updateResource,
  createResource,
  deleteResource,

  selectItem,
  selectPage,
  selectCurrentPage,
  selectAllPages,
  selectPagination,
  selectAll
};

Add `clearPagination` to package exports


#!/usr/bin/env node

import fs from 'fs'
import path from 'path'
import postcss from 'postcss'
import defaultConfig from './defaultConfig'
import program from 'commander'
import tailwind from './tailwind'

let splitFileName = filename => {
  return filename.split('.')
}

program
  .version('0.1.0')
  .usage('[options] <file ...>')
  .option('-c, --config [value]', 'Pass custom configuration')
  .parse(process.argv)

let inputFile = program.args[0]
let outputFile =
  program.args[1] || `${splitFileName(program.args[0])[0]}-output.css`

if (!inputFile) {
  console.error('No input file given!')
  process.exit(1)
}

fs.readFile(path.join(program.config), (err, config) => {
  if (err) {
    console.error(`config file ${program.config} does not exist`)
    process.exit(1)
  }

  const customConfig = JSON.parse(config.toString())

  let finalConfig = {
    ...defaultConfig,
    ...customConfig,
  }

  console.log('Building Tailwind!')

  fs.readFile(inputFile, (err, css) => {
    postcss([tailwind(finalConfig)])
      .process(css)
      .then(result => {
        fs.writeFileSync(outputFile, result.css)
      })
      .catch(error => console.log(error))
  })

  console.log('Finished building Tailwind!')
})

#!/usr/bin/env node

import fs from 'fs'
import path from 'path'
import postcss from 'postcss'
import defaultConfig from './defaultConfig'
import program from 'commander'
import tailwind from './tailwind'

let splitFileName = filename => {
  return filename.split('.')
}

program
  .version('0.1.0')
  .usage('[options] <file ...>')
  .option('-c, --config [value]', 'Pass custom configuration')
  .parse(process.argv)

let inputFile = program.args[0]

if (!inputFile) {
  console.error('No input file given!')
  process.exit(1)
}

let outputFile =
  program.args[1] || `${splitFileName(program.args[0])[0]}-output.css`

fs.readFile(path.join(program.config), (err, config) => {
  if (err) {
    console.error(`config file ${program.config} does not exist`)
    process.exit(1)
  }

  const customConfig = JSON.parse(config.toString())

  let finalConfig = {
    ...defaultConfig,
    ...customConfig,
  }

  console.log('Building Tailwind!')

  fs.readFile(inputFile, (err, css) => {
    postcss([tailwind(finalConfig)])
      .process(css)
      .then(result => {
        fs.writeFileSync(outputFile, result.css)
      })
      .catch(error => console.log(error))
  })

  console.log('Finished building Tailwind!')
})

Check for input file before trying to use


'use strict';

module.exports = {
  deref: deref
};

function deref (pointer, doc) {
  const segments = compact(pointer.split('/'));

  if(segments.length === 0) {
    return doc;
  }

  let context = doc;
  segments.forEach((segment) => { context = context[segment]; });
  return context;
}

function compact (collection) {
  return collection.filter((item) => item);
}

'use strict';

module.exports = {
  deref: deref
};

// TODO put the doc first
function deref (pointer, doc) {
  const segments = compact(pointer.split('/'));
  return traverse(doc, segments);
}

function traverse (doc, segments) {
  if(!segments.length) return doc;

  return traverse(doc[first(segments)], segments.slice(1));
}

function compact (collection) {
  return collection.filter((item) => item);
}

function first (arr) {
  return arr[0];
}

Use recursive function for traversal - babel will transform to a linear iterative process