/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
    // Task configuration.
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        files: {
            'dist/ng-mobile-menu.min.js' : ['src/ng-mobile-menu.js']
        }
      }
    },
    less: {
      dist: {
          options: {
              compress: true
          },
          files: {
              "dist/ng-mobile-menu.min.css" : "src/ng-mobile-menu.less"
          }
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-less');

  // Default task.
  grunt.registerTask('default', ['uglify', 'less']);

};

/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
      '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
      '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
      '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
      ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
    // Task configuration.
    uglify: {
      options: {
        banner: '<%= banner %>'
      },
      dist: {
        files: {
            'dist/ng-mobile-menu.min.js' : ['src/ng-mobile-menu.js']
        }
      }
    },
    less: {
      dist: {
          options: {
              compress: true,
              banner: '<%= banner %>'
          },
          files: {
              "dist/ng-mobile-menu.min.css" : "src/ng-mobile-menu.less"
          }
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-less');

  // Default task.
  grunt.registerTask('default', ['uglify', 'less']);

};

Add banner to CSS files


'use strict';

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Configure tasks
  grunt.initConfig({

    // Project settings
    project: {
      app: 'app'
    },

    // Watch files and execute tasks when they change
    watch: {
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= project.app %>/*.html'
        ]
      }
    },

    // Grunt servers
    connect: {
      options: {
        port: 9000,
        hostname: 'localhost',
        livereload: true
      },
      livereload: {
        options: {
          open: true,
          base: '<%= project.app %>'
        }
      }
    },

    wiredep: {
      app: {
        src: ['<%= project.app %>/index.html']
      }
    }
  });

  grunt.registerTask('serve', ['wiredep', 'connect:livereload', 'watch']);
};

'use strict';

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Configure tasks
  grunt.initConfig({

    // Project settings
    project: {
      app: 'app'
    },

    // Watch files and execute tasks when they change
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= project.app %>/*.html'
        ]
      }
    },

    // Grunt servers
    connect: {
      options: {
        port: 9000,
        hostname: 'localhost',
        livereload: true
      },
      livereload: {
        options: {
          open: true,
          base: '<%= project.app %>'
        }
      }
    },

    wiredep: {
      app: {
        src: ['<%= project.app %>/index.html']
      }
    }
  });

  grunt.registerTask('serve', ['wiredep', 'connect:livereload', 'watch']);
};

Watch bower.json and run wiredep


import BaseResolver from './BaseResolver';
import { STRING } from '../parsers/Types';

/**
 * @classdesc Options resolver for command parameter definitions.
 * @extends BaseResolver
 */
export default class ParameterResolver extends BaseResolver {
  /**
   * Constructor.
   */
  constructor() {
    super();

    this.resolver.setRequired('name')
      .setDefaults({
        description: null,
        optional: false,
        type: STRING,
        repeatable: false,
        literal: false,
        defaultValue: options => (options.repeatable ? [] : null),
      })
      .setAllowedTypes('name', 'string')
      .setAllowedTypes('optional', 'boolean')
      .setAllowedTypes('type', 'string')
      .setAllowedTypes('repeatable', 'boolean')
      .setAllowedTypes('literal', 'boolean');
  }
}

import BaseResolver from './BaseResolver';
import { STRING } from '../parsers/Types';

/**
 * @classdesc Options resolver for command parameter definitions.
 * @extends BaseResolver
 */
export default class ParameterResolver extends BaseResolver {
  /**
   * Constructor.
   */
  constructor() {
    super();

    this.resolver.setRequired('name')
      .setDefaults({
        description: null,
        optional: false,
        type: STRING,
        repeatable: false,
        literal: false,
        defaultValue: options => (options.repeatable ? [] : null),
      })
      .setAllowedTypes('name', 'string')
      .setAllowedTypes('description', ['string', 'null'])
      .setAllowedTypes('optional', 'boolean')
      .setAllowedTypes('type', 'string')
      .setAllowedTypes('repeatable', 'boolean')
      .setAllowedTypes('literal', 'boolean');
  }
}

Fix resolver failing for default param descriptions.


module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        banner: '/*! <%= pkg.name %> <%= pkg.version %> | Copyright <%= grunt.template.today("yyyy") %> <%= pkg.author.name %> | <%= pkg.license %> License */\n',

        concat: {
            options: {
                stripBanners: { block: true },
                banner: '<%= banner %>'
            },
            dist: {
                src: [ 'correctingInterval.js' ],
                dest: 'correctingInterval.js'
            }
        },

        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            dist: {
                files: {
                    'correctingInterval.min.js': [ 'correctingInterval.js' ]
                }
            }
        },

        jshint: {
            files: [
                'correctingInterval.js'
            ]
        },

        mocha: {
            index: ['test/index.html'],
            options: {
                run: true
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha');

    grunt.registerTask('test', [ 'jshint', 'mocha' ]);
    grunt.registerTask('compile', [ 'test', 'concat', 'uglify' ]);
    grunt.registerTask('default', [ 'compile' ]);
};

Apply consistent tabbing to gruntfile


module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-browserify');

    grunt.registerTask('default', ['browserify']);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        browserify: {
            main: {
                src: 'lib/vjs-hls.js',
                dest: 'debug/vjs-hls.js',
                options:  {
                   transform: ['babelify'],
                   browserifyOptions: {
                       debug: true
                   },
                   watch: true,
                   keepAlive: true
               }
            }
        }
    });
}

module.exports = function(grunt) {
    require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

    grunt.registerTask('default', ['browserify']);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        browserify: {
            main: {
                src: 'lib/vjs-hls.js',
                dest: 'debug/vjs-hls.js',
                options:  {
                   transform: ['babelify'],
                   browserifyOptions: {
                       debug: true
                   },
                   watch: true,
                   keepAlive: true
               }
            }
        }
    });
}

Load grunt-* dependencies with matchdep


import FilterModule from "../FilterModule";
import { dependencies as Inject, singleton as Singleton } from "needlepoint";
import Promise from "bluebird";
import Threads from "../../util/Threads";

@Singleton
@Inject(Threads)
export default class ThreadFilter extends FilterModule {
    /**
     * @param {Threads} threads
     */
    constructor(threads) {
        super();

        this.threadsToListen = threads.getThreadIds();
    }

    filter(msg) {
        const threadId = parseInt(msg.threadID);
        const shouldListen = this.threadsToListen.includes(threadId);

        if (shouldListen) {
            return Promise.resolve(msg);
        } else {
            return Promise.reject("Received message from thread (" + threadId + ") we're not listening to");
        }
    }
}

import FilterModule from "../FilterModule";
import { dependencies as Inject, singleton as Singleton } from "needlepoint";
import Promise from "bluebird";
import Threads from "../../util/Threads";

@Singleton
@Inject(Threads)
export default class ThreadFilter extends FilterModule {
    /**
     * @param {Threads} threads
     */
    constructor(threads) {
        super();

        this.threadsToListen = threads.getThreadIds();
    }

    filter(msg) {
        const threadId = parseInt(msg.threadID);
        const shouldListen = this.threadsToListen.indexOf(threadId) !== -1;

        if (shouldListen) {
            return Promise.resolve(msg);
        } else {
            return Promise.reject("Received message from thread (" + threadId + ") we're not listening to");
        }
    }
}

Fix use of Array.includes not supported in current node version


Use same maxRetries as rimraf did


'use strict';

module.exports =

/*@ngInject*/
function ($httpProvider, $stateProvider) {
  $httpProvider.interceptors.push(require('./oauth_interceptor.js'));

  $stateProvider.state('access_token', {
    url: '/access_token={accessToken}&token_type={tokenType}&expires_in={expiresIn}',
    template: '',
    controller: function ($stateParams, AccessToken, $location, $state, Storage) {
      var hashStr = [
        'access_token=' + $stateParams.accessToken,
        'token_type=' + $stateParams.tokenType,
        'expires_in=' + $stateParams.expiresIn
      ].join('&');
      AccessToken.setTokenFromString(hashStr);
      var postAuthenticationRedirect = Storage.delete('postAuthenticationRedirect');
      $state.go(postAuthenticationRedirect.stateName, postAuthenticationRedirect.stateParams);
    }
  });
};

'use strict';

module.exports =

/*@ngInject*/
function ($httpProvider, $stateProvider) {
  $httpProvider.interceptors.push(require('./oauth_interceptor.js'));

  $stateProvider.state('access_token', {
    url: '/access_token={accessToken}&token_type={tokenType}&expires_in={expiresIn}',
    template: '',
    controller: function ($stateParams, AccessToken, $location, $state, Storage) {
      var hashStr = [
        'access_token=' + $stateParams.accessToken,
        'token_type=' + $stateParams.tokenType,
        'expires_in=' + $stateParams.expiresIn
      ].join('&');
      AccessToken.setTokenFromString(hashStr);
      var postAuthenticationRedirect = Storage.delete('postAuthenticationRedirect');
      if (postAuthenticationRedirect === undefined) {
        throw new Error('No Post Authentication Redirect state or params found.');
      }
      $state.go(postAuthenticationRedirect.stateName, postAuthenticationRedirect.stateParams);
    }
  });
};

Throw error is there are now state params to redirect to upon authentication


var log = require('./log');
var TunerTwitter = require('./tuner_twitter');

var tt = TunerTwitter.create({twitterName: 'L2G', keywords: 'test'});
//var tt = TunerTwitter.create({twitterID: 14641869});
log.debug('created new TunerTwitter');
tt.on('ready', function () {
    log.debug('TwitterTuner is ready');
    tt.tuneIn();
});
tt.on('tunedIn', function () {
    log.debug('Twitter tuner is tuned in and listening for messages');
});
tt.on('message', function (message) {
    log.debug('Message from Twitter: ' + message);
});
tt.on('error', function (message) {
    log.debug('Twitter tuner raised an error: ' + message);
});
tt.on('lost', function (message) {
    log.debug('Twitter tuner lost its signal: ' + message);
});
tt.setup();

var log = require('./log');
var TunerTwitter = require('./tuner_twitter');

var tt = TunerTwitter.create({twitterName: 'L2G', keywords: 'test'});
//var tt = TunerTwitter.create({twitterID: 14641869});
log.debug('created new TunerTwitter');
tt.on('ready', function () {
    log.debug('TwitterTuner is ready');
    tt.tuneIn();
});
tt.on('tunedIn', function () {
    log.info('Twitter tuner is tuned in and listening for messages');
});
tt.on('message', function (message) {
    log.info('Message from Twitter: ' + message);
});
tt.on('error', function (message) {
    log.debug('Twitter tuner raised an error: ' + message);
});
tt.on('lost', function (message) {
    log.debug('Twitter tuner lost its signal: ' + message);
});
tt.setup();

Change some "debug" level log messages to "info"


/**
 * AdminLogonController: Creates a endpoint where a user can log
 * into the system. It renders the login template only if user is
 * not already logged in.
 */
AdminLogonController = RouteController.extend({
	waitOn: function () {
		return Meteor.user();
	},

	onBeforeAction: function(pause) {
    // Redirects user if allready logged in
		if (Meteor.user()) {
			if (!Meteor.loggingIn()) {
				this.redirect(Router.path('Reports', {page:0}));
			}
		}
	},

	action: function () {
    // if user is not logged in, render the login template
		if (!Meteor.user() && !Meteor.loggingIn()) {
			this.render();
		}
	}
});

/**
 * AdminLogonController: Creates a endpoint where a user can log
 * into the system. It renders the login template only if user is
 * not already logged in.
 */
AdminLogonController = RouteController.extend({
	onBeforeAction: function(pause) {
    // Redirects user if allready logged in
		if (Meteor.user()) {
			if (!Meteor.loggingIn()) {
				this.redirect(Router.path('Reports', {page:0}));
			}
		}
	},

	action: function () {
    // if user is not logged in, render the login template
		if (!Meteor.user() && !Meteor.loggingIn()) {
			this.render();
		}
	}
});

Fix a bug where the user was not redirected because of wrong use of waitOn


#!/usr/bin/env node
/*
Copyright (C) 2010, Oleg Efimov <efimovov@gmail.com>

See license text in LICENSE file
*/

var
  bindings_list = ['Sannis-node-mysql-libmysqlclient', 'felixge-node-mysql', /*'stevebest-node-mysql',*/ 'PHP-MySQL'],
  sys = require('sys'),
  default_factor = 1,
  factor = default_factor,
  cfg;

if (process.argv[2] !== undefined) {
  factor = Math.abs(process.argv[2]);

  if (isNaN(factor)) {
    factor = default_factor;
  }
}

cfg = require("./src/config").getConfig(factor);

function runNextBenchmark() {
  if (bindings_list.length > 0) {
    var binding_name = bindings_list.shift();
    sys.puts("\033[1mBenchmarking " + binding_name + ":\033[22m");

    var benchmark = require("./src/" + binding_name);
    benchmark.run(function () {
      runNextBenchmark();
    }, cfg);
  } else {
    sys.puts("\033[1mAll benchmarks finished\033[22m");
  }
}

runNextBenchmark();

#!/usr/bin/env node
/*
Copyright (C) 2010, Oleg Efimov <efimovov@gmail.com>

See license text in LICENSE file
*/

var
  bindings_list = ['Sannis-node-mysql-libmysqlclient', 'felixge-node-mysql', /*'stevebest-node-mysql',*/ 'PHP-MySQL'],
  //bindings_list = ['sidorares-nodejs-mysql-native'],
  sys = require('sys'),
  default_factor = 1,
  factor = default_factor,
  cfg;

if (process.argv[2] !== undefined) {
  factor = Math.abs(process.argv[2]);

  if (isNaN(factor)) {
    factor = default_factor;
  }
}

cfg = require("./src/config").getConfig(factor);

function runNextBenchmark() {
  if (bindings_list.length > 0) {
    var binding_name = bindings_list.shift();
    sys.puts("\033[1mBenchmarking " + binding_name + ":\033[22m");

    var benchmark = require("./src/" + binding_name);
    benchmark.run(function () {
      runNextBenchmark();
    }, cfg);
  } else {
    sys.puts("\033[1mAll benchmarks finished\033[22m");
  }
}

runNextBenchmark();

Add //bindings_list = ['sidorares-nodejs-mysql-native'] for tests


var Game = (function () {
    var Game = function (canvasRenderer,svgRenderer ) {

    };

    return Game;
}());

var canvasDrawer = new CanvasDrawer();
var player = new Player('Pesho', 20, 180, 15);
var disc = new Disc(canvasDrawer.canvasWidth / 2, canvasDrawer.canvasHeight / 2, 12);

function startGame() {
    canvasDrawer.clear();
    canvasDrawer.drawPlayer(player);
    canvasDrawer.drawDisc(disc);
    player.move();
    disc.move();
    detectCollisionWithDisc(player, disc);

    function detectCollisionWithDisc(player, disc) {

        var dx = player.x - disc.x,
            dy = player.y - disc.y,
            distance = Math.sqrt(dx * dx + dy * dy);

        if (distance < player.radius + disc.radius) {
            if (distance === 0) {
                distance = 0.1;
            }

            var unitX = dx / distance,
                unitY = dy / distance,

                force = -2,
                forceX = unitX * force,
                forceY = unitY * force;

            disc.velocity.x += forceX + player.speed / 2;
            disc.velocity.y += forceY + player.speed / 2;

            return true;
        } else {
            return false;
        }
    }

    // bounce off the floor
    if (disc.y > canvasDrawer.canvasHeight - disc.radius) {
        disc.y = canvasDrawer.canvasHeight - disc.radius;
        disc.velocity.y = -Math.abs(disc.velocity.y);
    }

    // bounce off ceiling
    if (disc.y < disc.radius + 0) {
        disc.y = disc.radius + 0;
        disc.velocity.y = Math.abs(disc.velocity.y);
    }
    // bounce off right wall
    if (disc.x > canvasDrawer.canvasWidth - disc.radius) {
        disc.x = canvasDrawer.canvasWidth - disc.radius;
        disc.velocity.x = -Math.abs(disc.velocity.x);
    }
    // bounce off left wall
    if (disc.x < disc.radius) {
        disc.x = disc.radius;
        disc.velocity.x = Math.abs(disc.velocity.x);
    }

    requestAnimationFrame(function () {
        startGame();
    });
}

startGame();

Implement logic for player and disc movements and collision between them


var gutil = require('gulp-util'),
    fs = require('fs');

/**
 * Loads reporter by its name.
 *
 * The function works only with reporters that shipped with the plugin.
 *
 * @param {String} name Name of a reporter to load.
 * @param {Object} options Custom options object that will be passed to
 *   a reporter.
 * @returns {Function}
 */
module.exports = function(name, options) {
    if (typeof name !== 'string') {
        throw new gutil.PluginError('gulp-phpcs', 'Reporter name must be a string');
    }

    if (name === 'index') {
        throw new gutil.PluginError('gulp-phpcs', 'Reporter cannot be named "index"');
    }

    var fileName = __dirname + '/' + name + '.js',
        reporter = null;
    try {
        reporter = require(fileName)(options || {});
    } catch(error) {
        if (error.code !== 'MODULE_NOT_FOUND') {
            throw error;
        }

        throw new gutil.PluginError('gulp-phpcs', 'There is no reporter "' + name + '"');
    }

    return reporter;
};

var gutil = require('gulp-util'),
    fs = require('fs');

/**
 * Loads reporter by its name.
 *
 * The function works only with reporters that shipped with the plugin.
 *
 * @param {String} name Name of a reporter to load.
 * @param {Object} options Custom options object that will be passed to
 *   a reporter.
 * @returns {Function}
 */
module.exports = function(name, options) {
    if (typeof name !== 'string') {
        throw new gutil.PluginError('gulp-phpcs', 'Reporter name must be a string');
    }

    if (name === 'index') {
        throw new gutil.PluginError('gulp-phpcs', 'Reporter cannot be named "index"');
    }

    var fileName = './' + name + '.js',
        reporter = null;
    try {
        reporter = require(fileName)(options || {});
    } catch(error) {
        if (error.code !== 'MODULE_NOT_FOUND') {
            throw error;
        }

        throw new gutil.PluginError('gulp-phpcs', 'There is no reporter "' + name + '"');
    }

    return reporter;
};

Make reporters' loader work on windows


// Generate a single webpack bundle for all tests for faster testing
// See https://github.com/webpack/karma-webpack#alternative-usage

// Configure raven with a fake DSN to avoid errors in test output
var Raven = require('raven-js');
Raven.config('http://abc@example.com:80/2');

// Include all files that end with .test.js (core tests)
var context = require.context('.', true, /.*test\.js$/); //make sure you have your directory and regex test set correctly!
context.keys().forEach(context);

// Include all files in the addons directory that end with .test.js
var addonContext = require.context('../../../addons/', true, /.*test\.js$/); //make sure you have your directory and regex test set correctly!
addonContext.keys().forEach(addonContext);

// Generate a single webpack bundle for all tests for faster testing
// See https://github.com/webpack/karma-webpack#alternative-usage

// Configure raven with a fake DSN to avoid errors in test output
var Raven = require('raven-js');
Raven.config('http://abc@example.com:80/2');

// Include all files that end with .test.js (core tests)
var context = require.context('.', true, /.*test\.js$/); //make sure you have your directory and regex test set correctly!
context.keys().forEach(context);

// Include all files in the addons directory that end with .test.js
var addonContext = require.context('../../../../addons/', true, /.*test\.js$/); //make sure you have your directory and regex test set correctly!
addonContext.keys().forEach(addonContext);

Update line that was pointing to the erstwhile ./website/addons now ./addons


var Bind = require("github/jillix/bind");
var Events = require("github/jillix/events");

module.exports = function(config) {

    var self = this;
    Events.call(self, config);

    for (var i in config.roles) {
        $("." + config.roles[i]).hide();
    }

    var cache;

    self.updateLinks = function (data) {

        cache = cache || data;
        data = cache || {};

        data.role = data.role || config.publicRole;

        $("." + data.role).fadeIn();
        var index = config.roles.indexOf(data.role);

        if (index !== -1) {
            config.roles.splice(index, 1);
        }

        for (var i in config.roles) {
            $("." + config.roles[i]).remove();
        }

        self.emit("updatedLinks", data);
    };
};

var Bind = require("github/jillix/bind");
var Events = require("github/jillix/events");

module.exports = function(config) {

    var self = this;
    Events.call(self, config);

    for (var i in config.roles) {
        $("." + config.roles[i]).hide();
    }

    var cache;

    self.updateLinks = function (data) {

        cache = cache || data;
        data = cache || {};

        data.role = data.role || config.publicRole;

        $("." + data.role).fadeIn();
        var index = config.roles.indexOf(data.role);

        if (index !== -1) {
            config.roles.splice(index, 1);
        }

        for (var i in config.roles) {
            $("." + config.roles[i] + ":not('." + data.role + "')").remove();
        }

        self.emit("updatedLinks", data);
    };
};

Remove only links that have not the data.role class.


const trimStart = (str) => {
  // NOTE String.trimStart is available on Firefox 61
  return str.replace(/^\s+/, '');
};

const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:'];

const searchUrl = (keywords, searchSettings) => {
  try {
    let u = new URL(keywords);
    if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) {
      return u.href;
    }
  } catch (e) {
    // fallthrough
  }
  if (keywords.includes('.') && !keywords.includes(' ')) {
    return 'http://' + keywords;
  }
  let template = searchSettings.engines[searchSettings.default];
  let query = keywords;

  let first = trimStart(keywords).split(' ')[0];
  if (Object.keys(searchSettings.engines).includes(first)) {
    template = searchSettings.engines[first];
    query = trimStart(trimStart(keywords).slice(first.length));
  }
  return template.replace('{}', encodeURIComponent(query));
};

const normalizeUrl = (url) => {
  try {
    let u = new URL(url);
    if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) {
      return u.href;
    }
  } catch (e) {
    // fallthrough
  }
  return 'http://' + url;
};

const homepageUrls = (value) => {
  return value.split('|').map(normalizeUrl);
};

export { searchUrl, normalizeUrl, homepageUrls };

const trimStart = (str) => {
  // NOTE String.trimStart is available on Firefox 61
  return str.replace(/^\s+/, '');
};

const SUPPORTED_PROTOCOLS = ['http:', 'https:', 'ftp:', 'mailto:', 'about:'];

const searchUrl = (keywords, searchSettings) => {
  try {
    let u = new URL(keywords);
    if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) {
      return u.href;
    }
  } catch (e) {
    // fallthrough
  }
  if (keywords.includes('.') && !keywords.includes(' ')) {
    return 'http://' + keywords;
  }
  let template = searchSettings.engines[searchSettings.default];
  let query = keywords;

  let first = trimStart(keywords).split(' ')[0];
  if (Object.keys(searchSettings.engines).includes(first)) {
    template = searchSettings.engines[first];
    query = trimStart(trimStart(keywords).slice(first.length));
  }
  return template.replace('{}', encodeURIComponent(query));
};

const normalizeUrl = (url) => {
  try {
    let u = new URL(url);
    if (SUPPORTED_PROTOCOLS.includes(u.protocol.toLowerCase())) {
      return u.href;
    }
  } catch (e) {
    // fallthrough
  }
  return 'http://' + url;
};

const homepageUrls = (value) => {
  return value.split('|').map(normalizeUrl);
};

export { searchUrl, normalizeUrl, homepageUrls };

Add about: pages to open home page


$(document).ready(function(){
    $('.entries').slick({
        slidesToShow: 3,
        variableWidth: true,
        autoplay: true,
        lazyLoad: 'ondemand'
    });
    Dropzone.options.dropzoneSubmitPhoto = {
        paramName: "image",
        maxFilesize: 2 // MB
    };
});

$(document).ready(function(){
    $('.entries').slick({
        slidesToShow: 3,
        variableWidth: true,
        autoplay: true,
        lazyLoad: 'ondemand'
    });
    Dropzone.options.dropzoneSubmitPhoto = {
        paramName: "image",
        maxFilesize: 2, // MB
        init: function() {
            this.on("success", function(file) {
                // Refresh the page to see uploaded contents
                location.reload();
            });
        }
    };
});

Refresh the page when successfully uploading a photo


import React, { Component } from 'react'
import { reduxForm, Field } from 'redux-form'

class NewMealForm extends Component {

  render() {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <label htmlFor="name">Meal Name</label>
        <Field name="name" component="input" type="text" />
        <button>Create Meal</button>
      </form>
    )
  }
}

export default reduxForm({
  form: 'newMeal'
})(NewMealForm)

import React, { Component } from 'react'
import { reduxForm, Field } from 'redux-form'
import { css } from 'glamor'

class NewMealForm extends Component {

  render() {
    return (
      <form onSubmit={this.props.handleSubmit}>
        <ul {...ul}>
          <li {...styles}>
            <label {...styles2} htmlFor="name">Meal Name</label>
            <Field {...styles3} name="name" component="input" type="text" />
          </li>
          <li {...styles}>
            <button {...btnStyle} >Create Meal</button>
          </li>
        </ul>
      </form>
    )
  }
}

const styles3 = css({
  flex: '1 0 220px',
  padding: '15px',
  borderRadius: '15px',
  border: '2px solid gray',
  ':focus': {
    outline: 'none'
  }
})

const ul = css({
  maxWidth: '800px',
  margin: '0 auto'
})

const styles = css({
  display: 'flex',
  flexWrap: 'wrap',
  alignItems: 'center',
  justifyContent: 'space-between',
  // maxWidth: '800px',
  marginBottom: '20px'
})

const btnStyle = css({
  marginLeft: 'auto',
  padding: '8px 16px',
  border: 'none',
  background: '#333',
  color: '#f2f2f2',
  textTransform: 'uppercase',
  letterSpacing: '.09em',
  borderRadius: '2px'
})

const styles2 = css({
  flex: '1 0 120px',
  maxWidth: '220px'
})

export default reduxForm({
  form: 'newMeal'
})(NewMealForm)

Add styling for new meal form


$(window).scroll
  ( function ()
    {
      $( "header" ).css
        ( "top"
        , Math.max(-280, Math.min(0, -$("body").scrollTop()))
        );
    }
  );

$("nav a").click
  ( function (ev)
    {
      var target = $("*[name=" + $(ev.target).attr("href").substr(1) + "]");

      $("html, body").animate({ scrollTop: $(target).offset().top - 80 });
      ev.preventDefault();
      ev.stopPropagation();
    }
  );

$("header > div").click
  ( function (ev)
    {
      $("html, body").animate({ scrollTop: 0 });
    }
  );

$(window).scroll
  ( function ()
    {
      $( "header" ).css
        ( "top"
        , Math.max(-280, Math.min(0, -$("body").scrollTop()))
        );
    }
  );

$("nav a").click
  ( function (ev)
    {
      var target = $("*[name=" + $(ev.target).attr("href").substr(1) + "]");

      $("html, body").animate
        ( { scrollTop : $(target).offset().top - 80 }
        , ev.shiftKey ? 2500 : 500
        );
      ev.preventDefault();
      ev.stopPropagation();
    }
  );

$("header > div").click
  ( function (ev)
    {
      $("html, body").animate({ scrollTop: 0 });
    }
  );

Allow slow scrolling with shift.


/**
 * Hint HTML
 */
'use strict';

const gulp     = require('gulp'),
      htmlhint = require('gulp-htmlhint'),
      notify   = require('gulp-notify');

module.exports = function(options) {

  return cb => {
    gulp.src('./*.html')
      .pipe(htmlhint())
      .pipe(htmlhint.reporter('htmlhint-stylish'))
      .pipe(htmlhint.failReporter({
        suppress: true
      }))
      .on('error', notify.onError({
        title: 'HTML'
      }));

    cb();
  };

};

/**
 * Hint HTML
 */
'use strict';

const gulp     = require('gulp'),
      htmlhint = require('gulp-htmlhint'),
      notify   = require('gulp-notify');

module.exports = function(options) {

  return cb => {
    gulp.src('./*.html')
      .pipe(htmlhint({
        'attr-lowercase': ['viewBox']
      }))
      .pipe(htmlhint.reporter('htmlhint-stylish'))
      .pipe(htmlhint.failReporter({
        suppress: true
      }))
      .on('error', notify.onError({
        title: 'HTML'
      }));

    cb();
  };

};

Add the 'viewBox' attribute to htmlhint ignore list


const assert = require("assert");

// Masquerade as the REPL module.
module.filename = null;
module.id = "<repl>";
module.loaded = false;
module.parent = void 0;

delete require.cache[require.resolve("../node/repl-hook.js")];

describe("Node REPL", () => {
  import "../node/repl-hook.js";
  import { createContext } from "vm";
  import { enable } from "../lib/runtime";
  import repl from "repl";

  it("should work with global context", (done) => {
    const r = repl.start({ useGlobal: true });
    enable(r.context.module);

    assert.strictEqual(typeof assertStrictEqual, "undefined");

    r.eval(
      'import { strictEqual as assertStrictEqual } from "assert"',
      null, // Context
      "repl", // Filename
      (err, result) => {
        // Use the globally defined assertStrictEqual to test itself!
        assertStrictEqual(typeof assertStrictEqual, "function");
        done();
      }
    );
  });

  it("should work with non-global context", (done) => {
    const r = repl.start({ useGlobal: false });
    const context = createContext({ module, require });

    r.eval(
      'import { strictEqual } from "assert"',
      context,
      "repl", // Filename
      (err, result) => {
        // Use context.strictEqual to test itself!
        context.strictEqual(typeof context.strictEqual, "function");
        done();
      }
    );
  });
});

const assert = require("assert");

// Masquerade as the REPL module.
module.filename = null;
module.id = "<repl>";
module.loaded = false;
module.parent = void 0;

delete require.cache[require.resolve("../node/repl-hook.js")];

describe("Node REPL", () => {
  import "../node/repl-hook.js";
  import { createContext } from "vm";
  import { enable } from "../lib/runtime";
  import repl from "repl";

  it("should work with global context", (done) => {
    const r = repl.start({ useGlobal: true });
    enable(r.context.module);

    assert.strictEqual(typeof assertStrictEqual, "undefined");

    r.eval(
      'import { strictEqual as assertStrictEqual } from "assert"',
      null, // Context
      "repl", // Filename
      (err, result) => {
        // Use the globally defined assertStrictEqual to test itself!
        assertStrictEqual(typeof assertStrictEqual, "function");
        if (typeof r.close === "function") {
          r.close();
        }
        done();
      }
    );
  });

  it("should work with non-global context", (done) => {
    const r = repl.start({ useGlobal: false });
    const context = createContext({ module, require });

    r.eval(
      'import { strictEqual } from "assert"',
      context,
      "repl", // Filename
      (err, result) => {
        // Use context.strictEqual to test itself!
        context.strictEqual(typeof context.strictEqual, "function");
        if (typeof r.close === "function") {
          r.close();
        }
        done();
      }
    );
  });
});

Make sure to close REPLs started by tests.


'use strict';

// Service for the spec config.
// We keep this separate so that changes are kept even if the spec changes.
angular.module('vlui')
  .factory('Config', function() {
    var Config = {};

    Config.data = {};
    Config.config = {};

    Config.getConfig = function() {
      return {};
    };

    Config.getData = function() {
      return Config.data;
    };

    Config.large = function() {
      return {
        cell: {
          width: 300,
          height: 300
        },
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        }
      };
    };

    Config.small = function() {
      return {
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        }
      };
    };

    Config.updateDataset = function(dataset, type) {
      if (dataset.values) {
        Config.data.values = dataset.values;
        delete Config.data.url;
        Config.data.formatType = undefined;
      } else {
        Config.data.url = dataset.url;
        delete Config.data.values;
        Config.data.formatType = type;
      }
    };

    return Config;
  });

'use strict';

// Service for the spec config.
// We keep this separate so that changes are kept even if the spec changes.
angular.module('vlui')
  .factory('Config', function() {
    var Config = {};

    Config.data = {};
    Config.config = {};

    Config.getConfig = function() {
      return {};
    };

    Config.getData = function() {
      return Config.data;
    };

    Config.large = function() {
      return {
        cell: {
          width: 300,
          height: 300
        },
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        },
        scale: {useRawDomain: false}
      };
    };

    Config.small = function() {
      return {
        facet: {
          cell: {
            width: 150,
            height: 150
          }
        }
      };
    };

    Config.updateDataset = function(dataset, type) {
      if (dataset.values) {
        Config.data.values = dataset.values;
        delete Config.data.url;
        Config.data.formatType = undefined;
      } else {
        Config.data.url = dataset.url;
        delete Config.data.values;
        Config.data.formatType = type;
      }
    };

    return Config;
  });

Make polestar's config useRawDomain = false


var registerSystem = require('../core/system').registerSystem;

/**
 * Tracked controls system.
 * Maintain list with available tracked controllers.
 */
module.exports.System = registerSystem('tracked-controls-webxr', {
  init: function () {
    this.addSessionEventListeners = this.addSessionEventListeners.bind(this);
    this.onInputSourcesChange = this.onInputSourcesChange.bind(this);
    this.addSessionEventListeners();
    this.el.sceneEl.addEventListener('enter-vr', this.addSessionEventListeners);
  },

  addSessionEventListeners: function () {
    var sceneEl = this.el;
    if (!sceneEl.xrSession) { return; }
    this.onInputSourcesChange();
    sceneEl.xrSession.addEventListener('inputsourceschange', this.onInputSourcesChange);
  },

  onInputSourcesChange: function () {
    this.controllers = this.el.xrSession.getInputSources();
    this.el.emit('controllersupdated', undefined, false);
  }
});

var registerSystem = require('../core/system').registerSystem;

/**
 * Tracked controls system.
 * Maintain list with available tracked controllers.
 */
module.exports.System = registerSystem('tracked-controls-webxr', {
  init: function () {
    this.controllers = [];
    this.addSessionEventListeners = this.addSessionEventListeners.bind(this);
    this.onInputSourcesChange = this.onInputSourcesChange.bind(this);
    this.addSessionEventListeners();
    this.el.sceneEl.addEventListener('enter-vr', this.addSessionEventListeners);
  },

  addSessionEventListeners: function () {
    var sceneEl = this.el;
    if (!sceneEl.xrSession) { return; }
    this.onInputSourcesChange();
    sceneEl.xrSession.addEventListener('inputsourceschange', this.onInputSourcesChange);
  },

  onInputSourcesChange: function () {
    this.controllers = this.el.xrSession.getInputSources();
    this.el.emit('controllersupdated', undefined, false);
  }
});

Initialize controllers to empty array


import React from 'react';

function allMustExist(props) {
  Object.keys(props).every(propName => props[propName] != null);
}

export default function pending(NotReadyComponent) {
  return (hasLoaded = allMustExist) => (ReadyComponent, ErrorComponent) => ({ error, ...props }) => {
    if (error) {
      return <ErrorComponent error={ error } { ...props } />;
    }
    else if (hasLoaded(props, ReadyComponent)) {
      return <ReadyComponent { ...props } />;
    }
    else {
      return <NotReadyComponent />;
    }
  }
}

import React from 'react';

function allMustExist(props) {
  Object.keys(props).every(propName => props[propName] != null);
}

function propTypesMustExist(props, { propTypes, displayName }) {
  Object.keys(propTypes).every(propName => propTypes[propName](props, propName, displayName) == null);
}

export default function pending(NotReadyComponent) {
  return (hasLoaded = propTypesMustExist) => (ReadyComponent, ErrorComponent) => ({ error, ...props }) => {
    if (error) {
      return <ErrorComponent error={ error } { ...props } />;
    }
    else if (hasLoaded(props, ReadyComponent)) {
      return <ReadyComponent { ...props } />;
    }
    else {
      return <NotReadyComponent />;
    }
  }
}

Add required prop types checker, and make it default loaded tester


// @flow
export {default as ChartData} from './chartdata/ChartData';

export {default as LineCanvas} from './component/canvas/LineCanvas';
export {default as ColumnCanvas} from './component/canvas/ColumnCanvas';
export {default as ScatterCanvas} from './component/canvas/ScatterCanvas';

// @flow
export {default as ChartData} from './chartdata/ChartData';

export {default as Canvas} from './component/canvas/Canvas';
export {default as LineCanvas} from './component/canvas/LineCanvas';
export {default as ColumnCanvas} from './component/canvas/ColumnCanvas';
export {default as ScatterCanvas} from './component/canvas/ScatterCanvas';

Add canvas to export seeing as it is part of public api


var fs = require('fs'),
    Path = require('path'),
    scripts;

scripts = [
    'pokemonfusion.js',
    'catoverflow.js',
    'nugme.coffee',
    'mta.coffee',
    'spot.js',
    'hr.js'
];

module.exports = function (robot) {
    var path = Path.resolve(__dirname, 'scripts');
    fs.exists(path, function (exists) {
        if (exists) {
            scripts.forEach(function (file) {
                robot.loadFile(path, file);
            });
        }
    });
};

var fs = require('fs'),
    Path = require('path'),
    scripts;

scripts = [
    'pokemonfusion.js',
    'catoverflow.js',
    'nugme.coffee',
    'mta.coffee',
    'spot.js',
    'hr.js',
    'jenkins-notifier.coffee'
];

module.exports = function (robot) {
    var path = Path.resolve(__dirname, 'scripts');
    fs.exists(path, function (exists) {
        if (exists) {
            scripts.forEach(function (file) {
                robot.loadFile(path, file);
            });
        }
    });
};

Enable our version of the jenkins-notifier script


import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware()(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <App />
  </Provider>
  , document.querySelector('.container'));

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route } from 'react-router-dom';

import App from './components/app';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware()(createStore);

class Hello extends React.Component {
  render() {
    return (

Hello

    )
  }
}

class Goodbye extends React.Component {
  render() {
    return (

Goodbye

    )
  }
}

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <BrowserRouter>

        <Route path='/hello' component={Hello}/>
        <Route path='/goodbye' component={Goodbye} />

    </BrowserRouter>
  </Provider>
  , document.querySelector('.container'));

Add dummy routes to try react-router-dom


$(document).ready(function() {

    $('select[multiple]').each(function() {
        var select = $(this),
            search = $('<button/>', {
                'class': 'btn'
            }).append(
            $('<span/>', {
                'class': 'icon-search'
            }));
        select.removeAttr('required');
        select.parent().parent().find('span').remove();
        select.wrap($('<div/>', {
            'class': 'input-append'
        }));
        select.after(search);
        select.select2({
            'width': '350px'
        });
        search.on('click', function() {
            select.select2('open');
            return false;
        });
    });

    $('form').on('submit', function() {
        if ($(this).get(0).checkValidity() === false) {
            return;
        }
        $(this).find('a, input[type=submit], button').addClass('disabled');
    });

    $('.click-disable').on('click', function() {
        if ($(this).closest('form').length > 0) {
            if ($(this).closest('form').get(0).checkValidity() === false) {
                return;
            }
        }
        $(this).addClass('disabled');
        $(this).find('span').attr('class', 'icon-spinner icon-spin');
    });

    $('.datepicker').css('width', '100px').datepicker({
        'format': 'dd-mm-yyyy',
        'language': 'nl'
    });
});

$(document).ready(function() {

    if(!/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent)) {
        $('select[multiple]').each(function() {
            var select = $(this),
                search = $('<button/>', {
                    'class': 'btn'
                }).append(
                $('<span/>', {
                    'class': 'icon-search'
                }));
            select.removeAttr('required');
            select.parent().parent().find('span').remove();
            select.wrap($('<div/>', {
                'class': 'input-append'
            }));
            select.after(search);
            select.select2({
                'width': '350px'
            });
            search.on('click', function() {
                select.select2('open');
                return false;
            });
        });
    }

    $('form').on('submit', function() {
        if ($(this).get(0).checkValidity() === false) {
            return;
        }
        $(this).find('a, input[type=submit], button').addClass('disabled');
    });

    $('.click-disable').on('click', function() {
        if ($(this).closest('form').length > 0) {
            if ($(this).closest('form').get(0).checkValidity() === false) {
                return;
            }
        }
        $(this).addClass('disabled');
        $(this).find('span').attr('class', 'icon-spinner icon-spin');
    });

    $('.datepicker').css('width', '100px').datepicker({
        'format': 'dd-mm-yyyy',
        'language': 'nl'
    });
});

Disable select2 on mobile devices


#!/usr/bin/env node
'use strict';
import fs from 'fs';
import snfe from './index';
import { name, version } from './package.json';

let printHelpMesage = () => {
    console.log(`\nStrip Named Function Expression\n`);
    console.log(`Usage:\n`);
    console.log(`   snfe [input file] > [output file]`);
    console.log(`\n${name}@${version} ${process.argv[1]}\n`);
};

if (process.argv.indexOf(`-h`) !== -1 ||
    process.argv.indexOf(`--help`) !== -1 ||
    process.argv.length === 2 ) {
    printHelpMesage();
    process.exit(0);
} else if (process.argv.indexOf(`-v`) !== -1 || process.argv.indexOf(`--version`) !== -1) {
    console.log(version);
    process.exit(0);
}

if (input) {
    process.stdout.write(strip(fs.readFileSync(input, `utf8`)).toString());
    process.exit(0);
}

#!/usr/bin/env node
'use strict';
import fs from 'fs';
import snfe from './index';
import { name, version } from './package.json';

let printHelpMesage = () => {
    console.log(`\nStrip Named Function Expression\n`);
    console.log(`Usage:\n`);
    console.log(`   snfe [input file] > [output file]`);
    console.log(`\n${name}@${version} ${process.argv[1]}\n`);
};

if (process.argv.indexOf(`-h`) !== -1 ||
    process.argv.indexOf(`--help`) !== -1 ||
    process.argv.length === 2 ) {
    printHelpMesage();
    process.exit(0);
} else if (process.argv.indexOf(`-v`) !== -1 || process.argv.indexOf(`--version`) !== -1) {
    console.log(version);
    process.exit(0);
}

let input = process.argv[2];

if (input) {
    let inputString = fs.readFileSync(input, `utf8`);
    let result = snfe(inputString);
    process.stdout.write(result);
    process.exit(0);
}

process.exit(0);

Refactor the main logic block


/**
 * Compile:JS task.
 * Uglify and merge all javascript files in 'Public/Javascripts/Sources/'.
 */

var config = require("../../Config");

module.exports = function(grunt) {
	"use strict";

	grunt.registerTask("compile:js", function() {
		// Optimize all js files if the 'useSingleFileBuild' option is 'false'.
		if(!config.JavaScripts.requireJS.useSingleFileBuild || grunt.option('env') === 'travis') {
			grunt.task.run("uglify:all");
		}

		// Optimize the project via the r.js optimizer.
		grunt.task.run("requirejs");
	});
};

/**
 * Compile:JS task.
 * Uglify and merge all javascript files in 'Public/Javascripts/Sources/'.
 */

var config = require("../../Config");

module.exports = function(grunt) {
	"use strict";

	grunt.registerTask("compile:js", function() {
		// Optimize all js files if the 'useSingleFileBuild' option is 'false'.
		if(!config.JavaScripts.requireJS.useSingleFileBuild || grunt.option('env') === 'travis') {
			grunt.task.run("uglify:js");
		}

		// Optimize the project via the r.js optimizer.
		grunt.task.run("requirejs");
	});
};

Set the correct sub-task name for the uglify task


import React from 'react';

import Logo from './components/logo'
import SocialButtons from './components/social-buttons'
import Navigation from './components/navigation'
import Home from './components/home';
import Footer from './components/footer';

import AppUrl from './appurl'

class Page {
  render() {

    let appUrl = new AppUrl();
    const siteComponent = this.props.siteComponent;

    return (
      <div id="wrapper" className="pure-g">
        <header className="pure-u-2-3">
          <Logo/>
          <SocialButtons/>
          <Navigation appUrl={appUrl} />
        </header>
        {siteComponent}
        <Footer />
      </div>
    )
  }
}

const rerender = (siteComponent = <Home />) => {
  React.render(<Page siteComponent={siteComponent} />, document.getElementById('app'));
};

import {parse as parseUrl} from 'url';
import Chronicle from './lexicon/chronicle'

window.addEventListener('hashchange', ({newURL: newUrl}) => {
  const parsedUrl = parseUrl(newUrl);
  processUrl(parsedUrl);
});

function processUrl(parsedUrl) {
  if (parsedUrl && parsedUrl.hash && parsedUrl.hash.startsWith('#/')) {
    if (parsedUrl.hash.match(/^#\/chronicle/)) {
      Chronicle.componentWithData((chronicleComponent) => {
        rerender(chronicleComponent);
      });
    }
  } else {
    rerender(<Home />);
  }
}

processUrl();

import React from 'react';
import 'babel/polyfill';

import Logo from './components/logo'
import SocialButtons from './components/social-buttons'
import Navigation from './components/navigation'
import Home from './components/home';
import Footer from './components/footer';

import AppUrl from './appurl'

class Page {
  render() {

    let appUrl = new AppUrl();
    const siteComponent = this.props.siteComponent;

    return (
      <div id="wrapper" className="pure-g">
        <header className="pure-u-2-3">
          <Logo/>
          <SocialButtons/>
          <Navigation appUrl={appUrl} />
        </header>
        {siteComponent}
        <Footer />
      </div>
    )
  }
}

const rerender = (siteComponent = <Home />) => {
  React.render(<Page siteComponent={siteComponent} />, document.getElementById('app'));
};

import {parse as parseUrl} from 'url';
import Chronicle from './lexicon/chronicle'

window.addEventListener('hashchange', ({newURL: newUrl}) => {
  const parsedUrl = parseUrl(newUrl);
  processUrl(parsedUrl);
});

function processUrl(parsedUrl) {
  if (parsedUrl && parsedUrl.hash && parsedUrl.hash.startsWith('#/')) {
    if (parsedUrl.hash.match(/^#\/chronicle/)) {
      Chronicle.componentWithData((chronicleComponent) => {
        rerender(chronicleComponent);
      });
    }
  } else {
    rerender(<Home />);
  }
}

processUrl();

Load babel polyfills, to work in less ES6 ready browsers.


$(function () {
    $(".inline." + formset_prefix).formset({
        prefix: formset_prefix, // The form prefix for your django formset
        addCssClass: "btn btn-block btn-primary bordered inline-form-add", // CSS class applied to the add link
        deleteCssClass: "btn btn-block btn-primary bordered", // CSS class applied to the delete link
        addText: 'Add another question', // Text for the add link
        deleteText: 'Remove question above', // Text for the delete link
        formCssClass: 'inline-form', // CSS class applied to each form in a formset
        added: function (row) {
            add_autocomplete(row);
        }
    })
});

$(function () {
    $(".inline." + formset_prefix).formset({
        prefix: formset_prefix, // The form prefix for your django formset
        addCssClass: "btn btn-block btn-primary bordered inline-form-add", // CSS class applied to the add link
        deleteCssClass: "btn btn-block btn-primary bordered", // CSS class applied to the delete link
        addText: 'Add another question', // Text for the add link
        deleteText: 'Remove question above', // Text for the delete link
        formCssClass: 'inline-form', // CSS class applied to each form in a formset
        added: function (row) {
            add_autocomplete(row);
            row.find("input").first().prop('disabled', true);
        },
        removed: function (row) {
            if ($('#id_' + formset_prefix + '-TOTAL_FORMS').val() == 1) {
                $(".inline." + formset_prefix).find("input").prop("disabled", false);
            }
        }
    })
});

Disable origin textfield for forms != first one


require('./lib/whatwg-fetch/fetch.js')
require('./lib/kube-6.0.1/kube.min.css')

import 'react-hot-loader/patch'
import React from 'react'
import ReactDOM from 'react-dom'
import Root from './components/Root'
import configureStore  from './configureStore'

const store = configureStore()

// import { AppContainer } from 'react-hot-loader'

ReactDOM.render(
  <Root store={ store } />,
  document.getElementById('app')
)

// if (module.hot) {
//   module.hot.accept('./containers/CashmereAppContainer', () => {
//     const NextCashmereAppContainer = require('./containers/CashmereAppContainer').CashmereAppContainer
//     ReactDOM.render(
//       // <AppContainer>
//         <Provider store={ store }>
//           <NextCashmereAppContainer />
//         </Provider>,
//       // </AppContainer>,
//       rootEl
//     )
//   })
// }

require('./lib/whatwg-fetch/fetch.js')
//require('./lib/kube-6.0.1/kube.min.css')

// Needed for onTouchTap
// http://stackoverflow.com/a/34015469/988941
import injectTapEventPlugin from 'react-tap-event-plugin';
injectTapEventPlugin();

import 'react-hot-loader/patch'
import React from 'react'
import ReactDOM from 'react-dom'
import Root from './components/Root'
import configureStore  from './configureStore'

const store = configureStore()

// import { AppContainer } from 'react-hot-loader'

ReactDOM.render(
  <Root store={ store } />,
  document.getElementById('app')
)

// if (module.hot) {
//   module.hot.accept('./containers/CashmereAppContainer', () => {
//     const NextCashmereAppContainer = require('./containers/CashmereAppContainer').CashmereAppContainer
//     ReactDOM.render(
//       // <AppContainer>
//         <Provider store={ store }>
//           <NextCashmereAppContainer />
//         </Provider>,
//       // </AppContainer>,
//       rootEl
//     )
//   })
// }

Remove kube and add react touch events


import Player from './components/Player';
import Video from './components/Video';
import BigPlayButton from './components/BigPlayButton';
import LoadingSpinner from './components/LoadingSpinner';
import PosterImage from './components/PosterImage';
import ControlBar from './components/control-bar/ControlBar';
import ForwardControl from './components/control-bar/ForwardControl';
import ReplayControl from './components/control-bar/ReplayControl';
import ForwardReplayControl from './components/control-bar/ForwardReplayControl';
import ProgressControl from './components/control-bar/ProgressControl';
import MouseTimeDisplay from './components/control-bar/MouseTimeDisplay';
import PlayToggle from './components/control-bar/PlayToggle';
import Slider from './components/Slider';

export {
  Player,
  Video,
  BigPlayButton,
  LoadingSpinner,
  PosterImage,
  ControlBar,
  ForwardControl,
  ReplayControl,
  MouseTimeDisplay,
  PlayToggle,
  ForwardReplayControl,
  ProgressControl,
  Slider,
};

import Player from './components/Player';
import Video from './components/Video';
import BigPlayButton from './components/BigPlayButton';
import LoadingSpinner from './components/LoadingSpinner';
import PosterImage from './components/PosterImage';
import ControlBar from './components/control-bar/ControlBar';
import ForwardControl from './components/control-bar/ForwardControl';
import ReplayControl from './components/control-bar/ReplayControl';
import ForwardReplayControl from './components/control-bar/ForwardReplayControl';
import ProgressControl from './components/control-bar/ProgressControl';
import MouseTimeDisplay from './components/control-bar/MouseTimeDisplay';
import PlayToggle from './components/control-bar/PlayToggle';
import SeekBar from './components/control-bar/SeekBar';
import FullscreenToggle from './components/control-bar/FullscreenToggle';
import PlayProgressBar from './components/control-bar/PlayProgressBar';
import LoadProgressBar from './components/control-bar/LoadProgressBar';
import Slider from './components/Slider';

export {
  Player,
  Video,
  BigPlayButton,
  LoadingSpinner,
  PosterImage,
  ControlBar,
  ForwardControl,
  ReplayControl,
  MouseTimeDisplay,
  PlayToggle,
  ForwardReplayControl,
  ProgressControl,
  SeekBar,
  FullscreenToggle,
  PlayProgressBar,
  LoadProgressBar,
  Slider,
};

Update Index.js to import new components


var environment = require('../environment'),
    offload = require('../../graphworker/standalone');

module.exports.search = function (options, recordcb, facetcb) {
    if (typeof options.query !== 'undefined') {
        if (typeof options.query.plan === 'undefined') {
            options.query.plan = environment.querybuilder.build(options.query.ast);
        }
        options.query.offset = options.offset;
        options.query.size = options.perpage;
    }
    offload('search', options, function (results) {
        recordcb(results.search);
    });
    if (typeof facetcb === 'function') {
        offload('facet', options, function (results) {
            facetcb(results.facet);
        });
    }
};

module.exports.facet = function (options, facetcb) {
    if (typeof options.query !== 'undefined' && typeof options.query.plan === 'undefined') {
        options.query.plan = environment.querybuilder.build(options.query.ast);
    }
    offload('facet', options, function (results) {
        facetcb(results.facet);
    });
};

var environment = require('../environment'),
    offload = require('../../graphworker/standalone');

module.exports.search = function (options, recordcb, facetcb) {
    if (typeof options.query !== 'undefined') {
        options.query.plan = environment.querybuilder.build(options.query.ast);
        options.query.offset = options.offset;
        options.query.size = options.perpage;
    }
    offload('search', options, function (results) {
        recordcb(results.search);
    });
    if (typeof facetcb === 'function') {
        offload('facet', options, function (results) {
            facetcb(results.facet);
        });
    }
};

module.exports.facet = function (options, facetcb) {
    if (typeof options.query !== 'undefined') {
        options.query.plan = environment.querybuilder.build(options.query.ast);
    }
    offload('facet', options, function (results) {
        facetcb(results.facet);
    });
};

Rebuild the query every time it's needed so that preseeded results display


var BOARD_HEIGHT = 288;
var BOARD_WIDTH = 224;
var VERT_TILES = BOARD_HEIGHT / 8;
var HORIZ_TILES = BOARD_WIDTH / 8;

gameBoard = new Array(VERT_TILES);
for(var y = 0; y < VERT_TILES; y++) {
  gameBoard[y] = new Array(HORIZ_TILES);
  for(var x = 0; x < HORIZ_TILES; x++) {
    gameBoard[y][x] = 0;
  }
}

var canvas, context;

var ready = function(fun) {
  if(document.readyState != "loading") {
    fun();
  }
  else if(document.addEventListener) {
    document.addEventListener("DOMContentLoaded", fun);
  }
  else {
    document.attachEvent("onreadystatechange", function() {
      if(document.readyState != "loading") {
        fun();
      }
    });
  }
}

ready(function() {
  canvas = document.getElementById("board");
  context = canvas.getContext("2d");
});

var BOARD_HEIGHT = 288;
var BOARD_WIDTH = 224;
var VERT_TILES = BOARD_HEIGHT / 8;
var HORIZ_TILES = BOARD_WIDTH / 8;

gameBoard = new Array(VERT_TILES);
for(var y = 0; y < VERT_TILES; y++) {
  gameBoard[y] = new Array(HORIZ_TILES);
  for(var x = 0; x < HORIZ_TILES; x++) {
    gameBoard[y][x] = "";
  }
}

var canvas, context;

var drawObject = function(args) {
  args.context.clearRect(0, 0, BOARD_WIDTH, BOARD_HEIGHT);
  args.context.fillStyle = args.color;

  args.objectArr.forEach(function(row, rIndex) {
    row.forEach(function(col, cIndex) {
      if(col == 1) {
        args.context.fillRect(args.x + cIndex, args.y + rIndex, 1, 1);
      }
    });
  });
}

var ready = function(fun) {
  if(document.readyState != "loading") {
    fun();
  }
  else if(document.addEventListener) {
    document.addEventListener("DOMContentLoaded", fun);
  }
  else {
    document.attachEvent("onreadystatechange", function() {
      if(document.readyState != "loading") {
        fun();
      }
    });
  }
}

ready(function() {
  canvas = document.getElementById("board");
  context = canvas.getContext("2d");

  drawObject({
    x: 80,
    y: 80,
    objectArr: charset["A"],
    color: "#FFF",
    context: context
  });
});

Add drawObject function to draw matrix of pixels


angular
    .module('ngVibrant')
    .provider('$vibrant', $vibrantProvider);

function $vibrantProvider() {
    this.$get = function() {
        function $vibrant(element) {
            var instance = new Vibrant(element);
            return instance.swatches();
        }
    };
}

angular
    .module('ngVibrant')
    .provider('$vibrant', $vibrantProvider);

function $vibrantProvider() {
    this.$get = function() {
        function $vibrant(element) {
            var instance = new Vibrant(element);
            var swatches = instance.swatches();
            var rgb = {};
            Object.getOwnPropertyNames(swatches).forEach(function(swatch) {
                if (angular.isDefined(swatches[swatch])) {
                    rgb[swatch] = swatches[swatch].rgb;
                }
            });
            return rgb;
        }
    };
}

Return only rgb swatches (gonna add a toggle for this later)


import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';

// Import all of your reducers here:
import employees from 'containers/GeoSpatialViewContainer/reducer';
import keyMetrics from 'containers/KeyMetricsViewContainer/reducer';
import dataView from 'containers/DataViewContainer/reducer';
import issueKeyMetrics from 'containers/IssueKeyMetricsContainer/reducer';

import client from './apolloClient';

const rootReducer = combineReducers({
  employees,
  dataView,
  keyMetrics,
  issueKeyMetrics,
  routing: routerReducer,
  form: formReducer,
  apollo: client.reducer(),
});

export default rootReducer;

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';

// Import all of your reducers here:
import employees from 'containers/GeospatialViewContainer/reducer';
import keyMetrics from 'containers/KeyMetricsViewContainer/reducer';
import dataView from 'containers/DataViewContainer/reducer';
import issueKeyMetrics from 'containers/IssueKeyMetricsContainer/reducer';

import client from './apolloClient';

const rootReducer = combineReducers({
  employees,
  dataView,
  keyMetrics,
  issueKeyMetrics,
  routing: routerReducer,
  form: formReducer,
  apollo: client.reducer(),
});

export default rootReducer;

TEST fix error cant resolve module


(function(){

'use strict';

angular
  .module('secondLead')

  .controller('LoginCtrl', [
    'Restangular',
    '$state',
    'store',
    'UserModel',
    function (Restangular, $state, store, UserModel) {
    var login = this;

    login.user = {};

    login.onSubmit = function() {
      UserModel.login(login.user)
      .then(function (response) {
        var user = response.data.user;
        $state.go('user.lists', {userID: user.id});
        login.reset();
       }, function(error){
        login.error = "Invalid username/password";
       }
      );
    }

    login.reset = function () {
      login.user = {};
    };

  }])

})();

(function(){

'use strict';

angular
  .module('secondLead')

  .controller('LoginCtrl', [
    'Restangular',
    '$state',
    'store',
    'UserModel',
    function (Restangular, $state, store, UserModel) {
    var login = this;

    login.user = {};

    login.onSubmit = function() {
      UserModel.login(login.user)
      .then(function (response) {
        var user = response.data.user;
        UserModel.setLoggedIn(true);
        $state.go('user.lists', {userID: user.id});
        login.reset();
       }, function(error){
        login.error = "Invalid username/password";
       }
      );
    }

    login.reset = function () {
      login.user = {};
    };

  }])

})();

Add update to usermodel upon login with login controller


var jQuery = require('jquery');
var VIE = require('../vie.js');

// Until https://github.com/tmpvar/jsdom/issues/issue/81 is fixed
VIE.RDFa.predicateSelector = '[property]';

exports['test inheriting subject'] = function(test) {
    var html = jQuery('
Albert Einstein1879-03-14
Federal Republic of Germany
');

    var entities = VIE.RDFa.readEntities(html);
    test.equal(entities.length, 2, "This RDFa defines two entities but they don't get parsed to JSON");

    var entities = VIE.RDFaEntities.getInstances(html);
    test.equal(entities.length, 2, "This RDFa defines two entities but they don't get to Backbone");

    test.done();
};

var jQuery = require('jquery');
var VIE = require('../vie.js');

// Until https://github.com/tmpvar/jsdom/issues/issue/81 is fixed
VIE.RDFa.predicateSelector = '[property]';

exports['test inheriting subject'] = function(test) {
    var html = jQuery('
Albert Einstein1879-03-14
Federal Republic of Germany
');

    var jsonldEntities = VIE.RDFa.readEntities(html);
    test.equal(jsonldEntities.length, 2, "This RDFa defines two entities but they don't get parsed to JSON");

    test.equal(jsonldEntities[1]['foaf:name'], 'Albert Einstein');
    test.equal(jsonldEntities[0]['dbp:conventionalLongName'], 'Federal Republic of Germany');

    var backboneEntities = VIE.RDFaEntities.getInstances(html);
    test.equal(backboneEntities.length, 2, "This RDFa defines two entities but they don't get to Backbone");

    test.equal(backboneEntities[1].get('foaf:name'), 'Albert Einstein');
    test.equal(backboneEntities[0].get('dbp:conventionalLongName'), 'Federal Republic of Germany');

    test.done();
};

Test getting properties as well


var phonecatControllers = angular.module('leaguecontrollers', []);

phonecatControllers.factory("dataProvider", ['$q', function($q) {
        console.log("Running dataProvider factory");

        return {
            getData: function() {
                var result = bowling.initialize({"root": "testdata"}, $q);
                return result;
            }
        }
    }]).controller('LeagueController', ['$scope', '$route', 'dataProvider',
    function ($scope, $route, dataProvider) {
        console.log("Loaded league data");

        dataProvider.getData().then(function(league) {
            $scope.league = league;
        });

    }
]
);

var phonecatControllers = angular.module('leaguecontrollers', []);

phonecatControllers.factory("dataProvider", ['$q', function($q) {
        console.log("Running dataProvider factory");

        var dataLoaded = false;

        return {
            getData: function() {
                if (!dataLoaded) {
                    var result = bowling.initialize({"root": "testdata"}, $q);
                    return result.then(function (league) {
                        console.log("Data loaded marking flag");
                        dataLoaded = true;
                        return league;
                    });
                } else {
                    return $q(function (resolve, reject) {
                       resolve(bowling.currentLeague);
                    });
                }
            }
        }
    }]).controller('LeagueController', ['$scope', '$route', 'dataProvider',
    function ($scope, $route, dataProvider) {
        console.log("Loaded league data");

        dataProvider.getData().then(function(league) {
            $scope.league = league;
        });

    }
]
);

Add getData overrides for multiple views.


#!/usr/bin/env node

var wrench = require('wrench');

var files = 0;
wrench.readdirRecursive(process.argv[2], function (err, curFiles) {
  if (curFiles === null) {
    console.log(files);
  } else {
    if (curFiles) files += curFiles.length;
  }
});

Kill trailing whitespace in benchmark.


/**
 * Created by XaviTorello on 30/05/18
 */
import React from 'react';
import ComposedComponent from './ComposedComponent';
import AutoComplete from 'material-ui/AutoComplete';

class TextSuggest extends React.Component {
    render() {
        // console.log('TextSuggest', this.props.form);

        // assign the source list to autocomplete
        const datasource = this.props.form.schema.enumNames || this.props.form.schema.enum || ['Loading...'];

        // assign the filter, by default case insensitive
        const filter = ((filter) => {
            switch (filter) {
                case 'fuzzy':
                    return AutoComplete.fuzzyFilter;
                    break;
                default:
                    return AutoComplete.caseInsensitiveFilter;
                    break;
            }
        })(this.props.form.filter)

        return (
            <div className={this.props.form.htmlClass}>
                <AutoComplete
                    type={this.props.form.type}
                    floatingLabelText={this.props.form.title}
                    hintText={this.props.form.placeholder}
                    errorText={this.props.error}
                    onChange={this.props.onChangeValidate}
                    defaultValue={this.props.value}
                    disabled={this.props.form.readonly}
                    style={this.props.form.style || {width: '100%'}}
                    dataSource={datasource}
                    filter={filter}
                    maxSearchResults={this.props.form.maxSearchResults || 5}
                />
            </div>
        );
    }
}

export default ComposedComponent(TextSuggest);

/**
 * Created by XaviTorello on 30/05/18
 */
import React from 'react';
import ComposedComponent from './ComposedComponent';
import AutoComplete from 'material-ui/AutoComplete';

const dataSourceConfig = {
  text: 'name',
  value: 'value',
};

class TextSuggest extends React.Component {
    render() {
        // console.log('TextSuggest', this.props.form);

        // assign the source list to autocomplete
        const datasource = this.props.form.schema.enumNames || this.props.form.schema.enum || ['Loading...'];

        // assign the filter, by default case insensitive
        const filter = ((filter) => {
            switch (filter) {
                case 'fuzzy':
                    return AutoComplete.fuzzyFilter;
                    break;
                default:
                    return AutoComplete.caseInsensitiveFilter;
                    break;
            }
        })(this.props.form.filter)

        return (
            <div className={this.props.form.htmlClass}>
                <AutoComplete
                    type={this.props.form.type}
                    floatingLabelText={this.props.form.title}
                    hintText={this.props.form.placeholder}
                    errorText={this.props.error}
                    onChange={this.props.onChangeValidate}
                    defaultValue={this.props.value}
                    disabled={this.props.form.readonly}
                    style={this.props.form.style || {width: '100%'}}
                    dataSource={datasource}
                    filter={filter}
                    maxSearchResults={this.props.form.maxSearchResults || 5}
                />
            </div>
        );
    }
}

export default ComposedComponent(TextSuggest);

Add dataSourceConfig to link passed datasource keys


import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { gql, graphql } from 'react-apollo';

import { getCurrentTimeSuccess } from '../App/actions';

const GetCurrentTime = gql`
  query GetCurrentTime {
    time
  }
`;

@graphql(GetCurrentTime, { options: { pollInterval: 5 * 60 * 1000 } })
@connect(null, (dispatch) => ({ dispatch }))
export default class TimeProvider extends React.PureComponent {

  constructor(props) {
    super(props);
    this.parseProps(props);
  }

  componentWillReceiveProps(nextProps) {
    this.parseProps(nextProps);
  }

  parseProps(props) {
    if (!props.data.loading) {
      this.props.dispatch(getCurrentTimeSuccess(moment(props.data.time)));
    }
  }

  render() {
    return this.props.children ? this.props.children : null;
  }
}

TimeProvider.propTypes = {
  children: PropTypes.node,
  dispatch: PropTypes.func,
};

import React, { PropTypes } from 'react';
import { connect } from 'react-redux';
import moment from 'moment';
import { gql, graphql } from 'react-apollo';

import { getCurrentTimeSuccess } from '../App/actions';

const GetCurrentTime = gql`
  query GetCurrentTime {
    time
  }
`;

@graphql(GetCurrentTime, { options: { pollInterval: 5 * 60 * 1000 } })
@connect(null, (dispatch) => ({ dispatch }))
export default class TimeProvider extends React.PureComponent {

  constructor(props) {
    super(props);
    this.parseProps(props);
  }

  componentWillReceiveProps(nextProps) {
    this.parseProps(nextProps);
  }

  parseProps(props) {
    if (!props.data.loading && !props.data.error) {
      this.props.dispatch(getCurrentTimeSuccess(moment(props.data.time)));
    }
  }

  render() {
    return this.props.children ? this.props.children : null;
  }
}

TimeProvider.propTypes = {
  children: PropTypes.node,
  dispatch: PropTypes.func,
};

Check for GraphQL error in TimeProvider


"use strict";

/* global describe, it */

describe('Riak client', function() {

    var riakClient = require('../lib/riak')();

    it('#getServerInfo', function() {
        return riakClient.getServerInfo()
            .then(function(info) {
                info.should.have.property('node')
                info.should.have.property('server_version')
            })
    })

})

"use strict";

/* global describe, it, before */

describe('Riak client', function() {

    var riakClient = require('../lib/riak')();
    var bucket = 'test-riak-' + Date.now();

    before(function() {
        return riakClient.setBucket({
            bucket: bucket,
            props: {
                allow_mult: true,
                last_write_wins: false,
            }
        })
    })

    it('#getServerInfo', function() {
        return riakClient.getServerInfo()
            .then(function(info) {
                info.should.have.property('node')
                info.should.have.property('server_version')
            })
    })

    it('delete without vclock should not create sibling (allow_mult=true)', function() {
        var vclock;
        return riakClient.put({
            bucket: bucket,
            key: 'testKey',
            content: {
                value: '1234'
            },
            return_head: true
        })
        .then(function(reply) {
            vclock = reply.vclock
            return riakClient.del({
                bucket: bucket,
                key: 'testKey'
            })
        })
        .then(function() {
            return riakClient.get({
                bucket: bucket,
                key: 'testKey',
                deletedvclock: true
            })
        })
        .then(function(reply) {
            reply.should.not.have.property('content')
            reply.vclock.should.not.be.eql(vclock)
        })
    })

    it('delete with stale vclock should create sibling (allow_mult=true)', function() {
        var vclock;
        return riakClient.put({
            bucket: bucket,
            key: 'testKey2',
            content: {
                value: '1234'
            },
            return_head: true
        })
        .then(function(reply) {
            vclock = reply.vclock

            return riakClient.put({
                bucket: bucket,
                key: 'testKey2',
                vclock: vclock,
                content: {
                    value: '123456'
                }
            })
        })
        .then(function() {
            return riakClient.del({
                bucket: bucket,
                key: 'testKey2',
                vclock: vclock
            })
        })
        .then(function() {
            return riakClient.get({
                bucket: bucket,
                key: 'testKey2',
                deletedvclock: true
            })
        })
        .then(function(reply) {
            reply.should.have.property('content').that.is.an('array').and.have.length(2)
        })
    })

})

Test Riak delete object with allow_mult=true


var express = require('express');
var app = express();

// Serve assets in /public
var path = require('path');
app.use(express.static(path.join(__dirname, '../client')));

// Body parsing for JSON POST payloads
var bodyParser = require('body-parser');
app.use(bodyParser.json());

// Middlewares
app.use(require('./middlewares/cross_origin_requests'));
app.use(require('./middlewares/http_verbs'));
app.use(require('./middlewares/add_user_to_request'));

// Mount controller files
app.use('/notes', require('./routes/notes'));
app.use('/users', require('./routes/users'));
app.use('/session', require('./routes/session'));

// Start server
app.set('port', (process.env.PORT || 5000));
app.listen(app.get('port'), function() {
  console.log('Listening on http://localhost:', app.get('port'));
});

var express = require('express');
var app = express();

// Serve assets in /public
var path = require('path');
app.use(express.static(path.join(__dirname, '../client')));

// Body parsing for JSON POST payloads
var bodyParser = require('body-parser');
app.use(bodyParser.json());

// Middlewares
app.use(require('./middlewares/cross_origin_requests'));
app.use(require('./middlewares/http_verbs'));
app.use(require('./middlewares/add_user_to_request'));

// Mount controller files
app.use('/notes', require('./routes/notes'));
app.use('/users', require('./routes/users'));
app.use('/session', require('./routes/session'));

// Start server
app.set('port', (process.env.PORT || 3000));
app.listen(app.get('port'), function() {
  console.log('Listening on http://localhost:', app.get('port'));
});

Use port 3000 instead of 5000.


import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';
import http from 'http';

const app = express();

app.use(logger('dev'));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.set('json spaces', 4);
const port = parseInt(process.env.PORT, 10) || 5000;
app.set('port', port);

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

app.get('*', (req, res) => res.status(200).send({
  message: 'Welcome to the beginning of aawesomeness',
}));

const server = http.createServer(app);
server.listen(port);

module.exports = app;

import express from 'express';
import logger from 'morgan';
import bodyParser from 'body-parser';

const app = express();

app.use(logger('dev'));

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));

app.set('json spaces', 4);
const port = process.env.PORT || 5000;
app.set('port', port);

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

app.get('*', (req, res) => res.status(200).send({
  message: 'Welcome to the beginning of aawesomeness',
}));

app.listen(port);

module.exports = app;

Refactor filre for hosting heroku


import { includePaths, excludePaths } from '../config/utils';

export default options => ({
  test: /\.(mjs|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options,
    },
  ],
  include: includePaths,
  exclude: excludePaths,
});

export const nodeModulesBabelLoader = {
  test: /\.js$/,
  include: /\/node_modules\/safe-eval\//,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        babelrc: false,
        presets: [
          [
            require.resolve('@babel/preset-env'),
            {
              useBuiltIns: 'usage',
              modules: 'commonjs',
            },
          ],
        ],
      },
    },
  ],
};

import { includePaths, excludePaths } from '../config/utils';

export default options => ({
  test: /\.(mjs|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options,
    },
  ],
  include: includePaths,
  exclude: excludePaths,
});

export const nodeModulesBabelLoader = {
  test: /\.js$/,
  include: /\/node_modules\/safe-eval\//,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        babelrc: false,
        presets: [
          [
            'env',
            {
              modules: 'commonjs',
            },
          ],
        ],
      },
    },
  ],
};

Make nodeModulesBabelLoader compatible with Babel 6


/*
 * Evernote-webhooks: A project to use webhooks to automate things in Evernote
 */
var express = require('express');
var config = require('./config.json');

var app = express();
var consumerKey = process.env.consumerKey;
var consumerSecret = process.env.consumerSecret;
var wwwDir = "/www";

app.use('/', express.static(__dirname + wwwDir));
app.get('/:endpoint', function(req, res, next) { console.log(req.params.endpoint); next(); });
app.get('/', function(req, res) { res.render(wwwDir + '/index.html');});

// Start the server on port 3000 or the server port.
var port = process.env.PORT || 3000;
console.log('PORT: ' + port);
var server = app.listen(port);

/*
 * Evernote-webhooks: A project to use webhooks to automate things in Evernote
 */
var express = require('express');

var app = express();
var consumerKey = process.env.consumerKey;
var consumerSecret = process.env.consumerSecret;
var wwwDir = "/www";

app.use('/', express.static(__dirname + wwwDir));
app.get('/:endpoint', function(req, res, next) { console.log(req.params.endpoint); next(); });
app.get('/', function(req, res) { res.render(wwwDir + '/index.html');});

// Start the server on port 3000 or the server port.
var port = process.env.PORT || 3000;
console.log('PORT: ' + port);
var server = app.listen(port);

Remove import of config.json for Heroku to work


'use strict';

angular.module('ngAppInit', []).

provider('$init', function(
){
  this.$get = function() {
    return {};
  };
}).

directive('ngAppInit', function(
  $window,
  $init
){
  return {
    compile: function() {
      return {
        pre: function(scope, element, attrs) {
          angular.extend($init, $window.JSON.parse(attrs.ngAppInit));
        }
      };
    }
  };
});

'use strict';

angular.module('data-init', []).

provider('$init', function() {
  this.$get = function(
    $window
  ){
    return $window.JSON.parse(document.querySelector('[ng-app]').dataset.init);
  };
});

Rewrite the logic without using directive


const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./webpack.config');

const app = new (require('express'))();
const port = 4000;

const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
app.use(webpackHotMiddleware(compiler));

app.use((req, res) => {
  res.sendFile(`${__dirname}/index.html`);
});

app.listen(port, (error) => {
  if (error) {
    console.error(error);
  } else {
    console.info('==> 🌎  Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port);
  }
});

const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
const config = require('./webpack.config');

const app = new (require('express'))();
const port = 4001;

const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: config.output.publicPath }));
app.use(webpackHotMiddleware(compiler));

app.use((req, res) => {
  res.sendFile(`${__dirname}/index.html`);
});

app.listen(port, (error) => {
  if (error) {
    console.error(error);
  } else {
    console.info('==> 🌎  Listening on port %s. Open up http://localhost:%s/ in your browser.', port, port);
  }
});

Change port of Async example


const pgp = require('pg-promise')()

const dbName = 'vinyl'
const connectionString = process.env.DATABASE_URL || `postgres://localhost:5432/${dbName}`
const db = pgp(connectionString)

const getAlbums = () => {
  return db.query('SELECT * FROM albums')
}

const getAlbumById = (albumId) => {
  return db.one(`
    SELECT * FROM albums
      WHERE id = $1
    `, [albumId])
}

const getUserByEmail = (email) => {
  return db.one(`
    SELECT * FROM users WHERE email = $1
    `, [email])
    .catch((error) => {
      console.error('\nError in queries.getUserByEmail\n')
      throw error
    })
}

const createUser = (name, email, password) => {
  return db.none(`
    INSERT INTO
      users (name, email, password)
    VALUES
      ($1, $2, $3)
    `, [name, email, password])
}

module.exports = {
  getAlbums,
  getAlbumById,
  createUser,
  getUserByEmail
}

const pgp = require('pg-promise')()

const dbName = 'vinyl'
const connectionString = process.env.DATABASE_URL || `postgres://localhost:5432/${dbName}`
const db = pgp(connectionString)

const getAlbums = () => {
  return db.query('SELECT * FROM albums')
}

const getAlbumById = (albumId) => {
  return db.one(`
    SELECT * FROM albums
      WHERE id = $1
    `, [albumId])
}

const getUserByEmail = (email) => {
  return db.one(`
    SELECT * FROM users WHERE LOWER(email) = LOWER($1)
    `, [email])
    .catch((error) => {
      console.error('\nError in queries.getUserByEmail\n')
      throw error
    })
}

const createUser = (name, email, password) => {
  return db.none(`
    INSERT INTO
      users (name, email, password)
    VALUES
      ($1, $2, $3)
    `, [name, email, password])
}

module.exports = {
  getAlbums,
  getAlbumById,
  createUser,
  getUserByEmail
}

Update query to make e-mail in sign-in not case sensitive


(function() {
    let height = 1,
        block = '#',
        space = ' ';

    if (height<2) {
        return console.log('Error! Height must be >= 2');
    }

    for (let i = 0; i < height; i++) {
        console.log(space.repeat(height-i) + block.repeat(i+1) + space.repeat(2) + block.repeat(1+i));
    }
})();

(function() {
    let height = 13,
        block = '#',
        space = ' ';

    if (height<2 && height>12) {
        return console.log('Error! Height must be >= 2 and <= 12');
    }

    for (let i = 0; i < height; i++) {
        console.log(space.repeat(height-i) + block.repeat(i+1) + space.repeat(2) + block.repeat(1+i));
    }
})();

Add maximum check for pyramid height


module.exports = function(app) {
    /**
     * @apiGroup buildings
     * @apiName Show list of buildings
     * @apiVersion 3.0.0
     * @api {get} buildings Show list of available buildings
     * @apiSuccess {[]} buildings List of buildings
     * @apiError InternalServerError
     */
    app.get('/api/v3/buildings', function(request, response) {
        app.settings.db.Building.find({},
            { _id: 0, __v: 0, rooms: 0 },
            function(error, buildings) {
                if (error)
                    return response.status(500).send();
                response.json(buildings);
            });
    });

    /**
     * @apiGroup building
     * @apiName Get building information
     * @apiVersion 3.0.0
     * @api {get} buildings Show list of available buildings
     * @apiParam {string} name Building name
     * @apiSuccess {} building data
     * @apiError BuildingNotFound
     */
    app.get('/api/v3/buildings/:name', function(request, response) {
        var name = request.params.name;
        app.settings.db.Building.find(
            { "name" : new RegExp(name, 'i') },
            { _id: 0, __v: 0 },
            function(error, building) {
                if (error || building.length == 0)
                    return response.status(404).send("BuildingNotFound");
                response.json(building[0]);
            });
    });
};

module.exports = function(app) {
    /**
     * @apiGroup buildings
     * @apiName Show list of buildings
     * @apiVersion 3.0.0
     * @api {get} buildings Show list of available buildings
     * @apiSuccess {[]} buildings List of buildings
     * @apiError InternalServerError
     */
    app.get('/api/v3/buildings', function(request, response) {
        app.settings.db.Building.find({},
            { _id: 0, __v: 0, rooms: 0 },
            function(error, buildings) {
                if (error)
                    return response.status(500).send();
                response.json(buildings);
            });
    });

    /**
     * @apiGroup building
     * @apiName Get building information
     * @apiVersion 3.0.0
     * @api {get} buildings Show list of available buildings
     * @apiParam {string} name Building name
     * @apiSuccess {string} name building name
     * @apiError BuildingNotFound
     */
    app.get('/api/v3/buildings/:name', function(request, response) {
        var name = request.params.name;
        app.settings.db.Building.find(
            { "name" : new RegExp(name, 'i') },
            { _id: 0, __v: 0 },
            function(error, building) {
                if (error || building.length == 0)
                    return response.status(404).send("BuildingNotFound");
                response.json(building[0]);
            });
    });
};

Fix apidoc to allow `npm install` to complete


describe('pingPong', function() {
  it("is false for a number that is not divisible by 3 or 5", function() {
    expect(pingPong(7)).to.equal(false);
  });
  it("will run pingPongType if isPingPong is true", function() {
    expect(pingPong(6)).to.equal("ping");
  });
});

describe('pingPongType', function() {
  it("returns ping for a number that is divisible by 3", function() {
    expect(pingPongType(6)).to.equal("ping");
  });
  it("returns pong for a number that is divisible by 5", function() {
    expect(pingPongType(10)).to.equal("pong");
  });
  it("returns pingpong for a number that is divisible by 3 and 5", function() {
    expect(pingPongType(30)).to.equal("pingpong")
  });
});

describe('isPingPong', function() {
  it("returns true for a number divisible by 3, 5, or 15", function() {
    expect(isPingPong(6)).to.equal(true);
  });
  it("returns false for a number not divisible by 3, 5, or 15", function() {
    expect(isPingPong(7)).to.equal(false);
  });
});

describe('pingPongType', function() {
  it("returns ping for a number that is divisible by 3", function() {
    expect(pingPongType(6)).to.equal("ping");
  });
  it("returns pong for a number that is divisible by 5", function() {
    expect(pingPongType(10)).to.equal("pong");
  });
  it("returns pingpong for a number that is divisible by 3 and 5", function() {
    expect(pingPongType(30)).to.equal("pingpong")
  });
});

describe('isPingPong', function() {
  it("returns pingPongType for a number divisible by 3, 5, or 15", function() {
    expect(isPingPong(6)).to.equal("ping");
  });
  it("returns false for a number not divisible by 3, 5, or 15", function() {
    expect(isPingPong(7)).to.equal(false);
  });
});

Remove description for pingPong, leave tests for pingPongType and isPingPong


/*eslint-env node*/

// Import assert function
global.assert = require("assert");

// Code coverage helper
require("blanket")({
    pattern: "src/sinon.js"
});

// 'Simulate' browser environment by creating a window object
global.window = {};

// 'Load' the current sinon file
require("./src/sinon.js");

// Map the sinon object to global in order to make it global
global.sinon = window.sinon;

/*eslint-env node*/

// Import assert function
global.assert = require("assert");

delete global._$jscoverage; // Purge any previous blanket use

// Code coverage helper
require("blanket")({
    pattern: "src/sinon.js"
});

// 'Simulate' browser environment by creating a window object
global.window = {};

// 'Load' the current sinon file
require("./src/sinon.js");

// Map the sinon object to global in order to make it global
global.sinon = window.sinon;

Clean any previous usage of blanket (because re-run in the same process)


app.controller('LoginCtrl', ['$scope', '$log', '$route', 'User',
    function($scope, $log, $route, User) {
        $scope.loginForm = {};
        $scope.errors = {};

        $scope.login = function() {
            $log.debug('Setting all the form fields to $dirty...');

            angular.forEach($scope.form, function(ctrl, field) {
                // Dirty hack because $scope.form contains so much more than just the fields
                if (typeof ctrl === 'object' && ctrl.hasOwnProperty('$modelValue')) {
                    ctrl.$dirty = true;
                    ctrl.$pristine = false;
                }
            });

            if ($scope.form.$invalid) {
                $log.debug('Form is invalid. Not sending request to server.')
                return;
            }

            $log.debug('Attempting to log user in...');
            User.login($scope.loginForm.email, $scope.loginForm.password).then(function(data) {
                $route.reload();
            }).catch(function(data) {
                $log.debug('Unable to log user in... %o', data);

                $scope.errors = {}

                angular.forEach(data.errors, function(error, field) {
                    $scope.form[field].$setValidity('server', false);
                    $scope.errors[field] = error;
                });
            });
        };
    }
]);

app.controller('LoginCtrl', ['$scope', '$log', '$route', 'User',
    function($scope, $log, $route, User) {
        $scope.loginForm = {};
        $scope.errors = {};

        $scope.login = function() {
            $log.debug('Setting all the form fields to $dirty...');

            angular.forEach($scope.form, function(ctrl, field) {
                // Dirty hack because $scope.form contains so much more than just the fields
                if (typeof ctrl === 'object' && ctrl.hasOwnProperty('$modelValue')) {
                    ctrl.$dirty = true;
                    ctrl.$pristine = false;
                }
            });

            if ($scope.form.$invalid) {
                $log.debug('Form is invalid. Not sending request to server.')
                return;
            }

            $scope.form.submitted = true;

            $log.debug('Attempting to log user in...');
            User.login($scope.loginForm.email, $scope.loginForm.password).then(function(data) {
                $route.reload();
            }).catch(function(data) {
                $log.debug('Unable to log user in... %o', data);

                $scope.errors = {}

                angular.forEach(data.errors, function(error, field) {
                    $scope.form[field].$setValidity('server', false);
                    $scope.errors[field] = error;
                });
            });
        };
    }
]);

Add a submitted value to the form


/**
 * GCMKey provider
 *
 * @description :: Server-side logic for managing users
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

module.exports = {
key: function key(req, res) {
  sails.log("Google Project Number: " + sails.config.push.gcm.projectNumber);
  res.json(sails.config.push.gcm.projectNumber);
}
};

/**
 * GCMKey provider
 *
 * @description :: Server-side logic for managing users
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

module.exports = {
key: function key(req, res) {
  sails.log("Google Project Number: " + sails.config.gcm.projectNumber);
  res.json(sails.config.gcm.projectNumber);
}
};

Use correct sails.config for GCM key


var qb;
function launch() {
  if ( ! qb ) qb = QBug.create();
  qb.launchBrowser();
//  qb.launchBrowser('chromium');
}

if ( chrome.app.runtime ) {
  ajsonp = (function() {
    var factory = OAuthXhrFactory.create({
      authAgent: ChromeAuthAgent.create({}),
      responseType: "json"
    });

    return function(url, params, opt_method) {
      return function(ret) {
        var xhr = factory.make();
        return xhr.asend(ret, opt_method ? opt_method : "GET", url + (params ? '?' + params.join('&') : ''));
      };
    };
  })();

  chrome.app.runtime.onLaunched.addListener(function(opt_launchData) {
    // launchData is provided by the url_handler
    if ( opt_launchData ) console.log(opt_launchData.url);

    console.log('launched');
    launch();
  });
}

var qb;
function launch() {
  if ( ! qb ) qb = QBug.create();
  qb.launchBrowser();
//  qb.launchBrowser('chromium');
}

if ( chrome.app.runtime ) {
  ajsonp = (function() {
    var factory = OAuthXhrFactory.create({
      authAgent: ChromeAuthAgent.create({}),
      responseType: "json"
    });

    return function(url, params, opt_method, opt_payload) {
      return function(ret) {
        var xhr = factory.make();
        xhr.responseType = "json";
        return xhr.asend(ret,
                         opt_method ? opt_method : "GET",
                         url + (params ? '?' + params.join('&') : ''),
                         opt_payload);
      };
    };
  })();

  chrome.app.runtime.onLaunched.addListener(function(opt_launchData) {
    // launchData is provided by the url_handler
    if ( opt_launchData ) console.log(opt_launchData.url);

    console.log('launched');
    launch();
  });
}

Add optional payload to ajsonp


module.exports = function (grunt) {

	grunt.initConfig({

		meta: {
			banner: '// ' + grunt.file.read('src/loStorage.js').split("\n")[0]
		},

		min: {
			dist: {
				src: ['<banner>', 'src/loStorage.js'],
				dest: 'src/loStorage.min.js'
			}
		},

		jasmine: {
			all: ['spec/index.html']
		},

		watch: {
			test: {
				files: ['src/loStorage.js', 'spec/*'],
				tasks: 'test'
			}
		}

	});

	grunt.loadNpmTasks('grunt-jasmine-task');

	grunt.registerTask('test', 'jasmine');
	grunt.registerTask('release', 'test min');
	grunt.registerTask('default', 'release');

};

module.exports = function (grunt) {

	grunt.initConfig({

		meta: {
			banner: '// ' + grunt.file.read('src/loStorage.js').split("\n")[0]
		},

		min: {
			dist: {
				src: ['<banner>', 'src/loStorage.js'],
				dest: 'src/loStorage.min.js'
			}
		},

		jasmine: {
			all: ['spec/index.html']
		},

		watch: {
			test: {
				files: ['src/loStorage.js', 'spec/*'],
				tasks: 'test'
			},

			min: {
				files: ['src/loStorage.js'],
				tasks: 'min'
			}
		}

	});

	grunt.loadNpmTasks('grunt-jasmine-task');

	grunt.registerTask('test', 'jasmine');
	grunt.registerTask('release', 'test min');
	grunt.registerTask('default', 'release');

};

Add min task to watch