const activitiesByTimestamp = {
  // activityTimestamps: [1488058736421, 1488058788421, 1488058446421, 1488051326421, 1488051326555]
  1488058736421: {
    text: "hang at Golden Gate park 🍺",
  },
  1488078736421: {
    text: "soak up some 🌞 at Dolores park",
  },
  1488058788421: {
    text: "climb at Planet Granite -- 3 hours",
  },
  1488058446421: {
    text: "run 4.5 miles 🏃",
  },
  1488059646421: {
    text: "surfing 🏄 with Salar in Santa Cruz",
  },
  1488051326421: {
    text: "read Infinite Jest -- 40 pages",
  },
  1488051326555: {
    text: "read Code by Petzold -- 90 pages",
  }
}

export default activitiesByTimestamp;

const activitiesByTimestamp = {
  1488058736421: {
    text: "hang at Golden Gate park 🍺",
  },
  1488078736421: {
    text: "soak up some 🌞 at Dolores park",
  },
  1487558788421: {
    text: "climb at Planet Granite -- 3 hours",
  },
  1488058446421: {
    text: "run 4.5 miles 🏃",
  },
  1486959646421: {
    text: "surfing 🏄 with Salar in Santa Cruz",
  },
  1488051326421: {
    text: "read Infinite Jest -- 40 pages",
  },
  1488051326555: {
    text: "read Code by Petzold -- 90 pages",
  }
}

export default activitiesByTimestamp;

Add some other dates into sample activities


define(function(require){

    var scene = new THREE.Object3D();
    var camera = new THREE.PerspectiveCamera(75, 16 / 9, 0.1, 5000);

    camera.position.set(0, 0, 5);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    var cube = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshBasicMaterial({color: 0xFF00FF})
    );

    scene.add(cube);

    return {
        scene: scene,
        camera: camera,
        render: function(time){
            cube.rotation.x = time;
            cube.rotation.y = time;
        },
        onEvent: function(event) {

        },
        init: function(args){

        }
    };
});

define(function(require){

    var scene = new THREE.Object3D();
    var camera = new THREE.PerspectiveCamera(75, 16 / 9, 0.1, 5000);

    camera.position.set(0, 0, 5);
    camera.lookAt(new THREE.Vector3(0, 0, 0));

    var cube = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshBasicMaterial({color: 0xFF88FF})
    );

    scene.add(cube);

    return {
        scene: scene,
        camera: camera,
        render: function(time){
            cube.rotation.x = time;
            cube.rotation.y = time;
        },
        onEvent: function(event) {

        },
        init: function(args){

        }
    };
});

Change colour of the cube for basic scene.


const notify = (events) => ({ dispatch }) => next => action => {
  const returnValue = next(action);
  events.forEach( event => {
    if (event.catch.indexOf(action.type) !== -1) {
      dispatch(event.dispatch());
    }
  });
  return returnValue;
};

export default notify;

const notify = (events) => ({ dispatch }) => next => action => {
  const returnValue = next(action);
  events.forEach( event => {
    if (event.catch.indexOf(action.type) !== -1) {
      if (event.dispatch instanceof Function) dispatch(event.dispatch());
      else if (event.dispatch instanceof Array) {
        event.dispatch.forEach( fn => setTimeout(() => { dispatch(fn()) }, 0) );
      }
      else throw new Error('Expected dispatch value to be a function or an array of functions.');
    }
  });
  return returnValue;
};

export default notify;

Allow to dispatch an array of actions in parallel.


const path = require('path');

let version;

module.exports = {
  Client: require('./client/Client'),
  Shard: require('./sharding/Shard'),
  ShardingManager: require('./sharding/ShardingManager'),
  Collection: require('./util/Collection'),

  get version() {
    if (!version) version = require(path.join(__dirname, '..', 'package.json')).version;
    return version;
  },
};

const path = require('path');

module.exports = {
  Client: require('./client/Client'),
  Shard: require('./sharding/Shard'),
  ShardingManager: require('./sharding/ShardingManager'),
  Collection: require('./util/Collection'),
  version: require(path.join(__dirname, '..', 'package.json')).version,
};

Make version a regular property instead of getter


privacyOptions = { // true means exposed
  _id: true,
  commentCount: true,
  createdAt: true,
  email_hash: true,
  isInvited: true,
  karma: true,
  postCount: true,
  slug: true,
  username: true,
  'profile.name': true,
  'profile.notifications': true,
  'profile.bio': true,
  'profile.github': true,
  'profile.site': true,
  'profile.twitter': true,
  'services.twitter.profile_image_url': true,
  'services.facebook.id': true,
  'services.twitter.screenName': true,
  'services.github.screenName': true, // Github is not really used, but there are some mentions to it in the code
  'votes.downvotedComments': true,
  'votes.downvotedPosts': true,
  'votes.upvotedComments': true,
  'votes.upvotedPosts': true
};

// minimum required properties to display avatars
avatarOptions = {
  _id: true,
  email_hash: true,
  slug: true,
  username: true,
  'profile.name': true,
  'profile.github': true,
  'profile.twitter': true,
  'services.twitter.profile_image_url': true,
  'services.facebook.id': true,
  'services.twitter.screenName': true,
  'services.github.screenName': true, // Github is not really used, but there are some mentions to it in the code
}

privacyOptions = { // true means exposed
  _id: true,
  commentCount: true,
  createdAt: true,
  email_hash: true,
  isInvited: true,
  karma: true,
  postCount: true,
  slug: true,
  username: true,
  'profile.name': true,
  'profile.notifications': true,
  'profile.bio': true,
  'profile.github': true,
  'profile.site': true,
  'profile.twitter': true,
  'services.twitter.profile_image_url': true,
  'services.twitter.profile_image_url_https': true,
  'services.facebook.id': true,
  'services.twitter.screenName': true,
  'services.github.screenName': true, // Github is not really used, but there are some mentions to it in the code
  'votes.downvotedComments': true,
  'votes.downvotedPosts': true,
  'votes.upvotedComments': true,
  'votes.upvotedPosts': true
};

// minimum required properties to display avatars
avatarOptions = {
  _id: true,
  email_hash: true,
  slug: true,
  username: true,
  'profile.name': true,
  'profile.github': true,
  'profile.twitter': true,
  'services.twitter.profile_image_url': true,
  'services.facebook.id': true,
  'services.twitter.screenName': true,
  'services.github.screenName': true, // Github is not really used, but there are some mentions to it in the code
}

Fix broken twitter avatars - services.twitter.profile_image_url_https field wasn't being published


import moment from 'moment';

const DefaultDateFormat = 'YYYY-MM-DD';
const DefaultTimeFormat = 'HH:mm:ss';
const DefaultDateTimeFormat = 'YYYY-MM-DD HH:mm:ss';

export default function renderDate(date, formFormat, displayFormat) {
	let format;
	if (displayFormat) format = displayFormat;
	else if (formFormat === 'time') format = DefaultTimeFormat;
	else if (formFormat === 'dateTime') format = DefaultDateTimeFormat;
	else format = DefaultDateFormat;
	return moment(new Date(date)).format(format);
}

import moment from 'moment';

const DefaultDateFormat = 'YYYY-MM-DD';
const DefaultTimeFormat = 'HH:mm:ss';
const DefaultDateTimeFormat = 'YYYY-MM-DD HH:mm:ss';

export default function renderDate(date, formFormat, displayFormat) {
	if (!date) return '';
	let format;
	if (displayFormat) format = displayFormat;
	else if (formFormat === 'time') format = DefaultTimeFormat;
	else if (formFormat === 'dateTime') format = DefaultDateTimeFormat;
	else format = DefaultDateFormat;
	return moment(new Date(date)).format(format);
}

Fix "Invalid date" bug in date related components


/* global angular */
(function() {
    angular.module("googlechart")
        .factory("agcScriptTagHelper", agcScriptTagHelperFactory);

    agcScriptTagHelperFactory.$inject = ["$q"];
    function agcScriptTagHelperFactory($q)
    {
        /** Add a script tag to the document's head section and return an angular
          * promise that resolves when the script has loaded.
          */
        function agcScriptTagHelper(url)
        {
            var deferred = $q.defer();
            var head = document.getElementsByTagName('head')[0];
            var script = document.createElement('script');

            script.setAttribute('type', 'text/javascript');
            script.src = url;

            if (script.addEventListener) { // Standard browsers (including IE9+)
                script.addEventListener('load', onLoad, false);
                script.onerror = onError;
            } else { // IE8 and below
                script.onreadystatechange = function () {
                    if (script.readyState === 'loaded' || script.readyState === 'complete') {
                        script.onreadystatechange = null;
                        onLoad();
                    }
                };
            }
            head.appendChild(script);

            function onLoad() {
                deferred.resolve();
            }

            function onError() {
                deferred.reject();
            }

            return deferred.promise;
        }

        return agcScriptTagHelper;
    }
})();

/* global angular */
(function() {
    angular.module("googlechart")
        .factory("agcScriptTagHelper", agcScriptTagHelperFactory);

    agcScriptTagHelperFactory.$inject = ["$q", "$document"];
    function agcScriptTagHelperFactory($q, $document)
    {
        /** Add a script tag to the document's head section and return an angular
          * promise that resolves when the script has loaded.
          */
        function agcScriptTagHelper(url)
        {
            var deferred = $q.defer();
            var head = $document.getElementsByTagName('head')[0];
            var script = $document.createElement('script');

            script.setAttribute('type', 'text/javascript');
            script.src = url;

            if (script.addEventListener) { // Standard browsers (including IE9+)
                script.addEventListener('load', onLoad, false);
                script.onerror = onError;
            } else { // IE8 and below
                script.onreadystatechange = function () {
                    if (script.readyState === 'loaded' || script.readyState === 'complete') {
                        script.onreadystatechange = null;
                        onLoad();
                    }
                };
            }
            head.appendChild(script);

            function onLoad() {
                deferred.resolve();
            }

            function onError() {
                deferred.reject();
            }

            return deferred.promise;
        }

        return agcScriptTagHelper;
    }
})();

Use $document for unit test suppport.


import scripts from './scripts';
import shortcut from './shortcut';
import setUserRequire from './require';

module.exports = {
  scripts,
  setUserRequire,
  shortcut
}

import scripts from './scripts';
import shortcut from './shortcut';
import setUserRequire from './require';
import log from './log';

module.exports = {
  scripts,
  setUserRequire,
  shortcut,
  log
}

Add log to module exports


const uuidV4 = require('uuid/v4');

class SocketAdapter {
  constructor(uuid) {
    this.uuid = uuid;
    this.conn = {
      remoteAddress: `socket-adapter: ${this.uuid}`,
    };
    this.pair = null;
    this.callbacks = {};
  }

  trigger(name, data) {
    this.callbacks[name](data);
  }

  emit(name, data) {
    if (!this.pair) {
      throw new Error('Trying to emit on an unpaired socket adapter');
    }
    this.pair.trigger(name, data);
  }

  on(name, callback) {
    this.callbacks[name] = callback;
  }
}

function createAdapterPair() {
  const adapter1 = new SocketAdapter(uuidV4());
  const adapter2 = new SocketAdapter(uuidV4());

  adapter1.pair = adapter2;
  adapter2.pair = adapter1;

  return [adapter1, adapter2];
}

module.exports = createAdapterPair;

const uuidV4 = require('uuid/v4');

class SocketAdapter {
  constructor(uuid) {
    this.uuid = uuid;
    this.conn = {
      remoteAddress: `socket-adapter: ${this.uuid}`,
    };
    this.pair = null;
    this.callbacks = {};
  }

  trigger(name, data) {
    if (this.callbacks[name]) {
      this.callbacks[name](data);
    }
  }

  emit(name, data) {
    if (!this.pair) {
      throw new Error('Trying to emit on an unpaired socket adapter');
    }
    this.pair.trigger(name, data);
  }

  on(name, callback) {
    this.callbacks[name] = callback;
  }
}

function createAdapterPair() {
  const adapter1 = new SocketAdapter(uuidV4());
  const adapter2 = new SocketAdapter(uuidV4());

  adapter1.pair = adapter2;
  adapter2.pair = adapter1;

  return [adapter1, adapter2];
}

module.exports = createAdapterPair;

Fix unregistered socket adapter triggers


Template.notificationBadge.helpers({
  count: function () {
    // TODO: find a better way ?
    this._count = this._count || this.count;

    if (this.count !== this._count) {
      $('.notification-count')
        .css({ opacity: 0 })
        .css({ top: '-3px' })
        .animate({ top: '5px', opacity: 1 });
    }

    return this.count;
  }
});

Template.notificationBadge.helpers({
  count: function () {
    // access template instance instead of 'this',
    // which only returns the data context
    var self = Template.instance();

    self._count = self._count || this.count;

    if (this.count !== self._count) {
      Meteor.defer(function () {
        $('.notification-count')
          .css({ opacity: 0 })
          .css({ top: '-20px' })
          .animate({ top: '-8px', opacity: 1 });
      });

      self._count = this.count;
    }

    return this.count;
  }
});

Fix animation and count checking


window.onload=function(){
var theNumber = _.random(1, 100);
var theList = $("#list");
var theBanner = $("#triumph");

$("#submit").click(function() {
  var theGuess = $("#guess").val();
  $("#guess").val("");
  if (theGuess === theNumber) {

    $("#submit").prop('disabled', true);
    $("#guess").prop('disabled', true);
    theBanner.text("That's right! " + theGuess + " is the number of which I am thinking.");
    theBanner.append('
<button onClick="location.reload(true);" >Play again</button>');

  } else if (theGuess < theNumber) {

    theList.append("
" + getRandomPhrase() + theGuess + " is too low.
");

  } else {

    theList.append("
" + getRandomPhrase() + theGuess + " is too high
");
  }

});

$("#guess").keyup(function(event) {
  if (event.keyCode === 13) {
    $("#submit").click();
  }
});

function getRandomPhrase() {
  var phrases = [
    "No. ",
    "Nope. ",
    "Guess again. ",
    "Give it another try. ",
    "That's not it. ",
    "Well, not quite. ",
    "Okay. You can try again. ",
    "No reason to give up now. ",
    "Nah. ",
    "Naw. ",
    "I hope you get it next time. "
  ]
  var index = _.random(0, phrases.length - 1);
  return phrases[index];
}

}

window.onload=function(){
var theNumber = _.random(1, 100);
var theList = $("#list");
var theBanner = $("#triumph");

$("#submit").click(function() {
  var theGuess = $("#guess").val();
  $("#guess").val("");
  if (theGuess == theNumber) {

    $("#submit").prop('disabled', true);
    $("#guess").prop('disabled', true);
    theBanner.text("That's right! " + theGuess + " is the number of which I am thinking.");
    theBanner.append('
<button onClick="location.reload(true);" >Play again</button>');

  } else if (theGuess < theNumber) {

    theList.append("
" + getRandomPhrase() + theGuess + " is too low.
");

  } else {

    theList.append("
" + getRandomPhrase() + theGuess + " is too high
");
  }

});

$("#guess").keyup(function(event) {
  if (event.keyCode === 13) {
    $("#submit").click();
  }
});

function getRandomPhrase() {
  var phrases = [
    "No. ",
    "Nope. ",
    "Guess again. ",
    "Give it another try. ",
    "That's not it. ",
    "Well, not quite. ",
    "Okay. You can try again. ",
    "No reason to give up now. ",
    "Nah. ",
    "Naw. ",
    "I hope you get it next time. "
  ]
  var index = _.random(0, phrases.length - 1);
  return phrases[index];
}

}

Use '==' because '===' causes undesired behavior


var GitHub = require( '../../lib/Webmaker.js' ).github;

module.exports = {
  tags: function( req, res ) {
    GitHub.tags( req.params.repo, function( err, tags ) {
      if ( err ) {
        res.json( 500, { error: 'Unable to get tags for repo ' + repo + '.' } );
        return;
      }
      res.json( tags );
    });
  },
  commits: function( req, res ) {
    GitHub.commits( req.params.repo, function( err, commits ) {
      if ( err ) {
        res.json( 500, { error: 'Unable to get commits for repo ' + req.params.repo + '.' } );
        return;
      }
      res.json( commits );
    });
  },
};

var GitHub = require( '../../lib/Webmaker.js' ).github;

module.exports = {
  tags: function( req, res ) {
    GitHub.tags( req.params.repo, function( err, tags ) {
      if ( err ) {
        res.json( 500, { error: 'Unable to get tags for repo ' + req.params.repo + '.' } );
        return;
      }
      res.json( tags );
    });
  },
  commits: function( req, res ) {
    GitHub.commits( req.params.repo, function( err, commits ) {
      if ( err ) {
        res.json( 500, { error: 'Unable to get commits for repo ' + req.params.repo + '.' } );
        return;
      }
      res.json( commits );
    });
  },
};

Fix typo in tags error message.


describe("Utilities", function() {
	it("should get the domain", function() {
		expect(getDomain('http://www.google.com')).toMatch('www.google.com');
		expect(getDomain('http://www.google.com/')).toMatch('www.google.com');
		expect(getDomain('http://www.google.com/kitty')).toMatch('www.google.com');

		expect(getDomain('https://www.google.com')).toMatch('www.google.com');
		expect(getDomain('https://www.google.com/')).toMatch('www.google.com');
		expect(getDomain('https://www.google.com/kitty')).toMatch('www.google.com');
	});

	it("should get the hostname", function() {
		expect(getDomain('http://www.google.com')).toMatch('google.com');
		expect(getDomain('http://www.google.com/')).toMatch('google.com');
		expect(getDomain('http://www.google.com/kitty')).toMatch('google.com');

		expect(getDomain('https://www.google.com')).toMatch('google.com');
		expect(getDomain('https://www.google.com/')).toMatch('google.com');
		expect(getDomain('https://www.google.com/kitty')).toMatch('google.com');
	});
});

describe("An array", function() {
	it("should insert an element at an arbitrary index", function() {
		var arr = [1, 2, 3, 4];
		arr.insertAtIndex(0, 1);
		expect(arr).toEqual([1, 0, 2, 3, 4]);
	});
});

Add test for reordering elements in an Array.


module.exports = {
  modules: false,
  presets: [
    ["latest", { es2015: { modules: false } }],
    "es2015-rollup",
    "react",
    "stage-0"
  ]
};

module.exports = {
  babelrc: false,
  presets: [
    ["latest", { es2015: { modules: false } }],
    "es2015-rollup",
    "react",
    "stage-0"
  ]
};

Fix issue with babel config error in UMD build.


'use strict';

var autoprefixer = require('autoprefixer-core')
  , cssAid       = require('css-aid/process')
  , cssAidRules  = [require('css-aid/rules/variables')]
  , getFiles     = require('./css-bundle-get-files');

module.exports = function (indexPath/*, options */) {
	return getFiles(indexPath, arguments[1])(function (data) {
		return cssAid(autoprefixer.process(data.reduce(function (content, data) {
			return content + '/* ' + data.filename + ' */\n\n' + data.content + '\n';
		}, '').slice(0, -1)).css, cssAidRules);
	});
};

'use strict';

var autoprefixer = require('autoprefixer')
  , cssAid       = require('css-aid/process')
  , cssAidRules  = [require('css-aid/rules/variables')]
  , getFiles     = require('./css-bundle-get-files');

module.exports = function (indexPath/*, options */) {
	return getFiles(indexPath, arguments[1])(function (data) {
		return cssAid(autoprefixer.process(data.reduce(function (content, data) {
			return content + '/* ' + data.filename + ' */\n\n' + data.content + '\n';
		}, '').slice(0, -1)).css, cssAidRules);
	});
};

Update to use autoprefixer directly


import MemoryFileSystem from 'memory-fs'
import tty from 'tty'
import path from 'path'
import webpack from 'webpack'

export default function plugin (config) {
  const compiler = webpack(config)
  compiler.outputFileSystem = new MemoryFileSystem()
  return function (files, metalsmith, done) {
    compiler.run((err, stats) => {
      if (err) {
        done(err)
        return
      }
      const info = stats.toString({
        chunkModules: false,
        colors: isStdoutATTY()  // Output colors iff stdout has a controlling terminal
      })
      if (stats.hasErrors()) {
        done(info)
        return
      }
      console.log(info)
      compiler.outputFileSystem.readdirSync(config.output.path).forEach(file => {
        const filePath = path.join(config.output.path, file)
        const key = path.relative(metalsmith.destination(), filePath)
        files[key] = {
          contents: compiler.outputFileSystem.readFileSync(filePath)
        }
      })
      return done()
    })
  }
}

function isStdoutATTY () {
  return tty.isatty(1 /* stdout */)
}

import MemoryFileSystem from 'memory-fs'
import tty from 'tty'
import path from 'path'
import webpack from 'webpack'

export default function plugin (config) {
  const compiler = webpack(config)
  compiler.outputFileSystem = new MemoryFileSystem()
  return function (files, metalsmith, done) {
    compiler.run((err, stats) => {
      if (err) {
        done(err)
        return
      }
      const info = stats.toString({
        chunkModules: false,
        colors: isStdoutATTY()  // Output colors iff stdout has a controlling terminal
      })
      if (stats.hasErrors()) {
        done(info)
        return
      }
      console.log(info)
      /*
       * Webpack requires the output path `config.output.path` to be an *absolute* path,
       * but metalsmith `files` expects keys that are file paths relative to metalsmith's
       * build directory.
       *
       * Read webpack's output files and assign them relative paths in metalsmith's `files`
       */
      compiler.outputFileSystem.readdirSync(config.output.path).forEach(filename => {
        const filePath = path.join(config.output.path, filename)
        const key = path.relative(metalsmith.destination(), filePath)
        files[key] = {
          contents: compiler.outputFileSystem.readFileSync(filePath)
        }
      })
      return done()
    })
  }
}

function isStdoutATTY () {
  return tty.isatty(1 /* stdout */)
}

Add comment to describe the output files


'use strict';

var bluebird = require('bluebird');
var fs       = bluebird.promisifyAll(require('fs'));
var hljs     = require('../../build');
var path     = require('path');
var utility  = require('../utility');

function testAutoDetection(language) {
  var languagePath = utility.buildPath('detect', language);

  it('should have test for ' + language, function(done) {
    fs.exists(languagePath, function(testExistence) {
      testExistence.should.be.true;
      done();
    });
  });

  it('should be detected as ' + language, function(done) {
    fs.readdirAsync(languagePath)
      .map(function(example) {
        var filename = path.join(languagePath, example);

        return fs.readFileAsync(filename, 'utf-8');
      })
      .each(function(content) {
        var expected = language,
            actual   = hljs.highlightAuto(content).language;

        actual.should.equal(expected);
      })
      .finally(done);
  });
}

describe('.highlightAuto', function() {
  var languages = hljs.listLanguages();

  languages.forEach(testAutoDetection);
});

'use strict';

var bluebird = require('bluebird');
var fs       = bluebird.promisifyAll(require('fs'));
var hljs     = require('../../build');
var path     = require('path');
var utility  = require('../utility');

function testAutoDetection(language) {
  var languagePath = utility.buildPath('detect', language);

  it('should have test for ' + language, function(done) {
    fs.exists(languagePath, function(testExistence) {
      testExistence.should.be.true;
      done();
    });
  });

  it('should be detected as ' + language, function(done) {
    fs.readdirAsync(languagePath)
      .map(function(example) {
        var filename = path.join(languagePath, example);

        return fs.readFileAsync(filename, 'utf-8');
      })
      .each(function(content) {
        var expected = language,
            actual   = hljs.highlightAuto(content).language;

        actual.should.equal(expected);
      })
      .done(function () {
        done();
      }, function (error) {
        done(error);
      });
  });
}

describe('.highlightAuto', function() {
  var languages = hljs.listLanguages();

  languages.forEach(testAutoDetection);
});

Fix detection tests silent fails


describe("The constructor is supposed a proper Captcha object", function() {
    it('Constructor Captcha exists', function(){
        expect(Captcha).toBeDefined();
    });
});

describe("The constructor is supposed a proper Captcha object", function() {
    it('Constructor Captcha exists', function(){
        expect(Captcha).toBeDefined();
    });
    it("Captcha object is not null", function(){
       expect(captcha).not.toBeNull();
    });
});

Add test to chekc if captcha object is null. The test fails


'use strict';

var debug          = require('debug')('fundation:redis');
var Redis          = require('ioredis');

//
// Redis
//
module.exports = function(app) {

  // Check if there is any configuration for Redis
  var server = app.get('config').redis;
  if ( !server ) {
    return;
  }

  return new Promise(function(resolve, reject) {

    debug('Setting up Redis');

    var client = new Redis({
      sentinels: [
        {
          host: server.host,
          port: server.port
        }
      ],
      name: server.name
    });

    client.on('error', function(err) {
      console.error('Redis error: ' + err);

      app.set('redis', false);

      resolve(true);
    });

    client.on('ready', function(err) {
      app.set('redis', client);

      resolve(true);
    });
  });

};

'use strict';

var debug          = require('debug')('fundation:redis');
var Redis          = require('ioredis');

//
// Redis
//
module.exports = function(app) {

  // Check if there is any configuration for Redis
  var server = app.get('config').redis;
  if ( !server ) {
    return;
  }

  return new Promise(function(resolve, reject) {

    debug('Setting up Redis');

    var client = new Redis({
      sentinels: [
        {
          host: server.host,
          port: server.port
        }
      ],
      name: server.name,
      sentinelRetryStrategy : (times) => {
        if (times >= 5) {
          return null;
        }

        return Math.min(times * 10, 1000);
      }
    });

    client.on('error', function(err) {
      console.error('Redis error: ' + err);

      app.set('redis', false);

      resolve(true);
    });

    client.on('ready', function(err) {
      app.set('redis', client);

      resolve(true);
    });
  });

};

Add Redis sentinelRetryStrategy function in Redis config to prevent constant retries


var $ = require('jquery');

module.exports = function(namespace) {
    var toggleSelector = '[data-' + namespace + '-toggle]';
    var openClass = namespace + '--open';

    var body = $(document.body).addClass(namespace);

    $(document)
        .on('click.' + namespace, toggleSelector, function(e) {
            e.preventDefault();

            var expanded = body
                .toggleClass(openClass)
                .hasClass(openClass)
            ;

            $(toggleSelector)
                .attr('aria-expanded', (expanded ? 'true' : 'false'))
                .trigger(namespace + ':' + (expanded ? 'open' : 'close'), [this]);
        })
    ;
};

var $ = require('jquery');

module.exports = function(namespace) {
    var toggleSelector = '[data-' + namespace + '-toggle]';
    var openClass = namespace + '--open';

    var root = $('html').addClass(namespace);

    $(document)
        .on('click.' + namespace, toggleSelector, function(e) {
            e.preventDefault();

            var expanded = root
                .toggleClass(openClass)
                .hasClass(openClass)
            ;

            $(toggleSelector)
                .attr('aria-expanded', (expanded ? 'true' : 'false'))
                .trigger(namespace + ':' + (expanded ? 'open' : 'close'), [this]);
        })
    ;
};

Fix adding root class to html, not body


/* global document, $ */
/* Project specific Javascript goes here. */

/*
Formatting hack to get around crispy-forms unfortunate hardcoding
in helpers.FormHelper:

    if template_pack == 'bootstrap4':
        grid_colum_matcher = re.compile('\w*col-(xs|sm|md|lg|xl)-\d+\w*')
        using_grid_layout = (grid_colum_matcher.match(self.label_class) or
                             grid_colum_matcher.match(self.field_class))
        if using_grid_layout:
            items['using_grid_layout'] = True

Issues with the above approach:

1. Fragile: Assumes Bootstrap 4's API doesn't change (it does)
2. Unforgiving: Doesn't allow for any variation in template design
3. Really Unforgiving: No way to override this behavior
4. Undocumented: No mention in the documentation, or it's too hard for me to find
*/
$('.form-group').removeClass('row');

const registerCSRFTokenAjaxFilter = () => {
  const csrfToken = document.getElementsByName('csrfmiddlewaretoken')[0].value;
  $.ajaxPrefilter((options, originalOptions, jqXHR) => {
    jqXHR.setRequestHeader('X-CSRFToken', csrfToken);
  });
};

registerCSRFTokenAjaxFilter();

/* global document, $ */
/* Project specific Javascript goes here. */

/*
Formatting hack to get around crispy-forms unfortunate hardcoding
in helpers.FormHelper:

    if template_pack == 'bootstrap4':
        grid_colum_matcher = re.compile('\w*col-(xs|sm|md|lg|xl)-\d+\w*')
        using_grid_layout = (grid_colum_matcher.match(self.label_class) or
                             grid_colum_matcher.match(self.field_class))
        if using_grid_layout:
            items['using_grid_layout'] = True

Issues with the above approach:

1. Fragile: Assumes Bootstrap 4's API doesn't change (it does)
2. Unforgiving: Doesn't allow for any variation in template design
3. Really Unforgiving: No way to override this behavior
4. Undocumented: No mention in the documentation, or it's too hard for me to find
*/
$('.form-group').removeClass('row');

const registerCSRFTokenAjaxFilter = () => {
  const csrfTokenElement = document.getElementsByName('csrfmiddlewaretoken')[0];
  if (!csrfTokenElement) {
    return;
  }
  const csrfToken = document.getElementsByName('csrfmiddlewaretoken')[0].value;
  $.ajaxPrefilter((options, originalOptions, jqXHR) => {
    jqXHR.setRequestHeader('X-CSRFToken', csrfToken);
  });
};

registerCSRFTokenAjaxFilter();

Add defensive logic to csrf-ajax-filter


var chai = require('chai');
var expect = chai.expect;
var models = require('../server/db/models');
var request = require('request');
var localServerUri = 'http://127.0.0.1:3000/';
var GETUri = localServerUri + '?x=100.123456&y=-50.323&z=14.4244';
var testData = {x: 100.123456, y: -50.323, z: 14.4244, message: 'hello database!'};

describe('server to database integration', function() {
  it('should persist valid POST request to database', function(done) {
    request.post({url:localServerUri, form: testData}, function(err, response, body) {
      models.retrieve(testData, function(messages) {
        var messageString = messages[0].messageString;
        expect(messageString).to.equal(testData.message);
        done();
      });
    });
  });

  it('should GET messages from databases', function(done) {
    request(GETUri, function(err, response, body) {
      var messages = JSON.parse(response.body);
      expect(messages).to.be.a('array');
      done();
    });
  });
});

var chai = require('chai');
var expect = chai.expect;
var models = require('../server/db/models');
var request = require('request');
var localServerUri = 'http://127.0.0.1:3000/';
var GETUri = localServerUri + '?x=100.123456&y=-50.323&z=14.4244';
var testData = {x: 100.123456, y: -50.323, z: 14.4244, message: 'hello database!'};

describe('server to database integration', function() {

  after(function() {
    models.removeData('marks', 'x', 100.123459);
    models.removeData('messages', 'messageString', "'hello database!'");
  });

  it('should persist valid POST request to database', function(done) {
    request.post({url:localServerUri, form: testData}, function(err, response, body) {
      models.retrieve(testData, function(messages) {
        var messageString = messages[0].messageString;
        expect(messageString).to.equal(testData.message);
        done();
      });
    });
  });

  it('should GET messages from databases', function(done) {
    request(GETUri, function(err, response, body) {
      var messages = JSON.parse(response.body);
      expect(messages).to.be.a('array');
      done();
    });
  });
});

Remove test data from database after tests are run


const path = require('path');
const webpack = require('webpack');
const banner = require('./banner');

module.exports = {
  entry: './src/api/v4/index.js',
  output: {
    path: path.resolve(__dirname, '../dist/public'),
    filename: 'carto.js',
    library: 'carto',
    libraryTarget: 'umd'
  },
  plugins: [
    // Include only the lastest camshaft-reference
    new webpack.IgnorePlugin(/^\.\/((?!0\.59\.4).)*\/reference\.json$/),
    new webpack.BannerPlugin(banner)
  ]
};

const path = require('path');
const webpack = require('webpack');
const banner = require('./banner');

module.exports = {
  entry: './src/api/v4/index.js',
  output: {
    path: path.resolve(__dirname, '../dist/public'),
    filename: 'carto.js',
    library: 'carto',
    libraryTarget: 'umd'
  },
  devtool: 'sourcemap',
  plugins: [
    // Include only the lastest camshaft-reference
    new webpack.IgnorePlugin(/^\.\/((?!0\.59\.4).)*\/reference\.json$/),
    new webpack.BannerPlugin(banner)
  ]
};

Add sourcemap generation to build script


'use strict';

var R = require('ramda');

function onPrClose() {

}

function writeSuccess(res, result) {
  res.send(':)');
}

function writeFailure(res, err) {
  res.send(':(');
}

function pullRequestRouteHandler(req, res) {
  var body = req.body;

  var onSucess = R.curry(writeSuccess)(res);
  var onFail   = R.curry(writeFailure)(res);

  var ghAction = body.action;
  var ghEventType = req.header('X-Github-Event')

  if(ghEventType !== 'pull_request') {
    res.status(403)
       .send('Pull requests only!');
  }

  if(ghAction === 'closed') {
    onPrClose(body)
      .then(onSuccess, onFail);
  } else {
    res.status(403)
       .send('We only want "closed" PR events right now.');
  }
}

module.exports = pullRequestRouteHandler;

'use strict';

var R = require('ramda');

function onPrClose() {
  return q.resolve();
}

function writeSuccess(res, result) {
  res.send(':)');
}

function writeFailure(res, err) {
  res.send(':(');
}

function pullRequestRouteHandler(req, res) {
  var body = req.body;

  var onSucess = R.curry(writeSuccess)(res);
  var onFail   = R.curry(writeFailure)(res);

  var ghAction = body.action;
  var ghEventType = req.header('X-Github-Event')

  if(ghEventType !== 'pull_request') {
    res.status(403)
       .send('Pull requests only!');
  }

  if(ghAction === 'closed') {
    onPrClose(body)
      .then(onSuccess, onFail);
  } else {
    res.status(403)
       .send('We only want "closed" PR events right now.');
  }
}

module.exports = pullRequestRouteHandler;

Resolve promise in PR handler


import _ from '../wrap/lodash'
import isMatcher from '../matchers/is-matcher'
import * as stringifyObject from 'stringify-object-es5'

export default (anything) => {
  if (_.isString(anything)) {
    return stringifyString(anything)
  } else if (isMatcher(anything)) {
    return anything.__name
  } else {
    return stringifyObject(anything, {
      indent: '  ',
      singleQuotes: false,
      inlineCharacterLimit: 65,
      transform (obj, prop, originalResult) {
        if (isMatcher(obj[prop])) {
          return obj[prop].__name
        } else {
          return originalResult
        }
      }
    })
  }
}

var stringifyString = (string) =>
  _.includes(string, '\n')
    ? `"""\n${string}\n"""`
    : `"${string.replace(new RegExp('"', 'g'), '\\"')}"`

import _ from '../wrap/lodash'
import isMatcher from '../matchers/is-matcher'
import * as stringifyObject from 'stringify-object-es5'

export default (anything) => {
  if (_.isString(anything)) {
    return stringifyString(anything)
  } else if (isMatcher(anything)) {
    return anything.__name
  } else if (anything && anything[Symbol("__is_proxy")]) {
    return anything.toString()
  } else {
    return stringifyObject(anything, {
      indent: '  ',
      singleQuotes: false,
      inlineCharacterLimit: 65,
      transform (obj, prop, originalResult) {
        if (isMatcher(obj[prop])) {
          return obj[prop].__name
        } else {
          return originalResult
        }
      }
    })
  }
}

var stringifyString = (string) =>
  _.includes(string, '\n')
    ? `"""\n${string}\n"""`
    : `"${string.replace(new RegExp('"', 'g'), '\\"')}"`

Use toString when printing proxy description


app.filter('dashcase', function () {

  return function (input) {

    input = input.replace(/\s+/g, '-')
      .toLowerCase()
      .replace('ä', 'ae')
      .replace('ö', 'oe')
      .replace('ü', 'ue')
      .replace('ß', 'ss')
      .replace(/[^a-z0-9-]/g, '');

    return input;
  };
});

app.filter('dashcase', function () {

  return function (input) {

    return input.toLowerCase()
      .replace(/\s+/g, '-')
      .replace(/ä/g, 'ae')
      .replace(/ö/g, 'oe')
      .replace(/ü/g, 'ue')
      .replace(/\u00df/g, 'ss')
      .replace(/[^a-z0-9-]/g, '');
  };
});

Fix bug with German umlauts in dashcase filter


import React, { Component } from 'react';
import Dialog from 'material-ui/lib/dialog';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';

// NOTE: For emit `onTouchTap` event.
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

export default class PromoteModal extends Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
  }

  handleOpen() {
    this.setState({ open: true });
  }

  handleClose() {
    this.props.onHidePromoteModal();
    this.setState({ open: this.props.open });
  }

  render() {
    const actions = [
      <FlatButton label="Cancel" primary={true} onTouchTap={this.handleClose.bind(this)} />,
      <FlatButton label="Submit" primary={true} onTouchTap={this.handleClose.bind(this)} />
    ];

    return (
      <div>
        <Dialog title="" actions={actions} modal={true} open={this.props.open} />
      </div>
    );
  }
}

import React, { Component } from 'react';
import Dialog from 'material-ui/lib/dialog';
import FlatButton from 'material-ui/lib/flat-button';
import RaisedButton from 'material-ui/lib/raised-button';

// NOTE: For emit `onTouchTap` event.
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

export default class PromoteModal extends Component {
  constructor(props) {
    super(props);
    this.state = { open: false };
  }

  handleClose() {
    this.props.onHidePromoteModal();
    this.setState({ open: this.props.open });
  }

  render() {
    const actions = [
      <FlatButton label="Cancel" primary={true} onTouchTap={this.handleClose.bind(this)} />,
      <FlatButton label="Submit" primary={true} onTouchTap={this.handleClose.bind(this)} />
    ];

    return (
      <div>
        <Dialog title="" actions={actions} modal={true} open={this.props.open} />
      </div>
    );
  }
}

Remove handleOpen function. because it is unnecessary.


import * as actionTypes from "../../src/actions/types";
import exampleReducer from "../../src/reducers/example-reducer";

describe("exampleReducer", () => {
  test("initial state", () => {
    expect(exampleReducer(undefined, {})).toEqual({example: ""});
  });

  test ("when action type is EXAMPLE_ACTION", () => {
    expect(exampleReducer(undefined, {type: actionTypes.EXAMPLE_ACTION, text: "Testing"}))
      .toEqual({example: "Testing"});
  });
});

import * as actionTypes from "../../src/actions/types";
import exampleReducer from "../../src/reducers/example-reducer";

describe("exampleReducer", () => {
  test("initial state", () => {
    expect(exampleReducer(undefined, {})).toEqual({example: ""});
  });

  test ("when action type is EXAMPLE_ACTION", () => {
    expect(exampleReducer(undefined, {type: actionTypes.EXAMPLE_ACTION, text: "Testing"}))
      .toEqual({example: "Testing"});

    expect(exampleReducer({example: "Prior text"}, {type: actionTypes.EXAMPLE_ACTION, text: "Testing"}))
      .toEqual({example: "Testing"});
  });
});

Test exampleReducer with prior state


define([
  'extensions/views/single_stat'
],
function (SingleStatView) {
  var NumberView = SingleStatView.extend({

    changeOnSelected: true,
    labelPrefix: '',

    formatValue: function(value) {
      return this.formatNumericLabel(value);
    },

    getValue: function () {
      return this.formatValue(this.collection.at(0).get(this.valueAttr));
    },

    getLabel: function () {
      var periodLabel = this.model.get('period') || "week";
      var events = this.collection.at(0).get("weeks"),
          unavailableEvents = events.total - events.available,
          label = [
            this.labelPrefix,
            'last',
            events.total,
            this.pluralise(periodLabel, events.total)
          ];

      if (unavailableEvents > 0) {
        label = label.concat([
          "(" + unavailableEvents,
          this.pluralise(periodLabel, unavailableEvents),
          "unavailable)"
        ]);
      }

      return label.join(' ');
    },

    getValueSelected: function (selection) {
      return this.formatValue(selection.selectedModel.get(this.selectionValueAttr));
    },

    getLabelSelected: function (selection) {
      return this.formatPeriod(selection.selectedModel, 'week');
    }
  });

  return NumberView;
});

define([
  'extensions/views/single_stat'
],
function (SingleStatView) {
  var NumberView = SingleStatView.extend({

    changeOnSelected: true,
    labelPrefix: '',

    formatValue: function(value) {
      return this.formatNumericLabel(value);
    },

    getValue: function () {
      return this.formatValue(this.collection.at(0).get(this.valueAttr));
    },

    getLabel: function () {
      var periodLabel = this.model.get('period') || "week";
      var events = this.collection.at(0).get("weeks"),
          unavailableEvents = events.total - events.available,
          label = [
            this.labelPrefix,
            'last',
            events.total,
            this.pluralise(periodLabel, events.total)
          ];

      if (unavailableEvents > 0) {
        label = label.concat([
          "(" + unavailableEvents,
          this.pluralise(periodLabel, unavailableEvents),
          "unavailable)"
        ]);
      }

      return label.join(' ');
    },

    getValueSelected: function (selection) {
      var val;
      if (selection.selectedGroupIndex !== null) {
        val = selection.selectedModel.get(this.selectionValueAttr);
      } else {
        val = null;
      }
      return this.formatValue(val);
    },

    getLabelSelected: function (selection) {
      var val;
      if (selection.selectedGroupIndex !== null) {
        return this.formatPeriod(selection.selectedModel, 'week');
      } else {
        return '';
      }

    }
  });

  return NumberView;
});

Add temporary fix for problem where selected model on hover does not exist


angular.module('pcApp.deliberation.directives.showDiscussion', [
    'pcApp.adhocracyEmbedder.services.adhocracy',
])

.directive('showDiscussion', ['Adhocracy', function (Adhocracy) {
    return {
        restrict: 'E',
        scope: {
            path: '@'
        },
        link: function(scope, element, attrs) {
            Adhocracy.then(function (adh) {
                element.append(adh.getIframe('comment-listing', {
                    path: scope.path
                }))
            });
        }
    };
}]);

angular.module('pcApp.deliberation.directives.showDiscussion', [
    'pcApp.adhocracyEmbedder.services.adhocracy',
])

.directive('showDiscussion', ['API_CONF', 'Adhocracy', function (API_CONF, Adhocracy) {
    return {
        restrict: 'E',
        scope: {
            key: '@'
        },
        link: function(scope, element, attrs) {
            Adhocracy.then(function (adh) {
                element.append(adh.getIframe('create-or-show-comment-listing', {
                    "pool-path": API_CONF.ADHOCRACY_BACKEND_URL + '/adhocracy/',
                    key: scope.key
                }))
            });
        }
    };
}]);

Adjust show-discussion directive to actual functionality


/*!
 * fullcalendar-rightclick v1.1
 * Docs & License: https://github.com/mherrmann/fullcalendar-rightclick
 * (c) 2015 Michael Herrmann
 */

(function($) {
	var fc = $.fullCalendar;
	var AgendaView = fc.views.agenda;
	var originalRender = AgendaView.prototype.render;
	AgendaView.prototype.render = function() {
		originalRender.call(this);
		this.registerDayRightclickListener();
		this.registerEventRightclickListener();
	};
	AgendaView.prototype.registerDayRightclickListener = function() {
		var that = this;
		this.el.on('contextmenu', '.fc-widget-content .fc-slats',
			function(ev) {
				that.coordMap.build();
				var cell = that.coordMap.getCell(ev.pageX, ev.pageY);
				if (cell)
					return that.trigger('dayRightclick', null, cell.start, ev);
			}
		);
	};
	AgendaView.prototype.registerEventRightclickListener = function() {
		var that = this;
		this.el.on('contextmenu', '.fc-event-container > *', function(ev) {
			var seg = $(this).data('fc-seg');
			return that.trigger('eventRightclick', this, seg.event, ev);
		});
	}
})(jQuery);

/*!
 * fullcalendar-rightclick v1.2
 * Docs & License: https://github.com/mherrmann/fullcalendar-rightclick
 * (c) 2015 Michael Herrmann
 */

(function($) {
	function monkeyPatchViewClass(View, dayCssClass) {
		var originalRender = View.prototype.render;
		View.prototype.render = function() {
			originalRender.call(this);
			this.registerDayRightclickListener();
			this.registerEventRightclickListener();
		};
		View.prototype.registerDayRightclickListener = function() {
			var that = this;
			this.el.on('contextmenu', '.fc-widget-content ' + dayCssClass,
				function(ev) {
					that.coordMap.build();
					var cell = that.coordMap.getCell(ev.pageX, ev.pageY);
					if (cell)
						return that.trigger(
							'dayRightclick', null, cell.start, ev
						);
				}
			);
		};
		View.prototype.registerEventRightclickListener = function() {
			var that = this;
			this.el.on('contextmenu', '.fc-event-container > *', function(ev) {
				var seg = $(this).data('fc-seg');
				return that.trigger('eventRightclick', this, seg.event, ev);
			});
		}
	}
	var fc = $.fullCalendar;
	monkeyPatchViewClass(fc.views.agenda, '.fc-slats');
	monkeyPatchViewClass(fc.views.basic, '.fc-content-skeleton');
})(jQuery);

Add support for FullCalendar's month view.


'use strict'

var context = {/* user id */};
//TODO: Replace with node-cache

/*Example:
{
    command: '/track',
    stage: 'askForTrack',
    parameters: [
        'Mike Oldfield'
    ]
}
*/

context.save = function (userId, command, stage, parameters) {
    context[userId] = {};
    context[userId].command = command;
    context[userId].stage = stage;
    if (!context[userId].parameters) {
        context[userId].parameters = [parameters];
    } else {
        context[userId].parameters.push(parameters);
    }
};

context.delete = function (userId) {
    delete context[userId];
};

module.exports = context;

'use strict'

var context = {/* user id */};
//TODO: Replace with node-cache

/*Example:
{
    command: '/track',
    stage: 'askForTrack',
    parameters: [
        'Mike Oldfield'
    ]
}
*/

context.save = function (userId, command, stage, parameters) {
    context[userId] = {};
    context[userId].command = command;
    context[userId].stage = stage;
    if (!context[userId].parameters) {
        context[userId].parameters = [parameters];
    } else {
        context[userId].parameters.push(parameters);
    }
};

context.pop = function (userId) {
    return context.parameters.pop();
};

context.delete = function (userId) {
    delete context[userId];
};

module.exports = context;

Add ability to pop parameters


(function() {
  'use strict';

  angular.module('pub.security.authentication', [])

    .factory('authentication', [
      '$q',
      '$http',
      'securityContext',
      function($q, $http, securityContext) {

        var authentication = {
          requestSecurityContext: function() {
            debugger;
            if (securityContext.authenticated) {
              return $q.when(securityContext);

            } else {
              var deferred = $q.defer();
              $http.get('/users/current', null).success(function(user) {
                deferred.resolve(securityContext.setAuthentication(user));
              })

              return deferred.promise;
            }
          },

          login: function(user, success, error) {
            $http.post('/login', user, null)
              .success(function(user) {
                success(user);
                securityContext.setAuthentication(user);
              })
              .error(error);
          },

          logout: function(success, error) {
            securityContext.reset();
            $http.get('/logout').success(success).error(error);
          }
        }

        return authentication;
      }
    ]);
}());

(function() {
  'use strict';

  angular.module('pub.security.authentication', [])

    .factory('authentication', [
      '$q',
      '$http',
      'securityContext',
      function($q, $http, securityContext) {

        var authentication = {
          requestSecurityContext: function() {
            if (securityContext.authenticated) {
              return $q.when(securityContext);

            } else {
              var deferred = $q.defer();
              $http.get('/users/current', null).success(function(user) {
                deferred.resolve(securityContext.setAuthentication(user));
              })

              return deferred.promise;
            }
          },

          login: function(user, success, error) {
            $http.post('/login', user, null)
              .success(function(user) {
                success(user);
                securityContext.setAuthentication(user);
              })
              .error(error);
          },

          logout: function(success, error) {
            securityContext.reset();
            $http.get('/logout').success(success).error(error);
          }
        }

        return authentication;
      }
    ]);
}());

Remove dubugger; statement from auth controller.


import {validate_request} from '../utils/errors'
import express from 'express'

function validate_request_body(request, response, next_handler) {
  request.checkBody({
    'screen_name': {
      notEmpty: {
        errorMessage: 'parameter is required',
      },
    },
  })

  validate_request(request, next_handler)
}

const all_groups_router = express.Router()
all_groups_router.route('/groups')
  .get((request, response) => {
    response.json({})
  })
  .post(validate_request_body, (request, response) => {
    response.json({
      group: request.body,
    })
  })

const one_group_router = express.Router()
one_group_router.param('group_id', (request, response, next_handler) => {
  request.checkParams('group_id', 'parameter is required').notEmpty()
  request
    .checkParams('group_id', 'parameter must be a MongoDB ObjectId')
    .isMongoId()

  validate_request(request, next_handler)
})
one_group_router.route('/groups/:group_id')
  .delete((request, response) => {
    response.json({
      group_id: request.params.group_id,
    })
  })

export const group_router = express.Router()
group_router.use(all_groups_router)
group_router.use(one_group_router)

import {check_authentication, validate_request} from '../utils/errors'
import express from 'express'

function validate_request_body(request, response, next_handler) {
  request.checkBody({
    'screen_name': {
      notEmpty: {
        errorMessage: 'parameter is required',
      },
    },
  })

  validate_request(request, next_handler)
}

const all_groups_router = express.Router()
all_groups_router.route('/groups')
  .get(check_authentication, (request, response) => {
    response.json({})
  })
  .post(check_authentication, validate_request_body, (request, response) => {
    response.json({
      group: request.body,
    })
  })

const one_group_router = express.Router()
one_group_router.param('group_id', (request, response, next_handler) => {
  request.checkParams('group_id', 'parameter is required').notEmpty()
  request
    .checkParams('group_id', 'parameter must be a MongoDB ObjectId')
    .isMongoId()

  validate_request(request, next_handler)
})
one_group_router.route('/groups/:group_id')
  .delete(check_authentication, (request, response) => {
    response.json({
      group_id: request.params.group_id,
    })
  })

export const group_router = express.Router()
group_router.use(all_groups_router)
group_router.use(one_group_router)

Check an authentication in the group router


/**
 * Pascal's triangle is defined as the rth column of the nth row is n! / ( r! x (n - r)!)
 *
 * @param {Integer} n
 * @return {Array} int array where each value represents a level in the triangle.
 */
function pascalsTriangle(n) {
  // Check if n is 0.
  if (!n) return [];

  // Start with the first level already made.
  var triangle = [[1]];

  // Add each level after the first.
  for (var i = 0; i < n - 1; i++) {
    // Each level starts with 1.
    var level = [1];

    for (var j = 1; j < triangle[i].length; j++) {
      level[j] = triangle[i][j] + triangle[i][j - 1];
    }

    // Each level ends with 1.
    level.push(1);
    triangle.push(level);
  }

  return triangle;
}

module.exports = pascalsTriangle;

/**
 * Pascal's triangle is defined as the rth column of the nth row is n! / ( r! x (n - r)!)
 *
 * @param {Integer} n
 * @return {Array} int array where each value represents a level in the triangle.
 */
function pascalsTriangle(n) {
  // Check if the triangle is empty.
  if (!n) return [];

  return pascalsTriangleRecursive(n, [[1]]);
}

function pascalsTriangleRecursive(n, triangle) { // jshint ignore:line
  if (n <= 1) return triangle;

  // Each level starts with 1;
  var level = [1];
  var above = triangle[triangle.length - 1];

  // A direct child level has exactly one more value.
  for (var i = 1; i < above.length; i ++) {
    level[i] = above[i] + above[i - 1];
  }

  // Each level ends with 1.
  level.push(1);
  triangle.push(level);

  return pascalsTriangleRecursive(n - 1, triangle);
}

function pascalsTriangleIterative(n) { // jshint ignore:line
  // Check if n is 0.
  if (!n) return [];

  // Start with the first level already made.
  var triangle = [[1]];

  // Add each level after the first.
  for (var i = 0; i < n - 1; i++) {
    // Each level starts with 1.
    var level = [1];

    for (var j = 1; j < triangle[i].length; j++) {
      level[j] = triangle[i][j] + triangle[i][j - 1];
    }

    // Each level ends with 1.
    level.push(1);
    triangle.push(level);
  }

  return triangle;
}

module.exports = pascalsTriangle;

Add recursive solution for pascals triangle


import * as actType from './action-types';

const initialState = {
  loadingApi: undefined,
  runtimeApi: undefined,
};

function loadApi(state = initialState, action) {
  switch (action.type) {
    case actType.START_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'started'});
    case actType.FINISH_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'finished', runtimeApi: action.payload});
    case actType.FAIL_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'failed'});
    default:
      return state;
  }
}

export default loadApi;

import * as actType from './action-types';

const initialState = {
  loadingApi: undefined,
  runtimeApi: undefined,
  error: undefined
};

function loadApi(state = initialState, action) {
  switch (action.type) {
    case actType.START_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'started'});
    case actType.FINISH_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'finished', runtimeApi: action.payload});
    case actType.FAIL_LOAD_RUNTIME:
      return Object.assign({}, state, {loadingApi: 'failed', error: action.payload});
    default:
      return state;
  }
}

export default loadApi;

Add error state and fail payload


'use strict'

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

/* global describe it expect */

describe('issues', () => {
  describe('#21 - undefined default value is rendering as a non string', () => {
    it('undefined default value is rendering as a non string', () => {
      const filecontent = `
        <script>
          export default {
            props: {
              value: {
                type: Boolean,
                default: undefined
              }
            }
          }
        </script>
      `

      const options = { filecontent }
      const expected = [
        '# Props',
        '',
        '| Name      | Type      | Description | Default     |',
        '| --------- | --------- | ----------- | ----------- |',
        '| `v-model` | `Boolean` |             | `undefined` |'
      ].join('\n')

      return vuedoc.md(options).then((doc) => expect(doc.trim()).toEqual(expected))
    })
  })
})

'use strict'

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

/* global describe it expect */

describe('issues', () => {
  describe('#21 - undefined default value is rendering as a non string', () => {
    it('undefined default value is rendering as a non string', () => {
      const filecontent = `
        <script>
          export default {
            props: {
              value: {
                type: Boolean,
                default: undefined
              }
            }
          }
        </script>
      `

      const options = { filecontent }
      const expected = [
        '# Props',
        '',
        '| Name      | Type      | Description | Default     |',
        '| --------- | --------- | ----------- | ----------- |',
        '| `v-model` | `Boolean` |             | `undefined` |'
      ].join('\n')

      return vuedoc.md(options).then((doc) => expect(doc.trim()).toEqual(expected))
    })
  })

  describe('#7 - Spread Operator not working in component methods', () => {
    it('should parse without errors', () => {
      const options = {
        filecontent: `
          <script>
            import { mapActions, mapMutations, mapGetters } from 'vuex';

            export default {
              methods: {
                ...mapActions(['storeAction']),
                ...mapMutations(['storeMutation']),
              },
              computed: {
                ...mapGetters(['storeGetter']),
              }
            }
          </script>
        `
      }

      const expected = [].join('\n')

      return vuedoc.md(options).then((doc) => expect(doc.trim()).toEqual(expected))
    })
  })
})

Add a test for Spread Operator


#!/usr/bin/env node

var exec = require('child_process').exec;

var dbconfig  = require(process.cwd() + '/config/database');
var envconfig = dbconfig[process.env.FP_NODE_ENV];

if (!envconfig) throw('invalid environment variable');

function parse (value) {
  if (typeof(value) == 'object') {
    return process.env[value.ENV];
  } else {
    return value;
  }
}

var user = parse(envconfig.user),
    host = parse(envconfig.host),
    port = parse(envconfig.port),
    pass = parse(envconfig.password),
    db   = parse(envconfig.database);

if (!db) throw('Database name must be specified in an environment variable.');

var query = 'psql -c "CREATE DATABASE ' + db + ';"';

if (user) query += ' -U ' + user;
if (host) query += ' -h ' + host;
if (port) query += ' -p ' + port;
if (pass) query += ' -w ' + pass;

exec(query, function (err, res) {
  if (err) throw(err);
  console.log(res);
  console.log(db + ' database created successfully!');
});

#!/usr/bin/env node

var exec = require('child_process').exec;

var dbconfig  = require(process.cwd() + '/config/database');
var envconfig = dbconfig[process.env.FP_NODE_ENV];

if (!envconfig) throw('invalid environment variable');

function parse (value) {
  if (typeof(value) == 'object') {
    return process.env[value.ENV];
  } else {
    return value;
  }
}

var user = parse(envconfig.user),
    host = parse(envconfig.host),
    port = parse(envconfig.port),
    pass = parse(envconfig.password),
    db   = parse(envconfig.database);

if (!db) throw('Database name must be specified in an environment variable.');

var query = 'psql -c "CREATE DATABASE ' + db + ';"';

if (user) query += ' -U ' + user;
if (host) query += ' -h ' + host;
if (port) query += ' -p ' + port;
if (pass) query += ' -w' + pass;

exec(query, function (err, res) {
  if (err) throw(err);
  console.log(res);
  console.log(db + ' database created successfully!');
});

Remove space between flag and password


/**
 * Error
 *
 * @constructor
 */
var ValidationError = function() {
  this.length = 0;
};

ValidationError.prototype.push = function(item) {
  this[this.length] = item;
  this.length += 1;
};

/**
 * GetProperties
 */
ValidationError.prototype.getProperties = function() {
  return pluck(this, 'property');
};

ValidationError.prototype.getMessages = function() {

};

/**
 * Error
 *
 * @constructor
 */
var ValidationError = function() {
  this.length = 0;
};

ValidationError.prototype.push = function(error) {

  this[this.length] = {

    property: error.property,
    propertyValue: error.propertyValue,
    attributeName: error.attributeName,
    attributeValue: error.attributeValue,
    message: error.message,

    // Deprecated
    validator: error.attributeName,
    validatorName: error.attributeName,
    validatoValue: error.attributeValue

  };

  this.length += 1;

};

/**
 * GetProperties
 */
ValidationError.prototype.getProperties = function() {
  return pluck(this, 'property');
};

/**
 * GetMessages
 */
ValidationError.prototype.getMessages = function() {
  return pluck(this, 'message');
};

Add a compatibility layer to the ‘Error’ object


var assert = require("assert");
var parseApk = require("..");

describe("APK V24", function () {
    var output = null;

    before(function (done) {
        parseApk(__dirname + "/samples/test_v24.apk", function (err, out) {
            if (err) {
                return done(err);
            }
            output = out;
            done();
        });
    });

    it("Parses correctly", function () {
        assert.notEqual(null, output);
    });

    it("Starts with a manifest tag", function () {
        assert.equal(output.manifest.length, 1);
    });

    it("Has a package name", function () {
        assert.equal(output.manifest[0]["@package"], "org.rubenv.testapk");
    });

    it("Has a package version", function () {
        assert.equal(output.manifest[0]["@platformBuildVersionCode"], "21");
    });

    it("Has an application tag", function () {
        var manifest = output.manifest[0];
        assert.equal(manifest.application.length, 1);
    });
});

var assert = require("assert");
var parseApk = require("..");

describe("APK V24", function () {
    var output = null;

    before(function (done) {
        parseApk(__dirname + "/samples/test_v24.apk", function (err, out) {
            if (err) {
                return done(err);
            }
            output = out;
            done();
        });
    });

    it("Parses correctly", function () {
        assert.notEqual(null, output);
    });

    it("Starts with a manifest tag", function () {
        assert.equal(output.manifest.length, 1);
    });

    it("Has a package name", function () {
        assert.equal(output.manifest[0]["@package"], "com.idotools.bookstore");
    });

    it("Has a package version", function () {
        assert.equal(output.manifest[0]["@platformBuildVersionCode"], "24");
    });

    it("Has an application tag", function () {
        var manifest = output.manifest[0];
        assert.equal(manifest.application.length, 1);
    });
});

Change test_v24 to the correct item.


/*global describe, it */
/*exported should */
/*jshint -W030 */

var should = require('should'),
    supertest = require('supertest'),
    app = require('../app');

describe('notSupported', function() {

  it('should not support anything', function(done) {
    supertest(app).
      get('/api/v1/').
      expect(500, function(err, res) {
        should.equal(res.body.request_type, 'atomic');
        should.equal(res.body.response_code, 500);
        res.body.resource_status.should.be.length(1);
        should.equal(res.body.resource_status[0].resource, '*');
        should.equal(res.body.resource_status[0].response_code, '500');
        res.body.resource_status[0].errors.should.be.length(1);
        should.equal(
          res.body.resource_status[0].errors[0].code,
          'NOT_SUPPORTED');
        done();
      });
  });

});

/*global describe, it */
/*exported should */
/*jshint -W030 */

var should = require('should'),
    supertest = require('supertest'),
    app = require('../app');

describe('notSupported', function() {

  it('should not support any resources', function(done) {
    supertest(app).
      get('/api/v1/questions').
      expect(500, function(err, res) {
        should.equal(res.body.request_type, 'atomic');
        should.equal(res.body.response_code, 500);
        res.body.resource_status.should.be.length(1);
        should.equal(res.body.resource_status[0].resource, '*');
        should.equal(res.body.resource_status[0].response_code, '500');
        res.body.resource_status[0].errors.should.be.length(1);
        should.equal(
          res.body.resource_status[0].errors[0].code,
          'NOT_SUPPORTED');
        done();
      });
  });

  it('should 404 non-api requests', function(done) {
    supertest(app).
      get('/allTheThings').
      expect(404, done);
  });

});

Test AEP and non-API 404s


"use strict";

angular.module("hikeio").
	directive("giveFocus", ["$timeout", function($timeout) {
	return {
		link: function(scope, element, attributes) {
			scope.$watch(attributes.giveFocus, function(value) {
				if (value) {
					$timeout(function() {
						element.focus();
					});
				}
			});
		}
	};
}]);

"use strict";

angular.module("hikeio").
	directive("giveFocus", ["$timeout", function($timeout) {
	return {
		link: function(scope, element, attributes) {
			scope.$watch(attributes.giveFocus, function(value) {
				if (value) {
					$timeout(function() {
						element.focus();

						// Set focus to the end of the input
						// http://stackoverflow.com/questions/1056359/set-mouse-focus-and-move-cursor-to-end-of-input-using-jquery
						if (element.is("input")) {
							var val = element.val();
							element.val("");
							element.val(val);
						}
					});
				}
			});
		}
	};
}]);

Set focus to the end of the input when giving focus, matters on the preopulated add dialog.


import View from '../View';
import HeaderAnalysesView from './HeaderAnalysesView';
import HeaderUserView from './HeaderUserView';
import HeaderImageView from './HeaderImageView';
import router from '../../router';
import events from '../../events';

import headerTemplate from '../../templates/layout/header.pug';
import '../../stylesheets/layout/header.styl';

var HeaderView = View.extend({
    events: {
        'click .g-app-title': function () {
            router.navigate('', {trigger: true});
        }
    },

    initialize() {
        this.listenTo(events, 'h:imageOpened', this._setImageText);
        return View.prototype.initialize.apply(this, arguments);
    },

    render() {
        this.$el.html(headerTemplate());

        this.$('a[title]').tooltip({
            placement: 'bottom',
            delay: {show: 300}
        });

        new HeaderUserView({
            el: this.$('.h-current-user-wrapper'),
            parentView: this
        }).render();

        new HeaderImageView({
            el: this.$('.h-image-menu-wrapper'),
            parentView: this
        }).render();

        new HeaderAnalysesView({
            el: this.$('.h-analyses-wrapper'),
            parentView: this
        }).render();

        return this;
    },

    _setImageText(img) {
        console.log(img);
    }
});

export default HeaderView;

import View from '../View';
import HeaderAnalysesView from './HeaderAnalysesView';
import HeaderUserView from './HeaderUserView';
import HeaderImageView from './HeaderImageView';
import router from '../../router';

import headerTemplate from '../../templates/layout/header.pug';
import '../../stylesheets/layout/header.styl';

var HeaderView = View.extend({
    events: {
        'click .g-app-title': function () {
            router.navigate('', {trigger: true});
        }
    },

    initialize() {
        return View.prototype.initialize.apply(this, arguments);
    },

    render() {
        this.$el.html(headerTemplate());

        this.$('a[title]').tooltip({
            placement: 'bottom',
            delay: {show: 300}
        });

        new HeaderUserView({
            el: this.$('.h-current-user-wrapper'),
            parentView: this
        }).render();

        new HeaderImageView({
            el: this.$('.h-image-menu-wrapper'),
            parentView: this
        }).render();

        new HeaderAnalysesView({
            el: this.$('.h-analyses-wrapper'),
            parentView: this
        }).render();

        return this;
    }
});

export default HeaderView;

Remove _setImageText in image header


export const printStyles =
`<style>
	div {
 border-radius: 0px !important;
 box-shadow: none !important; }

	@media print {
	  @page { margin: 0; }
	  body { margin: 0 0; }
	  img {visibility: hidden; }
	}

</style>`;

export const printStyles =
`<style>
div {
	border-width: 0px ! important;
 	border-radius: 0px !important;
 	box-shadow: none !important;}

 img {
 	visibility: hidden; }
@media print {
	@page { margin: 0; }
	 body { margin: 0 0; }
}

</style>`;

Fix pdf image appearing and borders appering


(function() {
  // Find the parent window, which has its parent set to itself.
  var parentWindow = window;
  while (parentWindow.parent !== parentWindow) {
    parentWindow = parentWindow.parent;
  }

  function failFunc(msg) {
    parentWindow.alert('fail: ' + msg);
  }

  var onLaunchedListeners = [];
  chrome = {};
  chrome.app = {};
  chrome.app.runtime = {};
  chrome.app.runtime.onLaunched = {};
  chrome.app.runtime.onLaunched.addListener = function(func) {
    onLaunchedListeners.push(func);
  };
  chrome.app.runtime.onLaunched.fire = function() {
    for (var i = 0, f; f = onLaunchedListeners[i]; ++i) {
      f();
    }
  };
  chrome.app.window = {};
  chrome.app.window.create = function(filePath, opt_options, opt_callback) {
    console.log('fetching ' + filePath);
    var xhr = new XMLHttpRequest();
    xhr.open('GET', filePath, true);
    xhr.onload = function() {
      console.log('found ' + filePath);
      document.open();
      document.write(xhr.responseText);
      document.close();
    };
    xhr.onerror = failFunc('xhr');
    xhr.send();
  };
})();

(function() {
  // Find the parent window, which has its parent set to itself.
  var parentWindow = window;
  while (parentWindow.parent !== parentWindow) {
    parentWindow = parentWindow.parent;
  }

  var onLaunchedListeners = [];
  chrome = {};
  chrome.app = {};
  chrome.app.runtime = {};
  chrome.app.runtime.onLaunched = {};
  chrome.app.runtime.onLaunched.addListener = function(func) {
    onLaunchedListeners.push(func);
  };
  chrome.app.runtime.onLaunched.fire = function() {
    for (var i = 0, f; f = onLaunchedListeners[i]; ++i) {
      f();
    }
  };
  chrome.app.window = {};
  chrome.app.window.create = function(filePath, opt_options, opt_callback) {
    console.log('fetching ' + filePath);
    var xhr = new XMLHttpRequest();
    xhr.open('GET', filePath, true);
    xhr.onload = function() {
      console.log('found ' + filePath);
      document.open();
      document.write(xhr.responseText);
      document.close();
    };
    xhr.onerror = function() {
      alert('XHR failed');
    };
    xhr.send();
  };
})();

Fix XHR failed alerts firing incorrectly.


// TODO: load based on params
Ember.keys(requirejs._eak_seen).filter(function(key) {
  return (/\_test/).test(key);
}).forEach(function(moduleName) {
  require(moduleName, null, null, true);
});

// TODO: load based on params
Ember.keys(requirejs._eak_seen).filter(function(key) {
  return (/\-test/).test(key);
}).forEach(function(moduleName) {
  require(moduleName, null, null, true);
});

Fix test loader for dasherized file names.


import React from 'react';
import { c } from 'ttag';
import PropTypes from 'prop-types';
import { Alert, Button, PrimaryButton, Block } from 'react-components';

const AddressesSection = ({ onRedirect }) => {
    return (
        <>
            <Alert>{c('Info for domain modal')
                .t`Addresses must be connected to an user account. Click Add user to add a new user account with its own login and inbox that you can connect addresses to.`}</Alert>
            <Block>
                <PrimaryButton className="mr1" onClick={() => onRedirect('/settings/addresses')}>{c('Action')
                    .t`Add address`}</PrimaryButton>
                <Button onClick={() => onRedirect('/settings/members')}>{c('Action').t`Add user`}</Button>
            </Block>
        </>
    );
};

AddressesSection.propTypes = {
    onRedirect: PropTypes.func.isRequired
};

export default AddressesSection;

import React from 'react';
import { c } from 'ttag';
import PropTypes from 'prop-types';
import { Alert, PrimaryButton, Block } from 'react-components';

const AddressesSection = ({ onRedirect }) => {
    return (
        <>
            <Alert>{c('Info for domain modal')
                .t`If you have a subscription plan with multi-user support, you can add users to your domain by clicking on the button below.`}</Alert>
            <Block>
                <PrimaryButton onClick={() => onRedirect('/settings/members')}>{c('Action').t`Add user`}</PrimaryButton>
            </Block>
            <Alert>{c('Info for domain modal')
                .t`Already have all the users you need? Click on the button below to add addresses to your users. More addresses can be purchased by customizing your plan from the subscription section.`}</Alert>
            <Block>
                <PrimaryButton onClick={() => onRedirect('/settings/addresses')}>{c('Action')
                    .t`Add address`}</PrimaryButton>
            </Block>
        </>
    );
};

AddressesSection.propTypes = {
    onRedirect: PropTypes.func.isRequired
};

export default AddressesSection;

Update text for addresses section


QUnit.config.urlConfig.push({
  id: "jquery",
  label: "jQuery version",
  value: ["3.2.1", "3.2.0", "3.1.1", "3.0.0", "2.2.4", "2.1.4", "2.0.3", "1.12.4", "1.11.3"],
  tooltip: "What jQuery Core version to test against"
});

/* Hijacks normal form submit; lets it submit to an iframe to prevent
 * navigating away from the test suite
 */
$(document).on('submit', function(e) {
  if (!e.isDefaultPrevented()) {
    var form = $(e.target), action = form.attr('action'),
        name = 'form-frame' + jQuery.guid++,
        iframe = $('<iframe name="' + name + '" />');

    if (action && action.indexOf('iframe') < 0) form.attr('action', action + '?iframe=true')
    form.attr('target', name);
    $('#qunit-fixture').append(iframe);
    form.trigger('iframe:loading');
  }
});

QUnit.config.urlConfig.push({
  id: "jquery",
  label: "jQuery version",
  value: ["3.2.1", "3.2.1.slim", "3.1.1", "3.1.1.slim", "3.0.0", "3.0.0.slim", "2.2.4", "2.1.4", "2.0.3", "1.12.4", "1.11.3"],
  tooltip: "What jQuery Core version to test against"
});

/* Hijacks normal form submit; lets it submit to an iframe to prevent
 * navigating away from the test suite
 */
$(document).on('submit', function(e) {
  if (!e.isDefaultPrevented()) {
    var form = $(e.target), action = form.attr('action'),
        name = 'form-frame' + jQuery.guid++,
        iframe = $('<iframe name="' + name + '" />');

    if (action && action.indexOf('iframe') < 0) form.attr('action', action + '?iframe=true')
    form.attr('target', name);
    $('#qunit-fixture').append(iframe);
    form.trigger('iframe:loading');
  }
});

Test against jQuery slim 3.x


function Events(target){
  var events = {}, i, list, args, A = Array;
  target = target || this
    /**
     *  On: listen to events
     */
    target.on = function(type, func, ctx){
      events[type] || (events[type] = [])
      events[type].push({f:func, c:ctx})
    }
    /**
     *  Off: stop listening to event / specific callback
     */
    target.off = function(type, func){
      list = events[type] || []
      i = list.length = func ? list.length : 0
      while(i-->0) func == list[i].f && list.splice(i,1)
    }
    /**
     * Emit: send event, callbacks will be triggered
     */
    target.emit = function(){
      args = A.apply([], arguments)
      list = events[args.shift()] || []
      i = list.length
      for(j=0;j<i;j++) list[j].f.apply(list[j].c, args)
    };
}
var u, module, cjs = module != u;
(!cjs ? window : module)[(cjs ? 'exports' : 'Events')] = Events;

function Events(target){
  var events = {}, i, list, args, A = Array;
  target = target || this
    /**
     *  On: listen to events
     */
    target.on = function(type, func, ctx){
      events[type] || (events[type] = [])
      events[type].push({f:func, c:ctx})
    }
    /**
     *  Off: stop listening to event / specific callback
     */
    target.off = function(type, func){
      list = events[type] || []
      i = list.length = func ? list.length : 0
      while(i-->0) func == list[i].f && list.splice(i,1)
    }
    /**
     * Emit: send event, callbacks will be triggered
     */
    target.emit = function(){
      args = A.apply([], arguments)
      list = events[args.shift()] || []
      i = list.length
      for(j=0;j<i;j++) list[j].f.apply(list[j].c, args)
    };
}
var u, module, cjs = module != u;
(cjs ? module : window)[(cjs ? 'exports' : 'Events')] = Events;

Remove \!, switch ternary outs


var path = require('path');

module.exports = {
  'dev': {
    'webpack': require(path.join(process.cwd(), 'tasks/config/webpack.js')),
    'publicPath': '/public/',
    'keepalive': true,
    'port': 3000,
    'hot': true,
    'historyApiFallback': true
  }
};

var path = require('path');

module.exports = {
  'dev': {
    'webpack': require(path.join(process.cwd(), 'tasks/config/webpack.js')),
    'publicPath': '/public/',
    'keepalive': true,
    'port': 8080,
    'hot': true,
    'historyApiFallback': true
  }
};

Set default port to 8080


try {
  window;
} catch(e) {
  var utility = require('./../game/utility');
}

function Wall(start_x, start_y, end_x, end_y) {
  this.start_x = start_x;
  this.start_y = start_y;
  this.end_x = end_x;
  this.end_y = end_y
}

Wall.prototype.init = function(){
}

Wall.prototype.update = function() {
}

Wall.prototype.render = function(ctx, wall_next, coeff) {
	// Currently not used as this is treated serverside.
}

Wall.prototype.getState = function() {
  return {
    start_x: this.start_x,
    start_y: this.start_y,
    end_x: this.end_x,
    end_y: this.end_y,
  }
}

module.exports = Wall;

try {
  window;
} catch(e) {
  var utility = require('./../game/utility');
}

function Wall(start_x, start_y, end_x, end_y) {
  this.start_x = start_x;
  this.start_y = start_y;
  this.end_x = end_x;
  this.end_y = end_y
}

Wall.prototype.init = function(){
}

Wall.prototype.update = function() {
}

Wall.prototype.render = function(ctx, wall_next, coeff) {
	// Currently not used as this is treated serverside.
  ctx.translate(this.start_x * GU, this.start_y * GU);

  ctx.strokeStyle = 'black';
  ctx.beginPath();
  ctx.lineTo((this.end_x - this.start_x) * GU,
             (this.end_y - this.start_y) * GU);
  ctx.stroke();

}

Wall.prototype.getState = function() {
  return {
    start_x: this.start_x,
    start_y: this.start_y,
    end_x: this.end_x,
    end_y: this.end_y,
  }
}

module.exports = Wall;

Add render function to wall.js


import { Comments, Posts } from 'meteor/example-forum';

// Recent Comments query index\
Comments._ensureIndex({'postedAt': -1, '_id': -1});

// Top Posts query index
Posts._ensureIndex({'status': -1, 'draft': -1, 'isFuture': -1, 'sticky': -1, 'score': -1, '_id': -1});

import { Comments, Posts } from 'meteor/example-forum';
import { Votes } from "meteor/vulcan:voting";

// Recent Comments query index\
Comments._ensureIndex({'postedAt': -1, '_id': -1});

// Top Posts query index
Posts._ensureIndex({'status': -1, 'draft': -1, 'isFuture': -1, 'sticky': -1, 'score': -1, '_id': -1});

// Votes by document (comment) ID
Votes._ensureIndex({ "documentId": 1 });

Add a missing index (votes by document)


(function($){
	$.entwine('userswitcher', function($){

		$('form.userswitcher select').entwine({
			onchange : function(){
				this.parents('form:first').submit();
			}
		});

		$('form.userswitcher .Actions').entwine({
			onmatch : function(){
				this.hide();
			}
		});

		$('body').entwine({
			onmatch : function(){
				var base = $('base').prop('href'),
					isCMS = this.hasClass('cms') ? 1 : '';

				$.get(base + 'userswitcher/UserSwitcherFormHTML/', {userswitchercms: isCMS}).done(function(data){
					var body = $('body');

					if(body.hasClass('cms')){
						$('.cms-login-status').append(data);
					}else{
						$('body').append(data);
					}

				});

			}
		});

	});
})(jQuery);

(function($){
	$.entwine('userswitcher', function($){

		$('form.userswitcher select').entwine({
			onchange : function(){
				this.parents('form:first').submit();
				this._super();
			}
		});

		$('form.userswitcher .Actions').entwine({
			onmatch : function(){
				this.hide();
				this._super();
			}
		});

		$('body').entwine({
			onmatch : function(){
				var base = $('base').prop('href'),
					isCMS = this.hasClass('cms') ? 1 : '';

				$.get(base + 'userswitcher/UserSwitcherFormHTML/', {userswitchercms: isCMS}).done(function(data){
					var body = $('body');

					if(body.hasClass('cms')){
						$('.cms-login-status').append(data);
					}else{
						$('body').append(data);
					}

				});
				this._super();
			}
		});

	});
})(jQuery);

Add this._super calls to avoid weird JS breaking behaviour


var pg = require('pg')
  , Transaction = require('any-db').Transaction
  , pgNative = null

try { pgNative = pg.native } catch (__e) {}

exports.forceJS = false

exports.createConnection = function (opts, callback) {
	var backend = chooseBackend()
		, conn = new backend.Client(opts)

	conn.begin = Transaction.createBeginMethod(exports.createQuery)

	if (callback) {
		conn.connect(function (err) {
			if (err) callback(err)
			else callback(null, conn)
		})
	} else {
		conn.connect()
	}

	return conn
}

// Create a Query object that conforms to the Any-DB interface
exports.createQuery = function (stmt, params, callback) {
	var backend = chooseBackend()
	return new backend.Query(stmt, params, callback)
}

function chooseBackend () {
  return (exports.forceJS || !pgNative) ? pg : pgNative
}

var pg = require('pg')
  , Transaction = require('any-db').Transaction
  , pgNative = null

try { pgNative = pg.native } catch (__e) {}

exports.forceJS = false

exports.createConnection = function (opts, callback) {
	var backend = chooseBackend()
		, conn = new backend.Client(opts)

	conn.begin = begin

	if (callback) {
		conn.connect(function (err) {
			if (err) callback(err)
			else callback(null, conn)
		})
	} else {
		conn.connect()
	}

	return conn
}

// Create a Query object that conforms to the Any-DB interface
exports.createQuery = function (stmt, params, callback) {
	var backend = chooseBackend()
	return new backend.Query(stmt, params, callback)
}

function chooseBackend () {
  return (exports.forceJS || !pgNative) ? pg : pgNative
}

var Transaction = require('any-db').Transaction

var begin = Transaction.createBeginMethod(exports.createQuery)

Use a single shared 'begin' function in postgres adapter


describe('Syrup Instantiation', function() {
    it('should instantiate without throwing an error', function() {
        require('../index.js');
    });
});

describe('Syrup Instantiation', function() {
    it('should instantiate without throwing an error', function() {
        require('../index.js');
    });
    it('should instantiate with a faker object as a property', function() {
        let assert = require('assert');
        assert(typeof require('../index.js').faker == 'object');
    });
});

Check for instantiation of faker on the Syrup class


import React, { Component } from 'react'
import { string, oneOfType, arrayOf, node } from 'prop-types'
import { Helmet } from 'react-helmet'

import pick from '../utils/pick'
import commonPropTypes from './commonPropTypes'

class Sidebar extends Component {
  static propTypes = {
    ...commonPropTypes,
    id: string.isRequired,
    side: string,
    children: oneOfType([
      arrayOf(node),
      node
    ])
  }

  static defaultProps = {
    side: '',
    children: []
  }

  get properties() {
    return pick(this.props, ...[
      ...Object.keys(commonPropTypes),
      'id',
      'side'
    ])
  }

  render() {
    const { children } = this.props
    return [
      <Helmet key="helmet">
        <script async="" custom-element="amp-sidebar" src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js" />
      </Helmet>,
      <amp-sidebar {...{ ...this.properties }} key="sidebar">
        {children}
      </amp-sidebar>
    ]
  }
}

export default Sidebar

import React, { Component } from 'react'
import { string, oneOfType, arrayOf, node } from 'prop-types'
import { Helmet } from 'react-helmet'

import pick from '../utils/pick'
import commonPropTypes from './commonPropTypes'

class Sidebar extends Component {
  static propTypes = {
    ...commonPropTypes,
    id: string.isRequired,
    side: string,
    children: oneOfType([
      arrayOf(node),
      node
    ])
  }

  static defaultProps = {
    side: null,
    children: []
  }

  get properties() {
    return pick(this.props, ...[
      ...Object.keys(commonPropTypes),
      'id',
      'side'
    ])
  }

  render() {
    const { children } = this.props
    return [
      <Helmet key="helmet">
        <script async="" custom-element="amp-sidebar" src="https://cdn.ampproject.org/v0/amp-sidebar-0.1.js" />
      </Helmet>,
      <amp-sidebar {...{ ...this.properties }} key="sidebar">
        {children}
      </amp-sidebar>
    ]
  }
}

export default Sidebar

Use null as default prop so it's not rendered


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

import App from './App'
import Home from './Home'
import NewGameContainer from './containers/NewGameContainer'
import Games from './Games'

export default (
  <Router history={hashHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Home} />
      <Route path='/game/new' component={NewGameContainer} />
      <Route path='/game/:id' component={Home} />
      <Route path='/game' component={Games} />
    </Route>
  </Router>
)

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

import App from './App'
import Home from './Home'
import NewGameContainer from './containers/NewGameContainer'
import GamesContainer from './containers/GamesContainer'

export default (
  <Router history={hashHistory}>
    <Route path='/' component={App}>
      <IndexRoute component={Home} />
      <Route path='/game/new' component={NewGameContainer} />
      <Route path='/game/:id' component={Home} />
      <Route path='/game' component={GamesContainer} />
    </Route>
  </Router>
)

Correct Games route component to GamesContainer


$(function() {
    var $explorer = $('#explorer');

    $('.nav-main .submenu-trigger').on('click', function() {
        if ($(this).closest('li').find('.nav-submenu').length) {

            // Close other active submenus first, if any
            if ($('.nav-wrapper.submenu-active').length && !$(this).closest('li').hasClass('submenu-active')) {
                $('.nav-main .submenu-active, .nav-wrapper').removeClass('submenu-active');
            }

            $(this).closest('li').toggleClass('submenu-active');
            $('.nav-wrapper').toggleClass('submenu-active');
            return false;
        }
    });

    $(document).on('keydown click', function(e) {
        if ($('.nav-wrapper.submenu-active').length && (e.keyCode == 27 || !e.keyCode)) {
            $('.nav-main .submenu-active, .nav-wrapper').removeClass('submenu-active');
        }
    });
});

$(function() {
    $('.nav-main .submenu-trigger').on('click', function() {
        if ($(this).closest('li').find('.nav-submenu').length) {

            // Close other active submenus first, if any
            if ($('.nav-wrapper.submenu-active').length && !$(this).closest('li').hasClass('submenu-active')) {
                $('.nav-main .submenu-active, .nav-wrapper').removeClass('submenu-active');
            }

            $(this).closest('li').toggleClass('submenu-active');
            $('.nav-wrapper').toggleClass('submenu-active');
            return false;
        }
    });

    $(document).on('keydown click', function(e) {
        if ($('.nav-wrapper.submenu-active').length && (e.keyCode == 27 || !e.keyCode)) {
            $('.nav-main .submenu-active, .nav-wrapper').removeClass('submenu-active');
        }
    });
});

Remove useless JS referencing explorer


import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import invariant from 'redux-immutable-state-invariant';
import devTools from 'remote-redux-devtools';
import reducer from '../reducers';

export default function configureStore(initialState) {

  const store = createStore(reducer, initialState, compose(
    applyMiddleware(invariant(), thunk),
    devTools({ realtime: true })
  ));

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers').default;
      store.replaceReducer(nextReducer);
    });
  }

  return store;
}

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import invariant from 'redux-immutable-state-invariant';
import { composeWithDevTools } from 'remote-redux-devtools';
import reducer from '../reducers';

export default function configureStore(initialState) {

  const store = createStore(reducer, initialState, composeWithDevTools(
    applyMiddleware(invariant(), thunk),
  )({ realtime: true }));

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextReducer = require('../reducers').default;
      store.replaceReducer(nextReducer);
    });
  }

  return store;
}

Update counter example to use `composeWithDevTools`


var Q = {};

/**
 * @constructor
 */
function QDeferred () {};

QDeferred.prototype.reject = function (args) {};

QDeferred.prototype.resolve = function (args) {};

/**
 * @type {string}
 */
QDeferred.prototype.state;

/**
 * @type {string}
 */
QDeferred.prototype.reason;

/**
 * @returns {QDeferred}
 */
Q.defer = function () {};

/**
 * @constructor
 */
function QPromise () {};

QPromise.prototype.then = function (args) {};

QPromise.prototype.catch = function (args) {};

/**
 * @returns {QPromise}
 */
Q.promise = function() {};

/**
 * @returns {QPromise}
 * @param {Array<QPromise>} promises
 */
Q.allSettled = function (promises) {};

/**
 * @returns {QPromise}
 * @param {Array<QPromise>} promises
 */
Q.all = function (promises) {};

/**
 * @returns {QPromise}
 * @param {function(...?):?} fn
 * @param {...*} args
 */
Q.nfcall = function (fn, args) {};

var Q = {};

/**
 * @constructor
 */
function QDeferred () {};

/**
 * @param {...*} args
 */
QDeferred.prototype.reject = function (args) {};

/**
 * @param {...*} args
 */
QDeferred.prototype.resolve = function (args) {};

/**
 * @type {string}
 */
QDeferred.prototype.state;

/**
 * @type {string}
 */
QDeferred.prototype.reason;

/**
 * @returns {QDeferred}
 */
Q.defer = function () {};

/**
 * @constructor
 */
function QPromise () {};

QPromise.prototype.then = function (args) {};

QPromise.prototype.catch = function (args) {};

/**
 * @returns {QPromise}
 */
Q.promise = function() {};

/**
 * @returns {QPromise}
 * @param {Array<QPromise>} promises
 */
Q.allSettled = function (promises) {};

/**
 * @returns {QPromise}
 * @param {Array<QPromise>} promises
 */
Q.all = function (promises) {};

/**
 * @returns {QPromise}
 * @param {function(...?):?} fn
 * @param {...*} args
 */
Q.nfcall = function (fn, args) {};

Fix externs definitions for Q


import BackgroundImage from 'ember-cli-image/components/background-image';
import ImageContainer from 'ember-cli-image/components/image-container';
import XImg from 'ember-cli-image/components/x-img';

import ImgixMixin from 'ember-cli-image-imgix/mixins/imgix-mixin';
import ImgixStaticMixin from 'ember-cli-image-imgix/mixins/imgix-static-mixin';

export function initialize() {
  BackgroundImage.reopen( ImgixMixin );
  BackgroundImage.reopenClass( ImgixStaticMixin );

  ImageContainer.reopen( ImgixMixin );
  ImageContainer.reopenClass( ImgixStaticMixin );

  XImg.reopen( ImgixMixin );
  XImg.reopenClass( ImgixStaticMixin );
}

export default {
  name: 'image-imgix',
  initialize: initialize
};

import BackgroundImageComponent from 'ember-cli-image/components/background-image-component';
import ImageContainerComponent from 'ember-cli-image/components/image-container-component';
import ImgComponent from 'ember-cli-image/components/img-component';

import ImgixMixin from 'ember-cli-image-imgix/mixins/imgix-mixin';
import ImgixStaticMixin from 'ember-cli-image-imgix/mixins/imgix-static-mixin';

export function initialize() {
  BackgroundImageComponent.reopen( ImgixMixin );
  BackgroundImageComponent.reopenClass( ImgixStaticMixin );

  ImageContainerComponent.reopen( ImgixMixin );
  ImageContainerComponent.reopenClass( ImgixStaticMixin );

  ImgComponent.reopen( ImgixMixin );
  ImgComponent.reopenClass( ImgixStaticMixin );
}

export default {
  name: 'image-imgix',
  initialize: initialize
};

Use the updated file names for image components in import statements


'use strict';

var Backbone = require('backbone');
var BusinessModel = Backbone.Model.extend({
	parse: function(data) {
    this.name = data.name;
    this.address = data.location.display_address.join(' ');
    this.rating = data.rating;
    this.specificCategory = data.categories[0][0];
	}
});
module.exports = BusinessModel;

'use strict';

var Backbone = require('backbone');
var BusinessModel = Backbone.Model.extend({
	parse: function(data) {
    console.log(data.name);
    this.name = data.name;
    this.address = data.location.display_address.join(' ');
    this.rating = data.rating;
    // this.specificCategory = data.categories[0][0];
	}
});
module.exports = BusinessModel;

Bring back console.log on new data, and comment out troublesome line


let express = require('express'),
	bodyParser = require('body-parser'),
	morgan = require('morgan'),
	mustacheExpress = require('mustache-express'),

	path = require('path'),

	db = require('./lib/db');

// load configuration
let config = {
	"mongo": {
		"host": "192.168.0.128",
		"port": 27017,
		"db": "g2x"
	}
}

// create app
var app = express();

// app configuration
app.set('port', (process.env.PORT || 8081));
app.set('db', db);

// configure template engine
app.engine('mustache', mustacheExpress());
app.set('view engine', 'mustache');
app.set('views', path.join(__dirname, 'views'));

// configure middleware
app.use(morgan('dev'));
app.use(express.static('public'));

// configure routes
require('./routes/static')(app);

// start server
var server = app.listen(app.get('port'), function() {
	var port = server.address().port;

	console.log("Server listening on port %s", port);

	db(config.mongo, (err, db) => {
		if (err) {
			console.error(err);
			process.exit(1);
		}

		console.log("Connected to mongo server:", config.mongo);
	});
});

let express = require('express'),
	bodyParser = require('body-parser'),
	morgan = require('morgan'),
	mustacheExpress = require('mustache-express'),

	path = require('path'),

	db = require('./lib/db');

// load configuration
let config = {
	"mongo": {
		"host": "192.168.0.128",
		"port": 27017,
		"db": "g2x"
	}
}

// create app
var app = express();

// app configuration
app.set('port', (process.env.PORT || 8081));

// configure template engine
app.engine('mustache', mustacheExpress());
app.set('view engine', 'mustache');
app.set('views', path.join(__dirname, 'views'));

// configure middleware
app.use(morgan('dev'));
app.use(express.static('public'));

// configure routes
require('./routes/static')(app);
require('./routes/imu')(app);

// start server
var server = app.listen(app.get('port'), function() {
	var port = server.address().port;

	console.log("Server listening on port %s", port);

	db(config.mongo, (err, db) => {
		if (err) {
			console.error(err);
			process.exit(1);
		}

		app.set('db', db);
		console.log("Connected to mongo server:", config.mongo);
	});
});

Add imu routes and store db reference on app


import TreeView from './TreeView';
import TreeDialog from './TreeDialog';

export {
    TreeView,
    TreeDialog
};

import ConfigView from './ConfigView';
import FileDialog from './FileDialog';
import FolderDialog from './FolderDialog';
import ItemDialog from './ItemDialog';
import TreeDialog from './TreeDialog';
import TreeView from './TreeView';

export {
    ConfigView,
    FileDialog,
    FolderDialog,
    ItemDialog,
    TreeDialog,
    TreeView
};

Add all views to the plugin namespace