var _ = require('lodash');

exports.formatNumber = function(dialect) {
  return {
    mysql: _.identity,
    sqlite3: _.identity,
    postgresql: function(count) { return count.toString() }
  }[dialect];
}

exports.countModels = function countModels(Model, options) {
  return function() {
    return Model.forge().count(options).then(function(count) {
      if (typeof count === 'string') return parseInt(count);
      return count;
    });
  }
}

exports.sort = function sort(model) {
  var sorted = {}

  for (var attribute in model) {
    sorted[attribute] = this.sortCollection(model[attribute])
  }

  return sorted
}

exports.sortCollection = function sortCollection(collection) {
  if (!Array.isArray(collection)) return collection

  collection.sort(function(model1, model2) {
    return model1.id - model2.id
  })

  return collection.map(this.sort, exports)
}

Add sort and sortCollection test helper methods


var
	extend            = req('/lib/utilities/extend'),
	ReplyMessage      = req('/lib/messages/reply'),
	Replies           = req('/lib/constants/replies'),
	NotOnChannelError = req('/lib/errors/not-on-channel');

class NotOnChannelMessage extends ReplyMessage {

	getValuesForParameters() {
		return {
			channel_name: this.getChannelName()
		};
	}

	setValuesFromParameters(parameters) {
		this.setChannelName(parameters.get('channel_name'));
	}

	toError() {
		return new NotOnChannelError(this.getChannelName());
	}

}

extend(NotOnChannelMessage.prototype, {
	reply: Replies.ERR_NOTONCHANNEL,
	abnf:  '<channel-name> " :You\'re not on that channel"'
});

module.exports = NotOnChannelMessage;

var
	extend            = req('/lib/utilities/extend'),
	ReplyMessage      = req('/lib/messages/reply'),
	Replies           = req('/lib/constants/replies'),
	NotOnChannelError = req('/lib/errors/not-on-channel');

class NotOnChannelMessage extends ReplyMessage {

	setChannelName(channel_name) {
		this.channel_name = channel_name;
		return this;
	}

	getChannelName() {
		return this.channel_name;
	}

	getValuesForParameters() {
		return {
			channel_name: this.getChannelName()
		};
	}

	setValuesFromParameters(parameters) {
		this.setChannelName(parameters.get('channel_name'));
	}

	toError() {
		return new NotOnChannelError(this.getChannelName());
	}

}

extend(NotOnChannelMessage.prototype, {
	reply:        Replies.ERR_NOTONCHANNEL,
	abnf:         '<channel-name> " :You\'re not on that channel"',
	channel_name: null
});

module.exports = NotOnChannelMessage;

Allow setting channel name parameter on ERR_NOTONCHANNEL


// XXX autopublish warning is printed on each restart. super spammy!

Meteor.publish("directory", function () {
  // XXX too easy to accidentally publish the list of validation tokens
  return Meteor.users.find({}, {fields: {"emails.address": 1}});
});

Meteor.publish("parties", function () {
  return Parties.find(
    {$or: [{"public": true}, {invited: this.userId}, {owner: this.userId}]});
});

// XXX autopublish warning is printed on each restart. super spammy!

Meteor.publish("directory", function () {
  return Meteor.users.find({}, {fields: {emails: 1}});
});

Meteor.publish("parties", function () {
  return Parties.find(
    {$or: [{"public": true}, {invited: this.userId}, {owner: this.userId}]});
});

Remove addressed XXX comment: verification tokens are now separate.


'use strict';

const { waterfall, mapSeries } = require('async');
const logger = require('../../lib/logger');

module.exports = function createPreviewRelease(getConfig, getReleasePreview, notify, repos) {

  return ({ verbose = false }, cb) => {
    waterfall([
      (next)            => getConfigForEachRepo(repos, next),
      (reposInfo, next) => getReleasePreview(reposInfo, next),
      (reposInfo, next) => notifyPreviewInSlack(reposInfo, verbose, next)
    ], cb);
  };

  function getConfigForEachRepo(repos, cb) {
    mapSeries(repos, (repo, nextRepo) => {
      getConfig(repo, (err, config) => {
        if (err) {
          logger.error('Error getting repo config', repo, err);
          return nextRepo(null, { repo, failReason: 'INVALID_REPO_CONFIG' });
        }
        nextRepo(null, { repo, config });
      });
    }, cb);
  }

  function notifyPreviewInSlack(reposInfo, verbose, cb) {
    notify(reposInfo, 'preview', verbose, cb);
  }
};

'use strict';

const { waterfall, mapSeries } = require('async');
const logger = require('../../lib/logger');

module.exports = function createPreviewRelease(getConfig, getReleasePreview, notify, repos) {

  return ({ verbose = false }, cb) => {
    waterfall([
      (next)            => getConfigForEachRepo(repos, next),
      (reposInfo, next) => getReleasePreview(reposInfo, next),
      (reposInfo, next) => notifyPreviewInSlack(reposInfo, verbose, next)
    ], cb);
  };

  function getConfigForEachRepo(repos, cb) {
    logger.debug('getConfigForEachRepo', { repos });
    mapSeries(repos, (repo, nextRepo) => {
      getConfig(repo, (err, config) => {
        if (err) {
          logger.error('Error getting repo config', repo, err);
          return nextRepo(null, { repo, failReason: 'INVALID_REPO_CONFIG' });
        }
        nextRepo(null, { repo, config });
      });
    }, cb);
  }

  function notifyPreviewInSlack(reposInfo, verbose, cb) {
    logger.debug('notifyPreviewInSlack', { reposInfo, verbose });
    notify(reposInfo, 'preview', verbose, cb);
  }
};

Add debug logs to preview release


function onDownloadFinished(duration)
{
    console.log("Finished download in: " + duration + "ms");
    initGame();
    initDebugger();
}

/*
 * Called on a resource download finish
 * Params :
 *  downloadedAmount : Amount of resource downloaded
 *  totalAmount      : Total amount resource to download
 */
function onDownloadUpdate(downloadedAmount, totalAmount)
{
    console.log("Downloaded file : " + downloadedAmount + " / " + totalAmount + "(" + parseInt((downloadedAmount / totalAmount) * 100) + "%)");
}

/*
 * Called on a resource download error
 * Params :
 *  error : Error returned by JQuery
 */
function onDownloadError(error)
{
    console.error("Failed to download resources :");
    console.error(error);
}

// Game Start
$(function()
{
    console.log("Game Starting...");
    console.log("Download game resources...");
    ResourceLoader.downloadGameResources(onDownloadFinished, onDownloadUpdate, onDownloadError);
    initGame();
    initDebugger();
});

function onDownloadFinished(duration)
{
    console.log("Finished download in: " + duration + "ms");
    initGame();
    initDebugger();
}

/*
 * Called on a resource download finish
 * Params :
 *  downloadedAmount : Amount of resource downloaded
 *  totalAmount      : Total amount resource to download
 */
function onDownloadUpdate(downloadedAmount, totalAmount)
{
    console.log("Downloaded file : " + downloadedAmount + " / " + totalAmount + "(" + parseInt((downloadedAmount / totalAmount) * 100) + "%)");
}

/*
 * Called on a resource download error
 * Params :
 *  error : Error returned by JQuery
 */
function onDownloadError(error)
{
    console.error("Failed to download resources :");
    console.error(error);
}

// Game Start
$(function()
{
    console.log("Game Starting...");
    console.log("Download game resources...");
    ResourceLoader.downloadGameResources(onDownloadFinished, onDownloadUpdate, onDownloadError);
});

Fix double call to map rendering and debugger


(function() {
  module('gpub.spec.preprocess');

  test('Preprocess grouping', function() {
    var cache = new gpub.util.MoveTreeCache();
    var sgf = '(;GM[1]AW[aa]AB[ba];B[bb]C[The End!])';
    var o = new gpub.Options({
      sgfs: [sgf],
      ids: ['z1'],
      grouping: {
        title: 'foo',
        description: 'bar',
        positionType: 'PROBLEM',
        positions: [
          'z1',
        ],
      }
    }, cache);
    var spec = gpub.spec.create(o);
    var gr = spec.rootGrouping;
    deepEqual(gr.title, o.grouping.title, 'title');
    deepEqual(gr.description, o.grouping.description, 'description');
    deepEqual(gr.positionType, o.grouping.positionType, 'description');
  })
})();

(function() {
  module('gpub.spec.preprocess');

  test('Preprocess grouping', function() {
    var cache = new gpub.util.MoveTreeCache();
    var sgf = '(;GM[1]AW[aa]AB[ba];B[bb]C[The End!])';
    var o = new gpub.Options({
      sgfs: [sgf],
      ids: ['z1'],
      grouping: {
        title: 'foo',
        description: 'bar',
        positionType: 'PROBLEM',
        positions: [
          'z1',
        ],
      }
    }, cache);
    var spec = gpub.spec.create(o);
    var gr = spec.rootGrouping;
    deepEqual(gr.title, o.grouping.title, 'title');
    deepEqual(gr.description, o.grouping.description, 'description');
    deepEqual(gr.positionType, o.grouping.positionType, 'description');
  })

  test('Preprocess grouping', function() {
    var cache = new gpub.util.MoveTreeCache();
    var sgf = '(;GM[1]AW[aa]AB[ba];B[bb]C[The End!])';
    var o = new gpub.Options({
      sgfs: [sgf, sgf],
      ids: ['z1', 'z2'],
      grouping: {
        title: 'foo',
        description: 'bar',
        positionType: 'PROBLEM',
        positions: [ 'z1' ],
        groupings: [{
          title: 'bar',
          positions: [ 'z1' ],
        }, {
          title: 'biff',
          positions: [ 'z2' ],
        }]
      }
    }, cache);
    var spec = gpub.spec.create(o);
    var gr = spec.rootGrouping;
    deepEqual(gr.title, o.grouping.title, 'title');
    deepEqual(gr.description, o.grouping.description, 'description');
    deepEqual(gr.positionType, o.grouping.positionType, 'description');

    deepEqual(gr.groupings.length, 2);
    deepEqual(gr.groupings[0].title, 'bar');
    deepEqual(gr.groupings[0].positions[0].alias, 'z1');
    deepEqual(gr.groupings[1].title, 'biff');
    deepEqual(gr.groupings[1].positions[0].alias, 'z2');
  })
})();

Add a test for pre-processing nested structures.


define(['jquery'], function ($) {
    var colors = {
        log: '#000000',
        warn: '#cc9900',
        error: '#cc0000'
    };

    var log = $('#log');

    if (!console) {
        console = {};
    }
    for (var name in colors) {
        console[name] = (function (original, color) {
            return function () {
                original.apply(console, arguments);

                var line = $('<div>');
                log.append(line);
                for (var i = 0; i < arguments.length; i++) {
                    var section = $('<span>');
                    section.text(arguments[i]);
                    line.append(section);
                    line.css('color', color);
                }
            };
        })(console[name] || function() {}, colors[name]);
    }
    return console;
});

define(['jquery'], function ($) {
    var stringify = function (x) {
        try {
            if (typeof x != 'object'
                || x instanceof String
                || x instanceof Number) {
                return x.toString();
            }

            if (x instanceof Array) {
                return '[' +
                    x.map(stringify).join(', ') +
                    ']';
            }

            if (x.length
                && x.length >= 0
                && x.length == Math.floor(x.length)) {
                return stringify(Array.prototype.slice.call(x));
            }

            if (x instanceof HTMLElement) {
                return '<' + x.tagName + ' ...>';
            }

            return x.toString();
        } catch (e) {
            return '' + x;
        }
    };

    var colors = {
        log: '#000000',
        warn: '#cc9900',
        error: '#cc0000'
    };

    var log = $('#log');

    if (!console) {
        console = {};
    }
    for (var name in colors) {
        console[name] = (function (original, color) {
            return function () {
                original.apply(console, arguments);

                var line = $('<div>');
                log.append(line);
                for (var i = 0; i < arguments.length; i++) {
                    var section = $('<span>');
                    section.text(stringify(arguments[i]));
                    line.append(section);
                    line.css('color', color);
                }
            };
        })(console[name] || function() {}, colors[name]);
    }
    return console;
});

Convert arguments to text before writing them out.


/*
 * Copyright (c) 2016 Steven Soloff
 *
 * This is free software: you can redistribute it and/or modify it under the
 * terms of the MIT License (https://opensource.org/licenses/MIT).
 * This software comes with ABSOLUTELY NO WARRANTY.
 */

'use strict'

const linting = require('./support/test-util').linting
const source = require('./support/test-util').source

describe('Linting variable declarations', () => {
  it('should report a violation when var declarations are not first in function scope', () => {
    const text = source([
      'while (1) {',
      '    var foo = 1;',
      '    foo;',
      '}'
    ])
    expect(linting(text)).toReportViolationForRule('vars-on-top')
  })

  it('should not report a violation when var declarations are first in function scope', () => {
    const text = source([
      'var foo = 1;',
      'while (1) {',
      '    foo;',
      '}'
    ])
    expect(linting(text)).toNotReportViolation()
  })
})

/*
 * Copyright (c) 2016 Steven Soloff
 *
 * This is free software: you can redistribute it and/or modify it under the
 * terms of the MIT License (https://opensource.org/licenses/MIT).
 * This software comes with ABSOLUTELY NO WARRANTY.
 */

'use strict'

const linting = require('./support/test-util').linting
const source = require('./support/test-util').source

describe('Linting variable declarations', () => {
  it('should report a violation when var declarations are not first in scope', () => {
    const text = source([
      'while (1) {',
      '    var foo = 1;',
      '    foo;',
      '}'
    ])
    expect(linting(text)).toReportViolationForRule('vars-on-top')
  })

  it('should not report a violation when var declarations are first in scope', () => {
    const text = source([
      'var foo = 1;',
      'while (1) {',
      '    foo;',
      '}'
    ])
    expect(linting(text)).toNotReportViolation()
  })

  it('should not report a violation when multiple var declarations are used in same scope', () => {
    const text = source([
      'var foo = 1;',
      'var bar = 2;',
      'while (foo) {',
      '    bar;',
      '}'
    ])
    expect(linting(text)).toNotReportViolation()
  })
})

Allow multiple var declarations per scope


import socketio from 'socket.io-client'

import log from 'services/log'
import foodsharing from 'services/foodsharing'

export let io = null
export const subscribers = []

export default {

  /*
   * Subscribe to the websocket receive all messages
   * Returns an unsubscribe function
   */
  subscribe (fn) {
    subscribers.push(fn)
    return () => {
      let idx = subscribers.indexOf(fn)
      if (idx !== -1) subscribers.splice(idx, 1)
    }
  },

  /*
   * Connects to the socket.io socket if not already
   * Returns a promise that resolves when connected
   */
  connect () {
    if (io) return Promise.resolve()
    return new Promise((resolve, reject) => {
      io = socketio({ path: '/foodsharing/socket' })
      io.on('connect', () => {
        io.emit('register')
        log.info('connected to websocket!')
        resolve()
      })
      io.on('conv', data => {
        if (!data.o) return
        log.info('recv', data)
        let message = foodsharing.convertMessage(JSON.parse(data.o))
        subscribers.forEach(fn => fn(message))
      })
    })
  },

  /*
   * Disconnect from socket.io
   */
  disconnect () {
    if (!io) return
    io.disconnect()
    io = null
  }
}

import socketio from 'socket.io-client'

import log from 'services/log'
import foodsharing from 'services/foodsharing'

export let io = null
export const subscribers = []

export default {

  /*
   * Subscribe to the websocket receive all messages
   * Returns an unsubscribe function
   */
  subscribe (fn) {
    subscribers.push(fn)
    return () => {
      let idx = subscribers.indexOf(fn)
      if (idx !== -1) subscribers.splice(idx, 1)
    }
  },

  /*
   * Connects to the socket.io socket if not already
   * Returns a promise that resolves when connected
   */
  connect () {
    if (io) return Promise.resolve()
    return new Promise((resolve, reject) => {
      io = socketio({ path: '/foodsharing/socket' })
      io.on('connect', () => {
        io.emit('register')
        log.info('connected to websocket!')
        resolve()
      })
      io.on('conv', data => {
        if (!data.o) return
        let message = foodsharing.convertMessage(JSON.parse(data.o))
        subscribers.forEach(fn => fn(message))
      })
    })
  },

  /*
   * Disconnect from socket.io
   */
  disconnect () {
    if (!io) return
    io.disconnect()
    io = null
  }
}

Remove a bit of logging


var expect = require('chai').expect;
var validator = require('../');

describe('Image Validator', function() {
  var rules = {
    imageInput: ['image']
  };

  it('should fail on non image type', function() {
    var result = validator.validate(rules, {
      imageInput: 'README.md'
    });

    expect(result.success).to.equals(false);
    expect(result.messages.imageInput.image).to.equals('Image Input must be an image.');
  });

  it('should success on image type', function() {
    var result = validator.validate(rules, {
      imageInput: 'tests/fixtures/dummyimg.jpeg'
    });

    expect(result.success).to.equals(true);
  });
});

var expect = require('chai').expect;
var validator = require('../');

describe('Image Validator', function() {
  var rules = {
    imageInput: ['image']
  };

  it('should fail on non image type', function() {
    var result = validator.validate(rules, {
      imageInput: 'README.md'
    });

    expect(result.success).to.equals(false);
    expect(result.messages.imageInput.image).to.equals('Image Input must be an image.');
  });

  it('should success on image type', function() {
    var result = validator.validate(rules, {
      imageInput: 'tests/fixtures/dummyimg.jpeg'
    });

    expect(result.success).to.equals(true);
  });

  it('should fail on non image type (object input)', function() {
    var result = validator.validate(rules, {
      imageInput: {path: 'README.md'}
    });

    expect(result.success).to.equals(false);
    expect(result.messages.imageInput.image).to.equals('Image Input must be an image.');
  });

  it('should success on image type (object input)', function() {
    var result = validator.validate(rules, {
      imageInput: {path: 'tests/fixtures/dummyimg.jpeg'}
    });

    expect(result.success).to.equals(true);
  });
});

Add tests for object input (image rule)


Change it so / has the latest, greatest view.


'use strict';

GJS.Sprite.gfxPath = '../examples/assets/gfx/';

describe('Sprite', function() {
    it('can be used before it is loaded', function() {
        var s = new GJS.Sprite('carrot.png');
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        s.draw(ctx, 0, 0);
        s.drawRotated(ctx, 0, 0, 0);
        s.drawRotatedNonUniform(ctx, 0, 0, 0, 0, 0);
        expect(s.loaded).toBe(false);
    });
    it('maintains a counter of loaded objects', function() {
        var s;
        runs(function() {
            s = new GJS.Sprite('carrot.png');
            expect(GJS.Sprite.loadedFraction()).toBe(0);
        });
        waitsFor(function() { return s.loaded; });
        runs(function() {
            expect(GJS.Sprite.loadedFraction()).toBe(1);
        });
    });
});

'use strict';

GJS.Sprite.gfxPath = '../examples/assets/gfx/';

describe('Sprite', function() {
    it('maintains a counter of loaded objects', function() {
        var s;
        runs(function() {
            s = new GJS.Sprite('carrot.png');
            expect(GJS.Sprite.loadedFraction()).toBeLessThan(1);
        });
        waitsFor(function() { return s.loaded; });
        runs(function() {
            expect(GJS.Sprite.loadedFraction()).toBe(1);
        });
    });
    it('can be used before it is loaded', function() {
        var s = new GJS.Sprite('carrot.png');
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
        s.draw(ctx, 0, 0);
        s.drawRotated(ctx, 0, 0, 0);
        s.drawRotatedNonUniform(ctx, 0, 0, 0, 0, 0);
        expect(s.loaded).toBe(false);
    });
});

Make sprite unit tests more robust


var path = require('path');
var childProcess = require('child_process');

function gulp(task) {
  return childProcess.execSync([
    'node_modules/.bin/gulp',
    '--gulpfile', path.resolve(__dirname, 'fixtures', 'gulpfile.js'),
    task
  ].join(' '), {encoding: 'utf8'});
}

describe('gulp-jasmine-browser', function() {
  it('works', function() {
    expect(gulp('dummy')).toContain('2 specs, 1 failure');
  });
});

var path = require('path');
var childProcess = require('child_process');

function gulp(task, callback) {
  return childProcess.exec([
    'node_modules/.bin/gulp',
    '--gulpfile', path.resolve(__dirname, 'fixtures', 'gulpfile.js'),
    task
  ].join(' '), {encoding: 'utf8'}, callback);
}

describe('gulp-jasmine-browser', function() {
  it('works', function(done) {
    gulp('dummy', function(error, stdout) {
      expect(stdout).toContain('2 specs, 1 failure');
      done();
    });
  });
});

Stop using execSync for compatibility with Node 0.10


/* global require, describe, it */

var assert = require('assert');
var urlPrefix = 'http://katas.tddbin.com/katas/es6/language/';
var katasUrl = urlPrefix + '__grouped__.json';

var GroupedKata = require('../src/grouped-kata.js');

describe('load ES6 kata data', function() {
  it('loaded data are as expected', function(done) {
    function onSuccess(groupedKatas) {
      assert.ok(groupedKatas);
      done();
    }

    new GroupedKata(katasUrl).load(function() {}, onSuccess);
  });
  describe('on error, call error callback and the error passed', function() {
    it('invalid JSON', function(done) {
      function onError(err) {
        assert.ok(err);
        done();
      }

      var invalidUrl = urlPrefix;
      new GroupedKata(invalidUrl).load(onError);
    });
    it('for invalid data', function(done) {
      function onError(err) {
        assert.ok(err);
        done();
      }

      var invalidData = urlPrefix + '__all__.json';
      new GroupedKata(invalidData).load(onError);
    });
  });
});

/* global require, describe, it */

import assert from 'assert';
var urlPrefix = 'http://katas.tddbin.com/katas/es6/language/';
var katasUrl = urlPrefix + '__grouped__.json';

var GroupedKata = require('../src/grouped-kata.js');

describe('load ES6 kata data', function() {
  it('loaded data are as expected', function(done) {
    function onSuccess(groupedKatas) {
      assert.ok(groupedKatas);
      done();
    }

    new GroupedKata(katasUrl).load(function() {}, onSuccess);
  });
  describe('on error, call error callback and the error passed', function() {
    it('invalid JSON', function(done) {
      function onError(err) {
        assert.ok(err);
        done();
      }

      var invalidUrl = urlPrefix;
      new GroupedKata(invalidUrl).load(onError);
    });
    it('for invalid data', function(done) {
      function onError(err) {
        assert.ok(err);
        done();
      }

      var invalidData = urlPrefix + '__all__.json';
      new GroupedKata(invalidData).load(onError);
    });
  });
});

Use one es6 feature, modules.


var mongoose = require('mongoose');

// Create a new schema for tweets
var schema = new mongoose.Schema({
  twid       : String,
  active     : Boolean,
  author     : String,
  avatar     : String,
  body       : String,
  date       : Date,
  screenname : String
});

var Tweet = mongoose.model('Tweet', schema);

// Return tweets from the database
schema.statics.getTweets = function(page, skip, callback) {
  var tweets = [];
  var start = (page * 10) + (skip * 1);

  // Query the database (use skip and limit to achieve page chunks)
  Tweet.find(
      {},
      'twid active author avatar body date screenname',
      { skip: start, limit: 10 }
    )
    .sort({ date: 'desc' })
    .exec(function(err, docs) {
      if (!err) {
        tweets = docs;
        tweets.forEach(function(tweet) {
          tweet.active = true;
        });
      }

      callback(tweets);
  });
};

module.exports = Tweet;

var mongoose = require('mongoose');

// Create a new schema for tweets
var schema = new mongoose.Schema({
  twid       : String,
  active     : Boolean,
  author     : String,
  avatar     : String,
  body       : String,
  date       : Date,
  screenname : String
});

// Return tweets from the database
schema.statics.getTweets = function(page, skip, callback) {
  var tweets = [];
  var start = (page * 10) + (skip * 1);

  // Query the database (use skip and limit to achieve page chunks)
  Tweet.find(
      {},
      'twid active author avatar body date screenname',
      { skip: start, limit: 10 }
    )
    .sort({ date: 'desc' })
    .exec(function(err, docs) {
      if (!err) {
        tweets = docs;
        tweets.forEach(function(tweet) {
          tweet.active = true;
        });
      }

      callback(tweets);
  });
};

var Tweet = mongoose.model('Tweet', schema);

module.exports = Tweet;

Create mongoose model after static methods are defined


import path from 'path';
import webpack from 'webpack';
import autoprefixer from 'autoprefixer';

module.exports = {
    entry: {
        'react-image-lightbox': './src/index',
    },
    output: {
        path: path.join(__dirname, 'dist', 'umd'),
        filename: '[name].js',
        libraryTarget: 'umd',
        library: 'ReactImageLightbox',
    },
    resolve: {
        extensions: ['', '.js']
    },
    devtool: 'source-map',
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.EnvironmentPlugin([
            "NODE_ENV",
        ]),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
        }),
    ],
    postcss: [
        autoprefixer({ browsers: ['IE >= 9', '> 1%'] }),
    ],
    externals: {
        react: 'react',
        'react-dom': 'react-dom',
        'react-modal': 'react-modal',
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                loaders: ['babel'],
                include: path.join(__dirname, 'src')
            },
            {
                test: /\.scss$/,
                loaders: [
                    'style-loader',
                    'css-loader?modules&importLoaders=1&localIdentName=[local]___[hash:base64:5]',
                    'postcss-loader',
                    'sass-loader',
                ],
                include: path.join(__dirname, 'src')
            },
        ]
    }
};

import path from 'path';
import webpack from 'webpack';
import autoprefixer from 'autoprefixer';

module.exports = {
    entry: {
        'react-image-lightbox': './src/index',
    },
    output: {
        path: path.join(__dirname, 'dist', 'umd'),
        filename: '[name].js',
        libraryTarget: 'umd',
        library: 'ReactImageLightbox',
    },
    resolve: {
        extensions: ['', '.js']
    },
    devtool: 'source-map',
    plugins: [
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.EnvironmentPlugin([
            "NODE_ENV",
        ]),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            mangle: false,
            beautify: true,
            comments: true,
        }),
    ],
    postcss: [
        autoprefixer({ browsers: ['IE >= 9', '> 1%'] }),
    ],
    externals: {
        react: 'react',
        'react-dom': 'react-dom',
        'react-modal': 'react-modal',
    },
    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                loaders: ['babel'],
                include: path.join(__dirname, 'src')
            },
            {
                test: /\.scss$/,
                loaders: [
                    'style-loader',
                    'css-loader?modules&importLoaders=1&localIdentName=[local]___[hash:base64:5]',
                    'postcss-loader',
                    'sass-loader',
                ],
                include: path.join(__dirname, 'src')
            },
        ]
    }
};

Make compiled source file more readable


import {NAMESPACE, PREFIX} from './constants';

const ast = require('parametric-svg-ast');
const arrayFrom = require('array-from');
const startsWith = require('starts-with');

const ELEMENT_NODE = 1;

const getChildren = ({children, childNodes}) => (children ?
  arrayFrom(children) :
  arrayFrom(childNodes).filter(({nodeType}) => nodeType === ELEMENT_NODE)
);

const nodeBelongsToNamespace = ({namespace, prefix = null}, node) => (
  ('namespaceURI' in node ?
    node.namespaceURI === namespace :
    (prefix !== null && startsWith(node.name, `${prefix}:`))
  )
);

const getLocalName = (node) => ('namespaceURI' in node ?
  node.localName :
  node.name.replace(new RegExp(`^.*?:`), '')
);

const crawl = (parentAddress) => (attributes, element, indexInParent) => {
  const address = parentAddress.concat(indexInParent);

  const currentAttributes = arrayFrom(element.attributes)
    .filter((node) => nodeBelongsToNamespace({
      namespace: NAMESPACE,
      prefix: PREFIX,
    }, node))

    .map((attribute) => ({
      address,
      name: getLocalName(attribute),
      dependencies: [],  // Proof of concept
      relation: () => Number(attribute.value),  // Proof of concept
    }));

  return getChildren(element).reduce(
    crawl(address),
    attributes.concat(currentAttributes)
  );
};

export default (root) => {
  const attributes = getChildren(root).reduce(crawl([]), []);

  return ast({attributes, defaults: []});
};

import {NAMESPACE, PREFIX} from './constants';

const ast = require('parametric-svg-ast');
const arrayFrom = require('array-from');
const startsWith = require('starts-with');

const ELEMENT_NODE = 1;

const getChildren = ({children, childNodes}) => (children ?
  arrayFrom(children) :
  arrayFrom(childNodes).filter(({nodeType}) => nodeType === ELEMENT_NODE)
);

const nodeBelongsToNamespace = ({namespace, prefix = null}, node) => (
  (node.namespaceURI ?
    node.namespaceURI === namespace :
    (prefix !== null && startsWith(node.name, `${prefix}:`))
  )
);

const getLocalName = (node) => (node.namespaceURI ?
  node.localName :
  node.name.replace(new RegExp(`^.*?:`), '')
);

const crawl = (parentAddress) => (attributes, element, indexInParent) => {
  const address = parentAddress.concat(indexInParent);

  const currentAttributes = arrayFrom(element.attributes)
    .filter((node) => nodeBelongsToNamespace({
      namespace: NAMESPACE,
      prefix: PREFIX,
    }, node))

    .map((attribute) => ({
      address,
      name: getLocalName(attribute),
      dependencies: [],  // Proof of concept
      relation: () => Number(attribute.value),  // Proof of concept
    }));

  return getChildren(element).reduce(
    crawl(address),
    attributes.concat(currentAttributes)
  );
};

export default (root) => {
  const attributes = getChildren(root).reduce(crawl([]), []);

  return ast({attributes, defaults: []});
};

Make it work more or less with HTML4


import React          from 'react';
import NextEvent      from './NextEvent';
import UpcomingEvents from './UpcomingEvents';
import PreviousEvents from './PreviousEvents';
import ParseComponent from 'parse-react/class';

export default class Homepage extends ParseComponent {
  constructor(props) {
    super(props);
  }

  observe(props, state) {
    return {
      events: new Parse.Query('Events')
    };
  }

  render() {

    return (

{this.props.description}

        <NextEvent event={this.data.events[0]} />
        <UpcomingEvents events={this.data.events} />
        <PreviousEvents events={this.data.events} />

    );
  }
}

import React          from 'react';
import NextEvent      from './NextEvent';
import UpcomingEvents from './UpcomingEvents';
import PreviousEvents from './PreviousEvents';
import ParseComponent from 'parse-react/class';

export default class Homepage extends ParseComponent {
  constructor(props) {
    super(props);
  }

  observe(props, state) {
    return {
      events: new Parse.Query('Events')
    };
  }

  render() {

    let eventsContent;

    if(this.pendingQueries().length !== 0) {
      eventsContent =
Loading...

    } else {
      eventsContent = (

          <NextEvent event={this.data.events[0]} />
          <UpcomingEvents events={this.data.events} />
          <PreviousEvents events={this.data.events} />

      );
    }

    return (

{this.props.description}

        {eventsContent}

    );
  }
}

Add loading text while Parse is fetching events


import Class from '../class';
import Matreshka from '../matreshka';
import instanceMembers from './_prototype';
import matreshkaError from '../_helpers/matreshkaerror';
import initMK from '../_core/init';
import staticMembers from './_staticmembers';

instanceMembers.extends = Matreshka;

instanceMembers.constructor = function MatreshkaArray(length) {
    if (!(this instanceof MatreshkaArray)) {
        throw matreshkaError('common:call_class');
    }

    initMK(this);

    // repeat the same logic as for native Array
    if (arguments.length === 1 && typeof length === 'number') {
        this.length = length;
    } else {
        nofn.forEach(arguments, (arg, index) => {
            this[index] = arg;
        });

        this.length = arguments.length;
    }

    // return is used to make possible to chain super() calls
    return this;
};

const MatreshkaArray = Class(instanceMembers, staticMembers);

export default MatreshkaArray;

import Class from '../class';
import Matreshka from '../matreshka';
import instanceMembers from './_prototype';
import matreshkaError from '../_helpers/matreshkaerror';
import initMK from '../_core/init';
import staticMembers from './_staticmembers';

instanceMembers.extends = Matreshka;

instanceMembers.constructor = function MatreshkaArray(length) {
    if (!(this instanceof MatreshkaArray)) {
        throw matreshkaError('common:call_class');
    }

    const def = initMK(this);
    const { itemMediator } = def;

    // repeat the same logic as for native Array
    if (arguments.length === 1 && typeof length === 'number') {
        this.length = length;
    } else {
        nofn.forEach(arguments, (arg, index) => {
            this[index] = itemMediator ? itemMediator(arg, index) : arg;
        });

        this.length = arguments.length;
    }

    // return is used to make possible to chain super() calls
    return this;
};

const MatreshkaArray = Class(instanceMembers, staticMembers);

export default MatreshkaArray;

Call itemMediator in Array constructor


/**
 * Created by Tomasz Gabrysiak @ Infermedica on 08/02/2017.
 */

import html from '../../templates/helpers';

const template = (context) => {
  return new Promise((resolve) => {
    context.api.getSuggestedSymptoms(context.data).then((suggestedSymptoms) => {
      resolve(html`

Do you have any of the following symptoms?

            <form>
              ${suggestedSymptoms.map(symptom => {
                return html`

                      <input id="${symptom.id}" type="checkbox" class="input-symptom custom-control-input">

                      ${symptom.name}

                `;
              })}
            </form>

 This is a list of symptoms suggested by our AI, basing on the information gathered so far during the interview.

        `);
    });
  });
};

export default template;

/**
 * Created by Tomasz Gabrysiak @ Infermedica on 08/02/2017.
 */

import html from '../../templates/helpers';

const template = (context) => {
  return new Promise((resolve) => {
    context.api.getSuggestedSymptoms(context.data).then((suggestedSymptoms) => {
      if (!suggestedSymptoms.length) {
        resolve('
 I am thinking...
');
        document.getElementById('next-step').click();
      }
      resolve(html`

Do you have any of the following symptoms?

            <form>
              ${suggestedSymptoms.map(symptom => {
                return html`

                      <input id="${symptom.id}" type="checkbox" class="input-symptom custom-control-input">

                      ${symptom.name}

                `;
              })}
            </form>

 This is a list of symptoms suggested by our AI, basing on the information gathered so far during the interview.

        `);
    });
  });
};

export default template;

Handle empty response form /suggest


// Example of how to connect to a Tor hidden service and use it as a peer.
// See demo.js to learn how to invoke this program.

var bcj = org.bitcoinj;
var params = bcj.params.MainNetParams.get();
var context = new bcj.core.Context(params);
bcj.utils.BriefLogFormatter.init();

var InetAddress = Java.type("java.net.InetAddress");
var InetSocketAddress = Java.type("java.net.InetSocketAddress");

// Hack around the fact that PeerAddress assumes nodes have IP addresses. Simple enough for now.
var OnionAddress = Java.extend(Java.type("org.bitcoinj.core.PeerAddress"), {
    toSocketAddress: function() {
        return InetSocketAddress.createUnresolved("hhiv5pnxenvbf4am.onion", params.port);
    }
});

var pg = bcj.core.PeerGroup.newWithTor(context, null, new com.subgraph.orchid.TorClient(), false);
// c'tor is bogus here: the passed in InetAddress will be ignored.
pg.addAddress(new OnionAddress(InetAddress.localHost, params.port));
pg.start();

pg.waitForPeers(1).get();
print("Connected to: " + pg.connectedPeers);

for each (var peer in pg.connectedPeers) {
    print(peer.peerVersionMessage.subVer);
    peer.ping().get()
}

pg.stop();

// Example of how to connect to a Tor hidden service and use it as a peer.
// See demo.js to learn how to invoke this program.

var bcj = org.bitcoinj;
var params = bcj.params.MainNetParams.get();
var context = new bcj.core.Context(params);
bcj.utils.BriefLogFormatter.init();

var PeerAddress = Java.type("org.bitcoinj.core.PeerAddress");
var InetSocketAddress = Java.type("java.net.InetSocketAddress");

// The PeerAddress class can now handle InetSocketAddresses with hostnames if they are .onion.
var OnionAddress = InetSocketAddress.createUnresolved("hhiv5pnxenvbf4am.onion", params.port);

var pg = bcj.core.PeerGroup.newWithTor(context, null, new com.subgraph.orchid.TorClient(), false);

pg.addAddress(new PeerAddress(OnionAddress));
pg.start();

pg.waitForPeers(1).get();
print("Connected to: " + pg.connectedPeers);

for each (var peer in pg.connectedPeers) {
    print(peer.peerVersionMessage.subVer);
    peer.ping().get()
}

pg.stop();

Update javascript Tor example to reflect simplified handling of .onion addresses


var passport = require('passport');
var auth0 = require('../lib/services/auth0');

module.exports = {
  type: 'authentication',
  module: auth0,
  initialize: (app) => {
    passport.use(auth0.strategy);

    passport.serializeUser(function(user, done) {
      done(null, user);
    });

    passport.deserializeUser(function(user, done) {
      done(null, user);
    });

    app.use(passport.initialize());
    app.use(passport.session());

    app.use(function(req, res, next) {
      res.locals.user = req.user;
      next();
    });
  },
  registerRoutes: app => {
    app.get('/login', function(req, res) {
      res.render('login', {env: process.env});
    });

    app.get('/logout', function(req, res) {
      req.logout();
      res.redirect('/');
    });

    app.get('/user', function (req, res) {
      res.render('user', {user: req.user});
    });

    app.get('/auth/callback', passport.authenticate('auth0', {
      failureRedirect: '/'
    }), function(req, res) {
      const serializedState = req.query.state;

      if(typeof(serializedState) === 'string') {
        const state = JSON.parse(Buffer.from(serializedState, 'base64'));
        res.redirect(state.returnPath);
      } else {
        res.redirect('/');
      }
    });
  }
};

var passport = require('passport');
var auth0 = require('../lib/services/auth0');

module.exports = {
  type: 'authentication',
  module: auth0,
  initialize: (app) => {
    passport.use(auth0.strategy);

    passport.serializeUser(function(user, done) {
      done(null, user);
    });

    passport.deserializeUser(function(user, done) {
      done(null, user);
    });

    app.use(passport.initialize());
    app.use(passport.session());

    app.use(function(req, res, next) {
      res.locals.user = req.user;
      next();
    });
  },
  registerRoutes: app => {
    app.get('/login', function(req, res) {
      res.render('login', {env: process.env});
    });

    app.get('/logout', function(req, res) {
      req.logout();
      res.redirect('/');
    });

    // Most user facing routes are danish, so let's keep it that way.
    app.get('/min-side', function (req, res) {
      res.render('profile', {user: req.user});
    });

    app.get('/auth/callback', passport.authenticate('auth0', {
      failureRedirect: '/'
    }), function(req, res) {
      const serializedState = req.query.state;

      if(typeof(serializedState) === 'string') {
        const state = JSON.parse(Buffer.from(serializedState, 'base64'));
        res.redirect(state.returnPath);
      } else {
        res.redirect('/');
      }
    });
  }
};

Rename /user route to /min-side


setupFlorence();

//forms field styling markup injection
//$('select:not(.small)').wrap('');
//$('select.small').wrap('');
//$('.selectbg--small:eq(1)').addClass('selectbg--small--margin');
//$('.selectbg--small:eq(3)').addClass('float-right');

Remove commented code not used.


import { group, member, message } from '../actions/actionTypes';

const groupReducer = (state = {}, action = {}) => {
  switch (action.type) {
    case group.CREATE_SUCCESS:
      return {
        ...state,
        [action.group.id]: {
          members: [],
          messages: []
        }
      };
    case member.ADD_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          members: [
            ...state[action.groupId].members,
            action.member
          ]
        }
      };
    case member.LIST_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          members: action.list
        }
      };
    case message.CREATE_SUCCESS:
      return { ...state,
        [action.message.groupId]: {
          messages: [...state[action.message.groupId].messages, action.message]
        } };
      // return {
      //   ...state,
      //   [action.groupId]: {
      //     ...state[action.groupId],
      //     messages: [
      //       ...state[action.groupId].messages,
      //       action.message
      //     ]
      //   }
      // };
    case message.LIST_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          messages: action.list
        }
      };
    default:
      return state;
  }
};

export default groupReducer;

import { group, member, message } from '../actions/actionTypes';

const groupReducer = (state = {}, action = {}) => {
  switch (action.type) {
    case group.CREATE_SUCCESS:
      return {
        ...state,
        [action.group.id]: {
          members: [],
          messages: []
        }
      };
    case member.ADD_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          members: [
            ...state[action.groupId].members,
            action.member
          ]
        }
      };
    case member.LIST_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          members: action.list
        }
      };
    case message.CREATE_SUCCESS:
      // return { ...state,
      //   [action.message.groupId]: {
      //     messages: [...state[action.message.groupId].messages, action.message]
      //   } };
      return {
        ...state,
        [action.message.groupId]: {
          ...state[action.message.groupId],
          messages: [
            ...state[action.message.groupId].messages,
            action.message
          ]
        }
      };
    case message.LIST_SUCCESS:
      return {
        ...state,
        [action.groupId]: {
          ...state[action.groupId],
          messages: action.list
        }
      };
    default:
      return state;
  }
};

export default groupReducer;

Edit logic for creating mesage success action


var convert = require('convert');
var parse = require('color-parser');

exports.segments = {
  stroke: function(display, segment) {
    if (!segment.focused) return;

    switch (segment.type) {
      case 'CAR':
        return '#888';
      case 'WALK':
        return 'none';
      case 'TRANSIT':
        var route = segment.patterns[0].route;
        var id = route.route_id.split(':');
        return convert.routeToColor(route.route_type, id[0].toLowerCase(), id[1].toLowerCase(), route.route_color);
    }
  }
};

exports.places = {
  stroke: 1
};

exports.places_icon = {
  x: -8,
  y: -8,
  width: 16,
  height: 16,
  'xlink:href': function(display, data) {
    if (data.owner.getId() === 'from') return 'build/planner-app/transitive-view/start.svg';
    if (data.owner.getId() === 'to') return 'build/planner-app/transitive-view/end.svg';
  },
  stroke: 1,
  visibility: 'visible'
};

exports.multipoints_pattern = exports.multipoints_merged = exports.stops_pattern = exports.stops_merged = {
  r: function(display, data, index, utils) {
    return utils.pixels(display.zoom.scale(), 4, 6, 8);
  }
};

var config = require('config');
var convert = require('convert');
var parse = require('color-parser');

exports.segments = {
  stroke: function(display, segment) {
    if (!segment.focused) return;

    switch (segment.type) {
      case 'CAR':
        return '#888';
      case 'WALK':
        return 'none';
      case 'TRANSIT':
        var route = segment.patterns[0].route;
        var id = route.route_id.split(':');
        return convert.routeToColor(route.route_type, id[0].toLowerCase(), id[1].toLowerCase(), route.route_color);
    }
  }
};

exports.places = {
  stroke: 1
};

exports.places_icon = {
  x: -8,
  y: -8,
  width: 16,
  height: 16,
  'xlink:href': function(display, data) {
    if (data.owner.getId() === 'from') return config.s3_bucket() + '/build/planner-app/transitive-view/start.svg';
    if (data.owner.getId() === 'to') return config.s3_bucket() + '/build/planner-app/transitive-view/end.svg';
  },
  stroke: 1,
  visibility: 'visible'
};

exports.multipoints_pattern = exports.multipoints_merged = exports.stops_pattern = exports.stops_merged = {
  r: function(display, data, index, utils) {
    return utils.pixels(display.zoom.scale(), 4, 6, 8);
  }
};

Prepend SVG icons with S3 bucket


steal("src/synthetic.js", function (Syn) {
	module("synthetic/typeable");

	var isTypeable = Syn.typeable.test;

	test("Inputs and textareas", function () {
		var input = document.createElement("input");
		var textarea = document.createElement("textarea");

		equal(isTypeable(input), true, "Input element is typeable.");
		equal(isTypeable(textarea), true, "Text area is typeable.");
	});

	test("Normal divs", function () {
		var div = document.createElement("div");

		equal(isTypeable(div), false, "Divs are not typeable.");
	});

	test("Contenteditable div", function () {
		var div = document.createElement("div");

		// True
		div.setAttribute("contenteditable", "true");
		equal(isTypeable(div), true, "Divs with contenteditable true");

		// Empty string
		div.setAttribute("contenteditable", "");
		equal(isTypeable(div), true, "Divs with contenteditable as empty string.");
	});

	test("User defined typeable function", function () {
		// We're going to define a typeable with a class of foo.
		Syn.typeable(function (node) {
			return node.className.split(" ")
				.indexOf("foo") !== -1;
		});

		var div = document.createElement("div");
		div.className = "foo";

		equal(isTypeable(div), true, "Custom function works.");
	});

});

steal("src/synthetic.js", function (Syn) {
	module("synthetic/typeable");

	var isTypeable = Syn.typeable.test;

	test("Inputs and textareas", function () {
		var input = document.createElement("input");
		var textarea = document.createElement("textarea");

		equal(isTypeable(input), true, "Input element is typeable.");
		equal(isTypeable(textarea), true, "Text area is typeable.");
	});

	test("Normal divs", function () {
		var div = document.createElement("div");

		equal(isTypeable(div), false, "Divs are not typeable.");
	});

	test("Contenteditable div", function () {
		var div = document.createElement("div");

		// True
		div.setAttribute("contenteditable", "true");
		equal(isTypeable(div), true, "Divs with contenteditable true");

		// Empty string
		div.setAttribute("contenteditable", "");
		equal(isTypeable(div), true, "Divs with contenteditable as empty string.");
	});

	test("User defined typeable function", function () {
		// We're going to define a typeable with a class of foo.
		Syn.typeable(function (node) {
			return node.className === "foo";
		});

		var div = document.createElement("div");
		div.className = "foo";

		equal(isTypeable(div), true, "Custom function works.");
	});

});

Make typeable test compatible with IE<=8


'use strict'

require('../lib/peer-watch.js')

const { setTimeout } = require('sdk/timers')
const { prefs } = require('sdk/simple-prefs')
const tabs = require('sdk/tabs')
const gw = require('../lib/gateways.js')

exports['test automatic mode disabling redirect when IPFS API is offline'] = function (assert, done) {
  const ipfsPath = 'ipfs/QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'
  prefs.apiPollInterval = 100 // faster test
  prefs.customApiPort = 59999 // change to something that will always fail
  prefs.useCustomGateway = true
  prefs.automatic = true

  setTimeout(function () {
    assert.equal(prefs.automatic, true, 'automatic mode should be enabled')
    assert.equal(prefs.useCustomGateway, false, 'redirect should be automatically disabled')
    assert.equal(gw.redirectEnabled, false, 'redirect should be automatically disabled')
    tabs.open({
      url: 'https://ipfs.io/' + ipfsPath,
      onReady: function onReady (tab) {
        assert.equal(tab.url, 'https://ipfs.io/' + ipfsPath, 'expected no redirect')
        tab.close(done)
      }
    })
  }, prefs.apiPollInterval + 500)
}

require('./prefs-util.js').isolateTestCases(exports)
require('sdk/test').run(exports)

'use strict'

require('../lib/peer-watch.js')

const { env } = require('sdk/system/environment')
const { setTimeout } = require('sdk/timers')
const { prefs } = require('sdk/simple-prefs')
const tabs = require('sdk/tabs')
const gw = require('../lib/gateways.js')

exports['test automatic mode disabling redirect when IPFS API is offline'] = function (assert, done) {
  const ipfsPath = 'ipfs/QmTkzDwWqPbnAh5YiV5VwcTLnGdwSNsNTn2aDxdXBFca7D/Makefile'
  const checkDelay = ('TRAVIS' in env && 'CI' in env) ? 5000 : 500
  prefs.apiPollInterval = 100 // faster test
  prefs.customApiPort = 59999 // change to something that will always fail
  prefs.useCustomGateway = true
  prefs.automatic = true

  setTimeout(function () {
    assert.equal(prefs.automatic, true, 'automatic mode should be enabled')
    assert.equal(prefs.useCustomGateway, false, 'redirect should be automatically disabled')
    assert.equal(gw.redirectEnabled, false, 'redirect should be automatically disabled')
    tabs.open({
      url: 'https://ipfs.io/' + ipfsPath,
      onReady: function onReady (tab) {
        assert.equal(tab.url, 'https://ipfs.io/' + ipfsPath, 'expected no redirect')
        tab.close(done)
      }
    })
  }, prefs.apiPollInterval + checkDelay)
}

require('./prefs-util.js').isolateTestCases(exports)
require('sdk/test').run(exports)

Increase test timeout when run in TravisCI


// Comes from https://github.com/facebook/relay/issues/161
// Should be used in tests as a replacement for `react-storybooks-relay-container`
//
var React = require.requireActual("react")

const graphql = (strings, ...keys) => {
  const lastIndex = strings.length - 1
  return (
    strings.slice(0, lastIndex).reduce((p, s, i) => p + s + keys[i], "") +
    strings[lastIndex]
  )
}

module.exports = {
  graphql,
  commitMutation: jest.fn(),
  QueryRenderer: props => React.createElement("div", {}),
  createFragmentContainer: component => component,
  createPaginationContainer: component => component,
  createRefetchContainer: component => component,
}

// Comes from https://github.com/facebook/relay/issues/161
// Should be used in tests as a replacement for `react-storybooks-relay-container`

var React = require.requireActual("react")

// This is a template string function, which returns the original string
// It's based on https://github.com/lleaff/tagged-template-noop
// Which is MIT licensed to lleaff
const graphql = (strings, ...keys) => {
  const lastIndex = strings.length - 1
  return (
    strings.slice(0, lastIndex).reduce((p, s, i) => p + s + keys[i], "") +
    strings[lastIndex]
  )
}

module.exports = {
  graphql,
  commitMutation: jest.fn(),
  QueryRenderer: props => React.createElement("div", {}),
  createFragmentContainer: component => component,
  createPaginationContainer: component => component,
  createRefetchContainer: component => component,
}

Document noop `graphql` tagged template


$().ready(loadContentSection);

$("body").on('click', '.keyword', function() {
  $(this).addClass("active");
  $(".base").hide(200);
  $("#real-body").addClass("focus");
});

$("body").on('click', ".close", function(event) {
  event.stopPropagation();
  $(".extended").removeClass("extended");
  $(this).parent().removeClass("active");
  $(".base").show(200);
  $("#real-body").removeClass("focus");
});

$("body").on('click', ".active .item", function() {
  $(".item").off("click");
  const url = $(this).attr("data-url");
  window.location.href = url;
});

$("body").on('click', '.level-name', function() {
  const isThisExtended = $(this).parent().hasClass("extended");
  $(".extended").removeClass("extended");
  if (!isThisExtended) {
    $(this).parent().addClass("extended");
  }
});

$("body").on('click', '#go-back', function() {
  $("#body").off("click");
  window.location.href = '/';
});

Add event listener to back button


(function () {
    'use strict';

    angular.module('j.point.me').controller('FirstController', ['$scope', '$firebase', '$firebaseAuth', '$window',
        function ($scope, $firebase, $firebaseAuth, $window) {

            var ref = new Firebase("https://jpointme.firebaseio.com/");
            var auth = $firebaseAuth(ref);

            if (auth.$getAuth()) {
               $scope.username = auth.$getAuth().github.displayName;
            } else {
                $scope.username = "anonymous";
            }

            $scope.authenticate = function (provider) {
                var auth = $firebaseAuth(ref);
                auth.$authWithOAuthPopup("github").then(function (authData) {
                    console.log("Logged in as:", authData);
                    $scope.username = authData.github.displayName;
                }).catch(function (error) {
                    console.error("Authentication failed: ", error);
                });
            };

            $scope.logout = function () {
                ref.unauth();
                $window.location.reload();
            };
        }
    ]);
}());

(function () {
    'use strict';

    angular.module('j.point.me').controller('FirstController', ['$scope', '$firebase', '$firebaseAuth', '$window',
        function ($scope, $firebase, $firebaseAuth, $window) {

            var ref = new Firebase("https://jpointme.firebaseio.com/");
            var auth = $firebaseAuth(ref);

            var authData = auth.$getAuth();
            if (authData) {
                $scope.username = authData.github.displayName;
                $scope.userId = authData.auth.provider + '/' + authData.auth.uid;
            } else {
                $scope.username = "anonymous";
                $scope.userId = "";
            }

            $scope.authenticate = function (provider) {
                var auth = $firebaseAuth(ref);
                auth.$authWithOAuthPopup("github").then(function (authData) {
                    console.log("Logged in as:", authData);
                    $scope.username = authData.github.displayName;
                }).catch(function (error) {
                    console.error("Authentication failed: ", error);
                });
            };

            $scope.logout = function () {
                ref.unauth();
                $window.location.reload();
            };

            var users = $firebase(ref.child("users"));
            var userExists = false;

            users.$asArray()
              .$loaded()
              .then(function(data) {
                  angular.forEach(data,function(user,index){
                      if (user.oAuthId === $scope.userId) {
                          userExists = true;
                      }
                  })
              }).then(function(data) {
                  if (!userExists) {
                      users.$push({name: $scope.username, oAuthId: $scope.userId}).then(function(newChildRef) {
                          console.log('user with userId ' + $scope.userId + ' does not exist; adding');
                      });
                  } else {
                        console.log('user with userId ' + $scope.userId + ' already exists; not adding.');
                  }
              });

        }
    ]);
}());

Write new users to database.


'use strict';

/*****
 * Vain
 *
 * A view-first templating engine for Node.js.
*****/
var jsdom = require('jsdom'),
    $ = require('jquery')(jsdom.jsdom().createWindow()),
    snippetRegistry = {};

/**
 * Register a snippet in the snippet registry.
**/
exports.registerSnippet = function(snippetName, snippetFn) {
  snippetRegistry[snippetName] = snippetFn;
};

/**
 * Process the given markup.
**/
exports.render = function(input, options, fn) {
  if ('function' === typeof options) {
    fn = options;
    options = undefined;
  }

  options = options || {};

  var $template = $(input);
  $template.find("data-vain").each(function() {
    var snippetName = $(this).data('vain');

    if ('function' === typeof snippetRegistry[snippetName]) {
      $(this).replaceWith(snippetRegistry[snippetName](this));
    }
  });

  return $("<div />").append($template).html();
};

/**
 * Process a given file.
**/
exports.renderFile = function(path, options, fn) {
  //
};

// Express support.
exports.__express = exports.renderFile;

'use strict';

/*****
 * Vain
 *
 * A view-first templating engine for Node.js.
*****/
var jsdom = require('jsdom'),
    $ = require('jquery')(jsdom.jsdom().createWindow()),
    snippetRegistry = {};

/**
 * Register a snippet in the snippet registry.
**/
exports.registerSnippet = function(snippetName, snippetFn) {
  snippetRegistry[snippetName] = snippetFn;
};

/**
 * Process the given markup.
**/
exports.render = function(input, options, fn) {
  if ('function' === typeof options) {
    fn = options;
    options = undefined;
  }

  options = options || {};

  var $template = $(input),
      snippetHandlers = $.merge(snippetRegistry, options.snippets || {});

  $template.find("data-vain").each(function() {
    var snippetName = $(this).data('vain');

    if ('function' === typeof snippetRegistry[snippetName]) {
      $(this).replaceWith(snippetRegistry[snippetName](this));
    }
  });

  return $("<div />").append($template).html();
};

/**
 * Process a given file.
**/
exports.renderFile = function(path, options, fn) {
  //
};

// Express support.
exports.__express = exports.renderFile;

Add the ability to specify snippets on a per-invocation basis.


'use strict';

define(function(require) {
    var i18next = require('ext/i18next');
    var i18nextJquery = require('ext/jquery-i18next');
    var i18nextXHRbackend = require('ext/i18next-xhr-backend');

    i18next
        .use(i18nextXHRbackend)
        .init({
            debug: false,
            lng: 'en',
            preload: ['en', 'es', 'gr'],
            lngs: ['en', 'es', 'gr'],
            fallbackLng: 'en',
            ns: [
                'index',
                'map',
                'footer',
                'saved-records',
                'common'
            ],
            defaultNS: 'index',
            fallbackNS: 'common',
            backend: {
                loadPath: 'locales/{{lng}}/{{ns}}.json'
            }
        }, function(err, t) {
            var userLng = localStorage.getItem('user-language');

            i18nextJquery.init(i18next, $, {
                tName: 't',
                i18nName: 'i18n',
                handleName: 'localize',
                selectorAttr: 'data-i18n',
                targetAttr: 'data-i18n-target',
                optionsAttr: 'data-i18n-options',
                useOptionsAttr: false,
                parseDefaultValueFromContent: true
            });

            $(document).on('pagecreate', function(event, ui) {
                $(event.target).localize();
            });

            i18next.changeLanguage(userLng);
            $(document).localize();
        });
});

'use strict';

define(function(require) {
    var i18next = require('ext/i18next');
    var i18nextJquery = require('ext/jquery-i18next');
    var i18nextXHRbackend = require('ext/i18next-xhr-backend');

    i18next
        .use(i18nextXHRbackend)
        .init({
            debug: false,
            lng: 'en',
            preload: ['en', 'es', 'gr'],
            lngs: ['en', 'es', 'gr'],
            fallbackLng: 'en',
            ns: [
                'index',
                'map',
                'footer',
                'project',
                'saved-records',
                'common'
            ],
            defaultNS: 'index',
            fallbackNS: 'common',
            backend: {
                loadPath: 'locales/{{lng}}/{{ns}}.json'
            }
        }, function(err, t) {
            var userLng = localStorage.getItem('user-language');

            i18nextJquery.init(i18next, $, {
                tName: 't',
                i18nName: 'i18n',
                handleName: 'localize',
                selectorAttr: 'data-i18n',
                targetAttr: 'data-i18n-target',
                optionsAttr: 'data-i18n-options',
                useOptionsAttr: false,
                parseDefaultValueFromContent: true
            });

            $(document).on('pagecreate', function(event, ui) {
                $(event.target).localize();
            });

            i18next.changeLanguage(userLng);
            $(document).localize();
        });
});

Add a 'project' namespace for custom translations of each project


//Loads images and then initializes Datatables
$(window).load(function() {
	var tableTitle = $('.tableImage');
	var imageTitle = $('.tableTitle a');
	var i = 0;

	for (i; i < tableTitle.length; i++) {
		var imageLink = imageTitle[i].innerText.toLowerCase();
		$('.tableImage')[i].innerHTML = "";
	}
});

Update Image Loader to HTTPS


import React from 'react'
import { getDisplayName, wrapDisplayName, setDisplayName } from 'recompose'

const fixLineHeight = (lineHeight, displayName) => {
  if (typeof lineHeight === 'string') {
    throw new Error(
      `The element \`${displayName}\` has a \`lineHeight\` set with a String. Use numbers instead.`
    )
  }

  return global.navigator.product === 'ReactNative' ? lineHeight : `${lineHeight}px`
}

const fixStyle = (style, displayName) => ({
  ...style,
  lineHeight: style.lineHeight ? fixLineHeight(style.lineHeight, displayName) : undefined,
})

export default Target =>
  setDisplayName(wrapDisplayName(Target, 'normalizeStyle'))(({ style, ...props }) =>
    <Target style={style ? fixStyle(style, getDisplayName(Target)) : undefined} {...props} />
  )

import React from 'react'
import { getDisplayName, wrapDisplayName, setDisplayName } from 'recompose'

const fixLineHeight = (lineHeight, displayName) => {
  if (typeof lineHeight === 'string') {
    throw new Error(
      `The element \`${displayName}\` has a \`lineHeight\` set with a String. Use numbers instead.`
    )
  }

  return global.navigator && global.navigator.product === 'ReactNative'
    ? lineHeight
    : `${lineHeight}px`
}

const fixStyle = (style, displayName) => ({
  ...style,
  lineHeight: style.lineHeight ? fixLineHeight(style.lineHeight, displayName) : undefined,
})

export default Target =>
  setDisplayName(wrapDisplayName(Target, 'normalizeStyle'))(({ style, ...props }) =>
    <Target style={style ? fixStyle(style, getDisplayName(Target)) : undefined} {...props} />
  )

Add additional guard for `global.navigator`


(function(app) {
  'use strict';

  var Root = app.Root || require('./components/root.js');

  var root = new Root();
  root.init();

  app.root = root;
})(this.app || (this.app = {}));

(function(app) {
  'use strict';

  var Root = app.Root || require('./components/root.js');

  var root = new Root();
  root.init();

  app._root = root;
})(this.app || (this.app = {}));

Rename property for root element as private property


export const reportBug = (data) => ({
    method: 'post',
    url: 'reports/bug',
    data
});

export const reportCrash = (data) => ({
    method: 'post',
    url: 'reports/bug',
    data
});

// reportCrashSentryProxy  unclear API-spec

export const reportCSPViolation = (cspReport) => ({
    method: 'post',
    url: 'reports/csp',
    data: { 'csp-report': cspReport }
});

export const reportPishing = ({ MessageID, MIMEType, Body }) => ({
    method: 'post',
    url: 'reports/pishing',
    data: { MessageID, MIMEType, Body }
});

export const reportBug = (data, input) => ({
    method: 'post',
    url: 'reports/bug',
    input,
    data
});

export const reportCrash = (data) => ({
    method: 'post',
    url: 'reports/bug',
    data
});

// reportCrashSentryProxy  unclear API-spec

export const reportCSPViolation = (cspReport) => ({
    method: 'post',
    url: 'reports/csp',
    data: { 'csp-report': cspReport }
});

export const reportPishing = ({ MessageID, MIMEType, Body }) => ({
    method: 'post',
    url: 'reports/pishing',
    data: { MessageID, MIMEType, Body }
});

Add input as parameter to report bug


angular.module('offClick',[])
.directive('offClick', ['$document', function ($document) {

    function targetInFilter(target,filter){
        if(!target || !filter) return false;
        var elms = angular.element(filter);
        var elmsLen = elms.length;
        for (var i = 0; i< elmsLen; ++i)
            if(elms[i].contains(target)) return true;
        return false;
    }

    return {
        restrict: 'A',
        scope: {
            offClick: '&',
            offClickIf: '&'
        },
        link: function (scope, elm, attr) {

            if (attr.offClickIf) {
                scope.$watch(scope.offClickIf, function (newVal, oldVal) {
                        if (newVal && !oldVal) {
                            $document.on('click', handler);
                        } else if(!newVal){
                            $document.off('click', handler);
                        }
                    }
                );
            } else {
                $document.on('click', handler);
            }

            function handler(event) {
                var target = event.target || event.srcElement;
                if (!(elm[0].contains(target) || targetInFilter(target, attr.offClickFilter))) {
                    scope.$apply(scope.offClick());
                }
            }
        }
    };
}]);

angular.module('offClick',[])
.directive('offClick', ['$document', function ($document) {

    function targetInFilter(target,filter){
        if(!target || !filter) return false;
        var elms = angular.element(filter);
        var elmsLen = elms.length;
        for (var i = 0; i< elmsLen; ++i)
            if(elms[i].contains(target)) return true;
        return false;
    }

    return {
        restrict: 'A',
        scope: {
            offClick: '&',
            offClickIf: '&'
        },
        link: function (scope, elm, attr) {

            if (attr.offClickIf) {
                scope.$watch(scope.offClickIf, function (newVal, oldVal) {
                        if (newVal && !oldVal) {
                            $document.on('click', handler);
                        } else if(!newVal){
                            $document.off('click', handler);
                        }
                    }
                );
            } else {
                $document.on('click', handler);
            }

            scope.$on('$destroy', function() {
                $document.off('click', handler);
            });

            function handler(event) {
                var target = event.target || event.srcElement;
                if (!(elm[0].contains(target) || targetInFilter(target, attr.offClickFilter))) {
                    scope.$apply(scope.offClick());
                }
            }
        }
    };
}]);

Remove click handler from document when scope is destroyed


import { combineReducers } from 'redux';
import fuelSavingsAppState from './fuelSavings';
import cmsAppState from './cms.js';

const rootReducer = combineReducers({
  fuelSavingsAppState: fuelSavingsAppState,
  cmsAppState: cmsAppState
});

export default rootReducer;

import { combineReducers } from 'redux';
import fuelSavingsAppState from './fuelSavings';
import cmsAppState from './cms.js';

const rootReducer = combineReducers({
  fuelSavingsAppState,
  cmsAppState
});

export default rootReducer;

Switch back to es6 object literal notation


var path = require('path')
var cp = require('child_process')

var script = path.join(__dirname, 'postinstall')
if (process.platform.indexOf('win') === 0) {
  script += '.cmd'
} else {
  script += '.sh'
}
var child = cp.exec(script, [], {stdio: ['pipe', 'pipe', 'pipe']})
child.stderr.pipe(process.stderr)
child.stdout.pipe(process.stdout)

var path = require('path')
var cp = require('child_process')

var script = path.join(__dirname, 'postinstall')
if (process.platform.indexOf('win') === 0) {
  script += '.cmd'
} else {
  script += '.sh'
}
var child = cp.spawn(script, [], {stdio: ['pipe', 'pipe', 'pipe']})
child.stderr.pipe(process.stderr)
child.stdout.pipe(process.stdout)

Fix build error on Node 7


describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(false).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = FILL_ME_IN;
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(FILL_ME_IN);
  });
});

describe("About Expects", function() {

  //We shall contemplate truth by testing reality, via spec expectations.
  it("should expect true", function() {
    expect(true).toBeTruthy(); //This should be true
  });

  //To understand reality, we must compare our expectations against reality.
  it("should expect equality", function () {
	  var expectedValue = 2;
	  var actualValue = 1 + 1;

	  expect(actualValue === expectedValue).toBeTruthy();
  });

  //Some ways of asserting equality are better than others.
  it("should assert equality a better way", function () {
	  var expectedValue = 2;
	  var actualValue = 1 + 1;

  // toEqual() compares using common sense equality.
	  expect(actualValue).toEqual(expectedValue);
  });

  //Sometimes you need to be really exact about what you "type".
  it("should assert equality with ===", function () {
	  var expectedValue = "2";
	  var actualValue = (1 + 1).toString();

  // toBe() will always use === to compare.
	  expect(actualValue).toBe(expectedValue);
  });

  //Sometimes we will ask you to fill in the values.
  it("should have filled in values", function () {
	  expect(1 + 1).toEqual(2);
  });
});

Change all expected variables to truthy values


var supportsWoff2 = (function( win ){
	if( !( "FontFace" in win ) ) {
		return false;
	}

	var f = new FontFace('t', 'url( "data:application/font-woff2;base64,d09GMgABAAAAAADcAAoAAAAAAggAAACWAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABk4ALAoUNAE2AiQDCAsGAAQgBSAHIBtvAcieB3aD8wURQ+TZazbRE9HvF5vde4KCYGhiCgq/NKPF0i6UIsZynbP+Xi9Ng+XLbNlmNz/xIBBqq61FIQRJhC/+QA/08PJQJ3sK5TZFMlWzC/iK5GUN40psgqvxwBjBOg6JUSJ7ewyKE2AAaXZrfUB4v+hze37ugJ9d+DeYqiDwVgCawviwVFGnuttkLqIMGivmDg" ) format( "woff2" )', {});
	f.load()['catch'](function() {});

	return f.status == 'loading' || f.status == 'loaded';
})( this );

var supportsWoff2 = (function( win ){
  if( !( "FontFace" in win ) ) {
    return false;
  }

  var f = new FontFace('t', 'url( "data:application/font-woff2;base64,d09GMgABAAAAAADwAAoAAAAAAiQAAACoAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAABmAALAogOAE2AiQDBgsGAAQgBSAHIBuDAciO1EZ3I/mL5/+5/rfPnTt9/9Qa8H4cUUZxaRbh36LiKJoVh61XGzw6ufkpoeZBW4KphwFYIJGHB4LAY4hby++gW+6N1EN94I49v86yCpUdYgqeZrOWN34CMQg2tAmthdli0eePIwAKNIIRS4AGZFzdX9lbBUAQlm//f262/61o8PlYO/D1/X4FrWFFgdCQD9DpGJSxmFyjOAGUU4P0qigcNb82GAAA" ) format( "woff2" )', {});
  f.load()['catch'](function() {});

  return f.status == 'loading' || f.status == 'loaded';
})( this );

Fix WOFF2 font so it passes OTS in Firefox


var express = require('express');
var router = express.Router();
var arduino = require('../lib/arduino');

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', {
        title: 'Findmon - 2015 SBA IoT Hackathon'
    });
});

router.get('/arduino/display', function(req, res, next) {
	var message = req.param("message");

	arduino.sendMessage(message, function(err, results) {
		res.render('arduinoRes', {
			title: 'Arduino Response',
			error: err,
			results: results
		});
	});

});
module.exports = router;

var express = require('express');
var router = express.Router();
var arduino = require('../lib/arduino');

/* GET home page. */
router.get('/', function(req, res, next) {
    res.render('index', {
        title: 'Findmon - 2015 SBA IoT Hackathon'
    });
});

router.get('/arduino/display', function(req, res, next) {
	var message = req.param("message");

	arduino.sendMessage(message, function(err, results) {
		res.render('arduinoRes', {
			title: 'Arduino Response',
			error: err,
			results: results
		});
	});
});

router.get('/arduino/location', function(req, res, next) {
    var lat = req.param('lat');
    var lon = req.param('lon');
    console.info('[NFC] lat: ' + lat + " | lon: " + lon);
    res.send(200);
});

module.exports = router;

Add new REST API for getting the target location


// nS - No Space
// lC - Lowercase

export function bundleIdentifiers(
  currentAppName,
  newName,
  projectName,
  currentBundleID,
  newBundleID,
  newBundlePath
) {
  const nS_CurrentAppName = currentAppName.replace(/\s/g, '');
  const nS_NewName = newName.replace(/\s/g, '');
  const lC_Ns_CurrentBundleID = currentBundleID.toLowerCase();
  const lC_Ns_NewBundleID = newBundleID.toLowerCase();

  return [
    {
      regex: currentBundleID,
      replacement: newBundleID,
      paths: [
        './android/app/BUCK',
        './android/app/build.gradle',
        './android/app/src/main/AndroidManifest.xml',
      ],
    },
    {
      regex: currentBundleID,
      replacement: newBundleID,
      paths: [`./ios/${nS_NewName}.xcodeproj/project.pbxproj`],
    },
    {
      regex: lC_Ns_CurrentBundleID,
      replacement: lC_Ns_NewBundleID,
      paths: [`./ios/${nS_NewName}.xcodeproj/project.pbxproj`],
    },
    {
      regex: currentBundleID,
      replacement: newBundleID,
      paths: [`${newBundlePath}/MainActivity.java`, `${newBundlePath}/MainApplication.java`],
    },
    {
      regex: lC_Ns_CurrentBundleID,
      replacement: lC_Ns_NewBundleID,
      paths: [`${newBundlePath}/MainApplication.java`],
    },
    {
      regex: nS_CurrentAppName,
      replacement: nS_NewName,
      paths: [`${newBundlePath}/MainActivity.java`],
    },
  ];
}

// nS - No Space
// lC - Lowercase

export function bundleIdentifiers(
  currentAppName,
  newName,
  projectName,
  currentBundleID,
  newBundleID,
  newBundlePath
) {
  const nS_CurrentAppName = currentAppName.replace(/\s/g, '');
  const nS_NewName = newName.replace(/\s/g, '');
  const lC_Ns_CurrentBundleID = currentBundleID.toLowerCase();
  const lC_Ns_NewBundleID = newBundleID.toLowerCase();

  return [
    {
      regex: currentBundleID,
      replacement: newBundleID,
      paths: [
        './android/app/BUCK',
        './android/app/build.gradle',
        './android/app/src/main/AndroidManifest.xml',
      ],
    },
    {
      regex: currentBundleID,
      replacement: newBundleID,
      paths: [`${newBundlePath}/MainActivity.java`, `${newBundlePath}/MainApplication.java`],
    },
    {
      regex: lC_Ns_CurrentBundleID,
      replacement: lC_Ns_NewBundleID,
      paths: [`${newBundlePath}/MainApplication.java`],
    },
    {
      regex: nS_CurrentAppName,
      replacement: nS_NewName,
      paths: [`${newBundlePath}/MainActivity.java`],
    },
  ];
}

Remove ios files (use Xcode instead)


#!/usr/bin/env node

var fs        = require('fs'),
    url       = require('url'),
    http      = require('http'),
    prompt    = require('prompt'),
    pecanApp  = require('commander'),
    pecanInfo = require('./package.json');

pecanApp
  .version(pecanInfo.version)
  .command('init', 'Create new PyProcessing project')
  .action(function(){
    console.log('Creating new PyProcessing project');
  })
  .parse(process.argv);

#!/usr/bin/env node

var fs        = require('fs'),
    url       = require('url'),
    http      = require('http'),
    prompt    = require('prompt'),
    pecanApp  = require('commander'),
    pecanInfo = require('./package.json');

// Setup Project
pecanApp
  .version(pecanInfo.version)
  .command('init', 'Create new PyProcessing project');

// Run Project
pecanApp
  .command('run', 'Run Pyprocessing file');

pecanApp.parse(process.argv);

Remove actions .action. Add run command.


class Vec {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }

    plus(v) {
        return new Vec(this.x + v.x, this.y + v.y);
    }

    minus(v) {
        return new Vec(this.x - v.x, this.y - v.y);
    }

    get length() {
        return Math.sqrt(this.x**2 + this.y**2);
    }
}

Add chapter 6, exercise 1


import {Socket} from "phoenix"
window.Experiment = class Experiment {
    constructor(topic, token, update) {
        this.socket = new Socket("/socket")
        this.socket.connect()
        this.chan = this.socket.channel(topic, {token: token})
        if (update != undefined) {
            this.onUpdate(update)
        }
    }

    send_data(data) {
        this.chan.push("client", {body: data})
    }

    onUpdate(func) {
        this.chan.join().receive("ok", _ => {
            this.chan.push("fetch", {})
        })
        this.chan.on("update", payload => {
            func(payload.body)
        })
    }

    onReceiveMessage(func) {
        this.chan.join().receive("ok", _ => {
            this.chan.push("fetch", {})
        })
        this.chan.on("message", payload => {
            func(payload.body)
        })
    }
}

import {Socket} from "phoenix"
window.Experiment = class Experiment {
    constructor(topic, token, update) {
        this.socket = new Socket("/socket")
        this.socket.connect()
        this.chan = this.socket.channel(topic, {token: token})
        if (update != undefined) {
            this.onUpdate(update)
        }
    }

    send_data(data) {
        this.chan.push("client", {body: data})
    }

    onUpdate(func) {
        this.chan.join().receive("ok", _ => {
            this.chan.push("fetch", {})
        })
        this.chan.on("update", payload => {
            func(payload.body)
        })
    }

    onReceiveMessage(func) {
        this.chan.join()
        this.chan.on("message", payload => {
            func(payload.body)
        })
    }
}

Remove fetch step from message-based experiment


/**
 * This file specifies the database collection and field names.
 */
export const COLLECTION_TRIPS = 'trips';
export const TRIPS_TITLE = 'title';
export const TRIPS_DESCRIPTION = 'description';
export const TRIPS_DESTINATION = 'destination';
export const TRIPS_START_DATE = 'start_date';
export const TRIPS_END_DATE = 'end_date';
export const TRIPS_ACCEPTED_COLLABS = 'accepted_collaborator_uid_arr';
export const TRIPS_PENDING_COLLABS = 'pending_collaborator_uid_arr';
export const TRIPS_REJECTED_COLLABS = 'rejected_collaborator_uid_arr';
export const TRIPS_UPDATE_TIMESTAMP = 'update_timestamp';
/**
 * NOTE: The following constant corresponds to the collaborator field in
 * {@link_RawTripData} and is not a field in a trip document.
 */
export const RAW_TRIP_COLLABS

export const COLLECTION_ACTIVITIES = 'activities';
export const ACTIVITIES_START_TIME = 'start_time';
export const ACTIVITIES_END_TIME = 'end_time';
export const ACTIVITIES_START_TZ = 'start_tz';
export const ACTIVITIES_END_TZ = 'end_tz';
export const ACTIVITIES_TITLE = 'title';
export const ACTIVITIES_DESCRIPTION = 'description';
export const ACTIVITIES_START_COUNTRY = 'start_country';
export const ACTIVITIES_END_COUNTRY = 'end_country';

/**
 * This file specifies the database collection and field names.
 */
export const COLLECTION_TRIPS = 'trips';
export const TRIPS_TITLE = 'title';
export const TRIPS_DESCRIPTION = 'description';
export const TRIPS_DESTINATION = 'destination';
export const TRIPS_START_DATE = 'start_date';
export const TRIPS_END_DATE = 'end_date';
export const TRIPS_ACCEPTED_COLLABS = 'accepted_collaborator_uid_arr';
export const TRIPS_PENDING_COLLABS = 'pending_collaborator_uid_arr';
export const TRIPS_REJECTED_COLLABS = 'rejected_collaborator_uid_arr';
export const TRIPS_UPDATE_TIMESTAMP = 'update_timestamp';
/**
 * NOTE: The following constant corresponds to the collaborator field in
 * {@link_RawTripData} and is not a field in a trip document.
 */
export const RAW_TRIP_COLLABS = 'collaborator_email_arr';

export const COLLECTION_ACTIVITIES = 'activities';
export const ACTIVITIES_START_TIME = 'start_time';
export const ACTIVITIES_END_TIME = 'end_time';
export const ACTIVITIES_START_TZ = 'start_tz';
export const ACTIVITIES_END_TZ = 'end_tz';
export const ACTIVITIES_TITLE = 'title';
export const ACTIVITIES_DESCRIPTION = 'description';
export const ACTIVITIES_START_COUNTRY = 'start_country';
export const ACTIVITIES_END_COUNTRY = 'end_country';

Update string for raw trip collab constant.


import React from 'react';
import ConfigForm from '../containers/ConfigForm';

export default class AttackConfig extends React.Component {
    constructor() {
        super();
        this.state = {
            sourceip: '',
            victim_id: ''
        };
    }

    componentWillMount() {
        if (this.props.location.state) {
            this.setState({ sourceip: this.props.location.state.sourceip,
                            victim_id: this.props.location.state.victim_id});
        }
    }

    render() {
        return(

                        <ConfigForm sourceip={ this.state.sourceip } victim_id={ this.state.victim_id }/>

        );
    }
}

import React from 'react';
import axios from 'axios';

import ConfigForm from '../containers/ConfigForm';

export default class AttackConfig extends React.Component {
    constructor() {
        super();
        this.state = {
            sourceip: '',
            victim_id: ''
        };
    }

    componentWillMount = () => {
        if (this.props.params.id) {
            this.setState({ victim_id: this.props.params.id });
            axios.get('/breach/victim/' + this.props.params.id)
            .then(res => {
                this.setState({ sourceip: res.data.victim_ip });
            })
            .catch(error => {
                console.log(error);
            });
        }
    }

    render() {
        console.log(this.state.sourceip);
        return(

                        <ConfigForm sourceip={ this.state.sourceip } victim_id={ this.state.victim_id }/>

        );
    }
}

Make GET /victim/<id> request to get the victimip


/**
 * Communicate back to the web app.
 */

var extensionRoot = (new File($.fileName)).parent + '/';

$.evalFile(extensionRoot + '/constants.js');
$.evalFile(extensionRoot + '/Json.js');
$.evalFile(extensionRoot + '/Saver.js');

function getSettingsPath()
{
	return SP_SETTINGS_PATH;
}

function save(args)
{
	var preset, s;

	preset = Json.eval(args[0]);
	s      = new sp.Saver();
	return Json.encode(s.save(preset));
}

function serializeUi(args)
{
	var file, collapsed;

	file = new File(SP_SETTINGS_PATH + 'ui.json');
	collapsed = [];

	for (i in args[0])
		collapsed.push(args[0][i]);

	if (file.open('w')) {
		file.writeln(Json.encode({ collapsed: collapsed }));
	}
}

/**
 * Communicate back to the web app.
 */

var extensionRoot = (new File($.fileName)).parent + '/';

$.evalFile(extensionRoot + '/constants.js');
$.evalFile(extensionRoot + '/Json.js');
$.evalFile(extensionRoot + '/Saver.js');

function getSettingsPath()
{
	return SP_SETTINGS_PATH;
}

function save(args)
{
	var preset = Json.eval(args[0])
	  , s      = new sp.Saver()
	;
	return Json.encode(s.save(preset));
}

function serializeUi(args)
{
	var file = new File(SP_SETTINGS_PATH + 'ui.json')
	  , collapsed = []
	;

	for (var i in args[0])
		collapsed.push(args[0][i]);

	if (file.open('w')) {
		file.writeln(Json.encode({ collapsed: collapsed }));
	}
}

Use npm style variable declarations.


#!/usr/bin/env node

const { ArgumentParser, Const } = require('argparse');
const { version } = require('../package.json');

const parser = new ArgumentParser({
  version,
  addHelp: true,
  description: 'A simple npm package to generate gh-badges (shields.io) based on lighthouse performance.',
});

parser.addArgument(
  ['-s', '--single-badge'], {
    action: 'storeFalse',
    help: 'Only output one single badge averaging the four lighthouse scores',
  },
);

parser.addArgument(
  ['-u', '--urls'], {
    action: 'store',
    required: true,
    nargs: Const.ONE_OR_MORE,
    help: 'the lighthouse badge(s) will contain the respective average score(s) of all the urls supplied, combined',
  },
);

module.exports = {
  parser,
};

#!/usr/bin/env node

const { ArgumentParser, Const } = require('argparse');
const { version } = require('../package.json');

const parser = new ArgumentParser({
  version,
  addHelp: true,
  description: 'A simple npm package to generate gh-badges (shields.io) based on lighthouse performance.',
});

parser.addArgument(
  ['-s', '--single-badge'], {
    action: 'storeFalse',
    help: 'Only output one single badge averaging the four lighthouse scores',
  },
);

let required_args = parser.addArgumentGroup({title: 'required arguments'});
required_args.addArgument(
  ['-u', '--urls'], {
    action: 'store',
    required: true,
    nargs: Const.ONE_OR_MORE,
    help: 'the lighthouse badge(s) will contain the respective average score(s) of all the urls supplied, combined',
  },
);

module.exports = {
  parser,
};

Add section for required args in argparse


#!/usr/bin/env node
var yargs = require('yargs');

var argv = yargs
  .usage('Sends pino logs to AWS CloudWatch Logs.\nUsage: node index.js | pino-cloudwatch [options]')
  .describe('aws_access_key_id', 'AWS Access Key ID')
  .describe('aws_secret_access_key', 'AWS Secret Access Key')
  .describe('aws_region', 'AWS Region')
  .describe('group', 'AWS CloudWatch log group name')
  .describe('prefix', 'AWS CloudWatch log stream name prefix')
  .describe('interval', 'The maxmimum interval (in ms) before flushing the log queue.')
  .demand('group')
  .default('interval', 1000)
  .wrap(140)
  .argv;

require('../index')(argv);

#!/usr/bin/env node
var yargs = require('yargs');
var pump = require('pump');
var split = require('split2');

var argv = yargs
  .usage('Sends pino logs to AWS CloudWatch Logs.\nUsage: node index.js | pino-cloudwatch [options]')
  .describe('aws_access_key_id', 'AWS Access Key ID')
  .describe('aws_secret_access_key', 'AWS Secret Access Key')
  .describe('aws_region', 'AWS Region')
  .describe('group', 'AWS CloudWatch log group name')
  .describe('prefix', 'AWS CloudWatch log stream name prefix')
  .describe('interval', 'The maxmimum interval (in ms) before flushing the log queue.')
  .demand('group')
  .default('interval', 1000)
  .wrap(140)
  .argv;

pump(process.stdin, split(), require('../index')(argv));

Move piping from stdin to the cli


'use strict';

module.exports = {
    entry: './src/index.ts',
    output: { filename: 'dist/index.js' },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader'
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.tsx', 'js' ]
    }
};

'use strict';

module.exports = {
    entry: './src/index.ts',
    output: { filename: 'dist/index.js' },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'ts-loader'
            }
        ]
    },
    resolve: {
        extensions: [ '.ts', '.tsx', '.js' ]
    }
};

Fix error in vanilla example


// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.
$(document).ready(function() {

    // localize times
    $('.localize').each(function () {
        var element = $(this);
        element.html(moment(element.html()).format('LLL'));
    });
});

// Place all the behaviors and hooks related to the matching controller here.
// All this logic will automatically be available in application.js.

var ready = function() {
    // localize times
    $('.localize').each(function () {
        var element = $(this);
        element.html(moment(element.html()).format('LLL'));
    });
};

$(document).ready(ready);
$(document).on('turbolinks:load', ready);

Fix dates sometimes not being localized on page load.


// import Platform from 'objects/platform';
import { ASSETS } from 'constants';
import Bullet from 'objects/bullet';

export default class Player extends Phaser.Sprite {
  constructor(game, x, y) {
    const { world } = game;

    super(game, x, y, ASSETS.PLAYER, 1);

    game.physics.p2.enable(this, true);

    this.body.setRectangle(20);
    this.body.static = true;
    game.debug.body(this);

    this.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

    this.bullet = new Bullet(game, x, y + 20);
    game.add.existing(this.bullet);
  }

  update() {
    if (this.spaceKey.isDown) {
      console.log('fire!')
      this.fireBullet();
    }
  }

  fireBullet() {
    this.bullet.body.velocity.x = 200;
  }
}

// import Platform from 'objects/platform';
import { ASSETS } from 'constants';
import Bullet from 'objects/bullet';

export default class Player extends Phaser.Sprite {
  constructor(game, x, y) {
    const { world } = game;

    super(game, x, y, ASSETS.PLAYER, 1);

    game.physics.p2.enable(this, true);

    this.body.setRectangle(20);
    this.body.static = true;
    game.debug.body(this);

    this.spaceKey = game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);

    this.bullet = new Bullet(game, x, y + 20);
    game.add.existing(this.bullet);
  }

  update() {
    if (this.spaceKey.isDown) {
      console.log('fire!')
      this.fireBullet();
    }
  }

  fireBullet() {
    this.bullet.body.velocity.x = 500;
    // this.bullet.body.velocity.y = 200;
  }
}

Increase bullet speed for testing


// Using regex instead of simply using 'host' because it causes error with security on Government browsers (IE9 so far)
function getHostname(url) {
    var m = url.match(/^http(s?):\/\/[^/]+/);
    return m ? m[0] : null;
}

function eachAnchor(anchors) {

    $(anchors).each(function() {
        var href = $(this).attr("href");
        var hostname = getHostname(href);

        if (hostname) {
            if (hostname !== document.domain && hostname.indexOf('ons.gov.uk') == -1) {
                $(this).attr('target', '_blank');
            }
        }

    });
}

$(function() {
    eachAnchor('a[href^="http://"]:not([href*="loop11.com"]):not([href*="ons.gov.uk"])');
    eachAnchor('a[href^="https://"]:not([href*="loop11.com"]):not([href*="ons.gov.uk"])');
    eachAnchor('a[href*="nationalarchives.gov.uk"]');
});

// Using regex instead of simply using 'host' because it causes error with security on Government browsers (IE9 so far)
function getHostname(url) {
    var m = url.match(/^http(s?):\/\/[^/]+/);
    return m ? m[0] : null;
}

function eachAnchor(anchors) {

    $(anchors).each(function() {
        var href = $(this).attr("href");
        var hostname = getHostname(href);

        if (hostname) {
            if ((hostname !== document.domain && hostname.indexOf('ons.gov.uk') == -1) || (hostname.indexOf('visual.ons.gov.uk') != -1 )){
                $(this).attr('target', '_blank');
            }
        }

    });
}

$(function() {
    eachAnchor('a[href^="http://"]:not([href*="loop11.com"]):not([href*="ons.gov.uk"])');
    eachAnchor('a[href^="https://"]:not([href*="loop11.com"]):not([href*="ons.gov.uk"])');
    eachAnchor('a[href*="nationalarchives.gov.uk"]');
    eachAnchor('a[href*="visual.ons.gov.uk"]');
});

Add visual.ons to external link formatter (will enable event tracking for outbound clicks)


import * as React from "react";
import { Navigation } from "./Navigation";

/**
 * Main Navigation Component
 */
export const Header = () => {
  const TITLE = "LLVM Build View";

  return (
    <header>
      <Wrapper>
        <span>{TITLE}</span>
      </Wrapper>
      <Navigation/>
    </header>
  );
}

import * as React from "react";
import { Navigation } from "./Navigation";

/**
 * Main Navigation Component
 */
export const Header = () => {
  const TITLE = "LLVM Build View";

  return (

      <Wrapper>
        {TITLE}
      </Wrapper>
      <Navigation/>

  );
}

Add classname to title component


import Ember from 'ember';
import uuid from 'ember-cli-uuid/utils/uuid-helpers';

export default {

  name: 'ember-cli-uuid',

  initialize: function () {

    console.log('uuid: ', uuid);
    DS.RESTAdapter.reopen({

      generateIdForRecord: function () {
        return uuid();
      }

    });
  }

};

import Ember from 'ember';
import uuid from 'ember-cli-uuid/utils/uuid-helpers';

export default {

  name: 'ember-cli-uuid',

  initialize: function () {

    console.log('Adapter');
    DS.Adapter.reopen({

      generateIdForRecord: function () {
        return uuid();
      }

    });
  }

};

Expand the addon to all adapters


(function(){
	if(!'Event' in window) return false;

	if(typeof window.Event === 'function') return true;

	var result = true;
	try{
		new Event('click');
	}catch(e){
		result = false;
	}

	return result;
}())

(function(){
	if(!'Event' in window) return false;

	if(typeof window.Event === 'function') return true;

	try{
		new Event('click');
		return true;
	}catch(e){
		return false;
	}
}());

Add missing semicolon, avoid var assignment


var VirtualMachine = require('./virtualMachine');

//define a criteria for a virtual machines search
//inherit of all property of a virtual machine
module.exports = VirtualMachine.extend({
	//Override the application validation, in order to not block the search.
	validation: {}
});

var VirtualMachine = require('./virtualMachine');

/*
  Define a criteria for a virtual machines search
  inherit of all property of a virtual machine with
  the extend method which is inherit by the Backbone.Model
*/
module.exports = VirtualMachine.extend({
	//Override the application validation.
	//If we have a required criteria in the search object it would be defined here.
	validation: {}
});

Add the VirtualMachione model comment.


'use strict';

var Database   = require('dbjs')
  , defineDate = require('dbjs-ext/date-time/date');

module.exports = function (t, a) {
	var db = new Database()
	  , toDateInTimeZone;

	defineDate(db);
	toDateInTimeZone = t(db);

	var mayanEndOfTheWorld = new Date(2012, 11, 21, 1, 1);

	a.deep(toDateInTimeZone(mayanEndOfTheWorld, 'America/Guatemala').valueOf(),
		new db.Date(2012, 11, 20).valueOf());
	a.deep(toDateInTimeZone(mayanEndOfTheWorld, 'Europe/Poland').valueOf(),
		new db.Date(2012, 11, 21).valueOf());
};

'use strict';

var db         = require('../../db')
  , defineDate = require('dbjs-ext/date-time/date');

module.exports = function (t, a) {
	defineDate(db);

	var mayanEndOfTheWorld = new Date(2012, 11, 21, 1, 1);

	a.deep(t(mayanEndOfTheWorld, 'America/Guatemala').valueOf(),
		new db.Date(2012, 11, 20).valueOf());
	a.deep(t(mayanEndOfTheWorld, 'Europe/Poland').valueOf(),
		new db.Date(2012, 11, 21).valueOf());
};

Update test after recent changes