module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		less: {
			options: {
				ieCompat: true,
				strictImports: false,
				syncImport: false,
				report: 'min'
			},
			css: {
				options: {
					compress: false,
					yuicompress: false
				},
				files: {
					'css/calendar.css': 'less/calendar.less',
				}
			},
			css_min: {
				options: {
					compress: true,
					yuicompress: true
				},
				files: {
					'css/calendar.min.css': 'css/calendar.css'
				}
			}
		},
		uglify: {
			options: {
				banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\nhttps://github.com/Serhioromano/bootstrap-calendar.git\n'
			},
			build: {
				src: 'js/calendar.js',
				dest: 'js/calendar.min.js'
			}
		}
	});

	// Load the plugin that provides the tasks.
	grunt.loadNpmTasks('grunt-contrib-less');
	grunt.loadNpmTasks('grunt-contrib-uglify');

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

};

module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		pkg: grunt.file.readJSON('package.json'),
		less: {
			options: {
				ieCompat: true,
				strictImports: false,
				syncImport: false,
				report: 'min'
			},
			css: {
				options: {
					compress: false,
					yuicompress: false
				},
				files: {
					'css/calendar.css': 'less/calendar.less',
				}
			},
			css_min: {
				options: {
					compress: true,
					yuicompress: true
				},
				files: {
					'css/calendar.min.css': 'css/calendar.css'
				}
			}
		},
		uglify: {
			options: {
				banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
					'<%= grunt.template.today("yyyy-mm-dd") %> \n' +
					'https://github.com/Serhioromano/bootstrap-calendar */\n'
			},
			build: {
				src: 'js/calendar.js',
				dest: 'js/calendar.min.js'
			}
		}
	});

	// Load the plugin that provides the tasks.
	grunt.loadNpmTasks('grunt-contrib-less');
	grunt.loadNpmTasks('grunt-contrib-uglify');

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

};

Add version to head of minified version


//= require govuk/multivariate-test

/*jslint browser: true,
 *  indent: 2,
 *  white: true
 */
/*global $, GOVUK */
$(function () {

  GOVUK.taxDiscBetaPrimary = function () {
    $('.primary-apply').html($('#beta-primary').html());
    $('.secondary-apply').html($('#dvla-secondary').html());
  };

  if(window.location.href.indexOf("/tax-disc") > -1) {
    new GOVUK.MultivariateTest({
      name: 'tax-disc',
      customVarIndex: 20,
      cohorts: {
        tax_disc_beta_control1: { callback: function () { } },
        tax_disc_beta1: { callback: GOVUK.taxDiscBetaPrimary }
      }
    });
  }
});

//= require govuk/multivariate-test

/*jslint browser: true,
 *  indent: 2,
 *  white: true
 */
/*global $, GOVUK */
$(function () {

  GOVUK.taxDiscBetaPrimary = function () {
    $('.primary-apply').html($('#beta-primary').html());
    $('.secondary-apply').html($('#dvla-secondary').html());
  };

  if(window.location.href.indexOf("/tax-disc") > -1) {
    new GOVUK.MultivariateTest({
      name: 'tax-disc-50-50',
      customVarIndex: 20,
      cohorts: {
        tax_disc_beta_control: { callback: function () { } },
        tax_disc_beta: { callback: GOVUK.taxDiscBetaPrimary }
      }
    });
  }
});

Rename tax disc test and cohorts


ManageIQ.angular.app.service('DialogEditorHttp', ['$http', 'API', function($http, API) {
  this.loadDialog = function(id) {
    return API.get('/api/service_dialogs/' + id + '?attributes=content,buttons,label');
  };

  this.saveDialog = function(id, action, data) {
    return API.post('/api/service_dialogs' + id, {
      action: action,
      resource: data,
    }, {
      skipErrors: [400],
    });
  };

  this.treeSelectorLoadData = function(fqdn) {
    var url = '/tree/automate_entrypoint' + (fqdn ? '?fqdn=' + encodeURIComponent(fqdn) : '');
    return $http.get(url).then(function(response) {
      return response.data;
    });
  };

  this.treeSelectorLazyLoadData = function(node) {
    return $http.get('/tree/automate_entrypoint?id=' + encodeURIComponent(node.key)).then(function(response) {
      return response.data;
    });
  };

  // Load categories data from API.
  this.loadCategories = function() {
    return API.get('/api/categories' +
                        '?expand=resources' +
                        '&attributes=id,name,description,single_value,children');
  };
}]);

ManageIQ.angular.app.service('DialogEditorHttp', ['$http', 'API', function($http, API) {
  this.loadDialog = function(id) {
    return API.get('/api/service_dialogs/' + id + '?attributes=content,buttons,label');
  };

  this.saveDialog = function(id, action, data) {
    return API.post('/api/service_dialogs' + id, {
      action: action,
      resource: data,
    }, {
      skipErrors: [400],
    });
  };

  this.treeSelectorLoadData = function(fqname) {
    var url = '/tree/automate_entrypoint' + (fqname ? '?fqname=' + encodeURIComponent(fqname) : '');
    return $http.get(url).then(function(response) {
      return response.data;
    });
  };

  this.treeSelectorLazyLoadData = function(node) {
    return $http.get('/tree/automate_entrypoint?id=' + encodeURIComponent(node.key)).then(function(response) {
      return response.data;
    });
  };

  // Load categories data from API.
  this.loadCategories = function() {
    return API.get('/api/categories' +
                        '?expand=resources' +
                        '&attributes=id,name,description,single_value,children');
  };
}]);

Rename fqdn to fqname in DialogEditorHttpService


module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('bower.json'),
    jshint: {
      grunt: {
        src: ['Gruntfile.js']
      },
      main: {
        src: ['tock.js'],
        options: {
          'browser': true,
          'camelcase': true,
          'curly': true,
          'eqeqeq': true,
          'indent': 2,
          'newcap': true,
          'quotmark': 'single',
          'unused': true
        }
      },
    },
    uglify: {
      options: {
        banner: '// Tock.js (version <%= pkg.version %>) <%= pkg.homepage %>\n// License: <%= pkg.license %>\n'
      },
      main: {
        src: '<%= jshint.main.src %>',
        dest: 'tock.min.js'
      }
    },
    watch: {
      main: {
        files: '<%= jshint.main.src %>',
        tasks: ['jshint:main', 'uglify:main']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['jshint', 'uglify']);
};

module.exports = function(grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('bower.json'),
    jshint: {
      grunt: {
        src: ['Gruntfile.js']
      },
      main: {
        src: ['tock.js'],
        options: {
          'browser': true,
          'camelcase': true,
          'curly': true,
          'devel': true,
          'eqeqeq': true,
          'newcap': true,
          'quotmark': 'single',
          'undef': true,
          'unused': true
        }
      },
    },
    uglify: {
      options: {
        banner: '// Tock.js (version <%= pkg.version %>) <%= pkg.homepage %>\n// License: <%= pkg.license %>\n'
      },
      main: {
        src: '<%= jshint.main.src %>',
        dest: 'tock.min.js'
      }
    },
    watch: {
      main: {
        files: '<%= jshint.main.src %>',
        tasks: ['jshint:main', 'uglify:main']
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['jshint', 'uglify']);
};

Add missing "devel" and "undef". Remove "indent" since it was moved to jscs.


require('./intro-anim.sass');

const isTouchDevice = 'ontouchstart' in document.documentElement;
const ev = isTouchDevice ? 'touchend' : 'click';
const delay = isTouchDevice ? 1050 : 550;

document.getElementById('corners').addEventListener(ev, () => setTimeout(() => {
  console.log('Animation finished');
}, delay));

require('./intro-anim.sass');

const isTouchDevice = 'ontouchstart' in document.documentElement;
const ev = isTouchDevice ? 'touchend' : 'click';
const delay = isTouchDevice ? 1050 : 550;

document.getElementById('corners').addEventListener(ev, () => setTimeout(() => {
  alert('You\'re in!');
}, delay));

Implement user-visible alert after interaction


'use strict'

module.exports = {
  up: function (queryInterface, Sequelize) {
    queryInterface.addColumn(
      'Rescues',
      'type',
      {
        type: Sequelize.ENUM('success', 'failure', 'invalid', 'other'),
        allowNull: false,
        defaultValue: 'other'
      }
    )

    queryInterface.addColumn(
      'Rescues',
      'status',
      {
        type: Sequelize.ENUM('open', 'inactive', 'closed'),
        allowNull: false,
        defaultValue: 'other'
      }
    )
  },

  down: function (queryInterface) {
    queryInterface.removeColumn('Rescues', 'type')
    queryInterface.removeColumn('Rescues', 'status')
  }
}

'use strict'

module.exports = {
  up: function (queryInterface, Sequelize) {
    queryInterface.addColumn(
      'Rescues',
      'type',
      {
        type: Sequelize.ENUM('success', 'failure', 'invalid', 'other'),
        allowNull: false,
        defaultValue: 'other'
      }
    )

    queryInterface.addColumn(
      'Rescues',
      'status',
      {
        type: Sequelize.ENUM('open', 'inactive', 'closed'),
        allowNull: false,
        defaultValue: 'open'
      }
    )
  },

  down: function (queryInterface) {
    queryInterface.removeColumn('Rescues', 'type')
    queryInterface.removeColumn('Rescues', 'status')
  }
}

Use correct default value for status enum in migration


var Pixelator = function(data, partner) {
  this.data = data;
  this.partner = partner;
};

Pixelator.prototype = {
  defaults: function() {
    var default_context = this.data.context || {};
    default_context.timestamp = new Date().getTime();
    return default_context;
  },
  picker: function(key, options) {
    var self = this;
    _.each(this.data.pixels[key], function(pixel) {

      if (pixel.partner && self.partner !== pixel.partner) {
        return;
      }

      var gp = new GenericPixel({ context: options, pixel: pixel });
      gp.insert();
    });
  },
  run: function(key, options) {
    options = _(options || {}).extend(this.defaults());
    this.picker(key, options);
  }
}

var Pixelator = function(data, partner) {
  this.data = data;
  this.partner = partner;
};

Pixelator.prototype = {
  defaults: function() {
    var default_context = this.data.context || {};
    default_context.timestamp = new Date().getTime();
    return default_context;
  },
  picker: function(key, options) {
    var self = this;
    var keys = self.data.pixels[key];

    if (!keys) { return; }

    _.each(keys, function(pixel) {
      if (pixel.partner && self.partner !== pixel.partner) {
        return;
      }

      var gp = new GenericPixel({ context: options, pixel: pixel });
      gp.insert();
    });
  },
  run: function(key, options) {
    options = _(options || {}).extend(this.defaults());
    this.picker(key, options);
  }
}

Return out of Pixelator.picker if no keys are provided


'use strict'

const path = require('path')
const {spawn} = require('child_process')

const CONFIG = require('../config')

module.exports = async function () {
  return new Promise((resolve, reject) => {
    const eslint = spawn(
      path.join('script', 'node_modules', '.bin', 'eslint'),
      ['--cache', '--format', 'json', '.'],
      { cwd: CONFIG.repositoryRootPath }
    )

    let output = ''
    let errorOutput = ''
    eslint.stdout.on('data', data => {
      output += data.toString()
    })

    eslint.stderr.on('data', data => {
      errorOutput += data.toString()
    })

    eslint.on('error', error => reject(error))
    eslint.on('close', exitCode => {
      const errors = []
      let files

      try {
        files = JSON.parse(output)
      } catch (_) {
        reject(errorOutput)
        return
      }

      for (const file of files) {
        for (const error of file.messages) {
          errors.push({
            path: file.filePath,
            message: error.message,
            lineNumber: error.line,
            rule: error.ruleId
          })
        }
      }

      resolve(errors)
    })
  })
}

'use strict'

const path = require('path')
const {spawn} = require('child_process')
const process = require('process')

const CONFIG = require('../config')

module.exports = async function () {
  return new Promise((resolve, reject) => {
    const eslintArgs = ['--cache', '--format', 'json']

    if (process.argv.includes('--fix')) {
      eslintArgs.push('--fix')
    }

    const eslint = spawn(
      path.join('script', 'node_modules', '.bin', 'eslint'),
      [...eslintArgs, '.'],
      { cwd: CONFIG.repositoryRootPath }
    )

    let output = ''
    let errorOutput = ''
    eslint.stdout.on('data', data => {
      output += data.toString()
    })

    eslint.stderr.on('data', data => {
      errorOutput += data.toString()
    })

    eslint.on('error', error => reject(error))
    eslint.on('close', exitCode => {
      const errors = []
      let files

      try {
        files = JSON.parse(output)
      } catch (_) {
        reject(errorOutput)
        return
      }

      for (const file of files) {
        for (const error of file.messages) {
          errors.push({
            path: file.filePath,
            message: error.message,
            lineNumber: error.line,
            rule: error.ruleId
          })
        }
      }

      resolve(errors)
    })
  })
}

Add script/lint --fix which fixes some code formatting issues via eslint


"use strict";

if (process.env.NO_UPDATE) {
  process.exit(0);
}

const path = require("path");
const fs = require("fs");
const request = require("request");

// Pin to specific version, reflecting the spec version in the readme.
// At the moment we are pinned to a branch.
//
// To get the latest commit:
// 1. Go to https://github.com/w3c/web-platform-tests/tree/master/url
// 2. Press "y" on your keyboard to get a permalink
// 3. Copy the commit hash
const commitHash = "d93247d5cb7d70f80da8b154a171f4e3d50969f4";

const sourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/urltestdata.json`;
const setterSourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/setters_tests.json`;

const targetDir = path.resolve(__dirname, "..", "test", "web-platform-tests");

request.get(sourceURL)
  .pipe(fs.createWriteStream(path.resolve(targetDir, "urltestdata.json")));

request.get(setterSourceURL)
  .pipe(fs.createWriteStream(path.resolve(targetDir, "setters_tests.json")));

"use strict";

if (process.env.NO_UPDATE) {
  process.exit(0);
}

const path = require("path");
const fs = require("fs");
const request = require("request");

// Pin to specific version, reflecting the spec version in the readme.
// At the moment we are pinned to a branch.
//
// To get the latest commit:
// 1. Go to https://github.com/w3c/web-platform-tests/tree/master/url
// 2. Press "y" on your keyboard to get a permalink
// 3. Copy the commit hash
const commitHash = "1e1e80441b8d6a60f836de4005dba25698ecfe4a";

const sourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/urltestdata.json`;
const setterSourceURL = `https://raw.githubusercontent.com/w3c/web-platform-tests/${commitHash}/url/setters_tests.json`;

const targetDir = path.resolve(__dirname, "..", "test", "web-platform-tests");

request.get(sourceURL)
  .pipe(fs.createWriteStream(path.resolve(targetDir, "urltestdata.json")));

request.get(setterSourceURL)
  .pipe(fs.createWriteStream(path.resolve(targetDir, "setters_tests.json")));

Update to the latest web platform tests


require('coffee-script/register');
require('babel-register');
require('source-map-support').install({ handleUncaughtExceptions: false, hookRequire: true });

Fix stack traces for errors happening inside coffee-script tests.


import React, { useRef } from 'react';

export default {
  title: 'Core/Rendering',
};

// NOTE: in our example apps each component is mounted twice as we render in strict mode
let timesMounted = 0;
export const Counter = () => {
  const countRef = useRef();

  if (!countRef.current) timesMounted += 1;
  countRef.current = (countRef.current || 0) + 1;

  return (
    <div>
      Mounted: {timesMounted}, rendered (this mount): {countRef.current}
    </div>
  );
};

import React, { useEffect, useRef } from 'react';
import { useArgs } from '@storybook/client-api';

export default {
  title: 'Core/Rendering',
};

// NOTE: in our example apps each component is mounted twice as we render in strict mode
let timesCounterMounted = 0;
export const Counter = () => {
  const countRef = useRef();

  if (!countRef.current) timesCounterMounted += 1;
  countRef.current = (countRef.current || 0) + 1;

  return (

      Mounted: {timesCounterMounted}, rendered (this mount): {countRef.current}

  );
};

// An example to test what happens when the story is remounted due to argChanges
let timesArgsChangeMounted = 0;
export const ArgsChange = () => {
  const countRef = useRef();

  if (!countRef.current) timesArgsChangeMounted += 1;
  countRef.current = true;

  return (

      Mounted: {timesArgsChangeMounted} (NOTE: we use strict mode so this number is 2x what you'd
      expect -- it should be 2, not 4 though!)

  );
};

ArgsChange.args = {
  first: 0,
};

ArgsChange.decorators = [
  (StoryFn) => {
    const [args, updateArgs] = useArgs();

    useEffect(() => {
      if (args.first === 0) {
        updateArgs({ first: 1 });
      }
    }, []);

    return <StoryFn />;
  },
];

Add an example to highlight if a story renders too many times


'use strict';

var generators = require('yeoman-generator'),
  _ = require('lodash');

module.exports = generators.Base.extend({

  constructor: function () {
    generators.Base.apply(this, arguments);

    this.argument('appname', { type: String, required: true });

    // And you can then access it later on this way; e.g. CamelCased
    this.viewName = _.startCase(this.appname);
    this.appname = _.camelCase(this.appname);
    this.kebabName = _.kebabCase(this.appname);
  },

  writing: function () {
    this.copy('_bs-config.js', 'bs-config.js');
    this.copy('_eslintrc', '.eslintrc');
    // this.copy('_gulpfile.js', 'gulpfile.js');
    this.copy('_package.json', 'package.json');
    this.copy('_webpack.config.js', 'webpack.config.js');
    this.copy('_karma.conf.js', 'karma.conf.js');
    this.copy('gitignore', '.gitignore');

    this.copy('src/_index.html', 'src/index.html');
    // this.copy('src/_index.html', 'build/index.html');
    this.copy('src/_app.js', 'src/app.js');
    this.directory('src/common', 'src/common');
    this.directory('src/assets', 'src/assets');
    this.directory('src/home', 'src/home');
  },

  install: function() {
    this.installDependencies({
      bower: false,
      npm: true
    });
  }
});

'use strict';

var generators = require('yeoman-generator'),
  _ = require('lodash');

module.exports = generators.Base.extend({

  constructor: function () {
    generators.Base.apply(this, arguments);

    this.argument('appname', { type: String, required: true });

    this.viewName = _.startCase(this.appname);
    this.appname = _.camelCase(this.appname);
    this.kebabName = _.kebabCase(this.appname);
  },

  writing: function () {
    this.copy('_bs-config.js', 'bs-config.js');
    this.copy('_eslintrc', '.eslintrc');
    this.copy('_package.json', 'package.json');
    this.copy('_webpack.config.js', 'webpack.config.js');
    this.copy('_karma.conf.js', 'karma.conf.js');
    this.copy('gitignore', '.gitignore');
    this.copy('_README.md', 'README.md');
    this.directory('src', 'src');
  },

  install: function() {
    this.installDependencies({
      bower: false,
      npm: true
    });
  }
});

Copy entire src directory not file by file


function getDocuments(path, email, key, projectId) {
  const token = getAuthToken_(email, key);

  const baseUrl = "https://firestore.googleapis.com/v1beta1/projects/" + projectId + "/databases/(default)/documents/" + path;
  const options = {
   'muteHttpExceptions' : true,
   'headers': {'content-type': 'application/json', 'Authorization': 'Bearer ' + token}
  };

  return getObjectFromResponse(UrlFetchApp.fetch(baseUrl, options));
}

function get(path, email, key, projectId) {
  const token = getAuthToken_(email, key);

  const baseUrl = "https://firestore.googleapis.com/v1beta1/projects/" + projectId + "/databases/(default)/documents/" + path;
  const options = {
   'muteHttpExceptions' : true,
   'headers': {'content-type': 'application/json', 'Authorization': 'Bearer ' + token}
  };

  return getObjectFromResponse(UrlFetchApp.fetch(baseUrl, options));
}

Update getDocuments function to be a general GET function


Meteor.loginWithGoogle = function (options, callback) {
  // support both (options, callback) and (callback).
  if (!callback && typeof options === 'function') {
    callback = options;
    options = {};
  }

  var config = Accounts.loginServiceConfiguration.findOne({service: 'google'});
  if (!config) {
    callback && callback(new Accounts.ConfigError("Service not configured"));
    return;
  }

  var state = Random.id();

  // always need this to get user id from google.
  var requiredScope = ['https://www.googleapis.com/auth/userinfo.profile'];
  var scope = ['https://www.googleapis.com/auth/userinfo.email'];
  if (options && options.requestPermissions)
    scope = options.requestPermissions;
  scope = _.union(scope, requiredScope);
  var flatScope = _.map(scope, encodeURIComponent).join('+');

  // https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl
  var accessType = options.requestOfflineToken ? 'offline' : 'online';

  var loginUrl =
        'https://accounts.google.com/o/oauth2/auth' +
        '?response_type=code' +
        '&client_id=' + config.clientId +
        '&scope=' + flatScope +
        '&redirect_uri=' + Meteor.absoluteUrl('_oauth/google?close') +
        '&state=' + state +
        '&access_type=' + accessType;

  Accounts.oauth.initiateLogin(state, loginUrl, callback);
};

Meteor.loginWithGoogle = function (options, callback) {
  // support both (options, callback) and (callback).
  if (!callback && typeof options === 'function') {
    callback = options;
    options = {};
  } else if (!options) {
    options = {};
  }

  var config = Accounts.loginServiceConfiguration.findOne({service: 'google'});
  if (!config) {
    callback && callback(new Accounts.ConfigError("Service not configured"));
    return;
  }

  var state = Random.id();

  // always need this to get user id from google.
  var requiredScope = ['https://www.googleapis.com/auth/userinfo.profile'];
  var scope = ['https://www.googleapis.com/auth/userinfo.email'];
  if (options.requestPermissions)
    scope = options.requestPermissions;
  scope = _.union(scope, requiredScope);
  var flatScope = _.map(scope, encodeURIComponent).join('+');

  // https://developers.google.com/accounts/docs/OAuth2WebServer#formingtheurl
  var accessType = options.requestOfflineToken ? 'offline' : 'online';

  var loginUrl =
        'https://accounts.google.com/o/oauth2/auth' +
        '?response_type=code' +
        '&client_id=' + config.clientId +
        '&scope=' + flatScope +
        '&redirect_uri=' + Meteor.absoluteUrl('_oauth/google?close') +
        '&state=' + state +
        '&access_type=' + accessType;

  Accounts.oauth.initiateLogin(state, loginUrl, callback);
};

Fix error on Meteor.loginWithGoogle() with no args


function BaseError(data){
    var oldLimit = Error.stackTraceLimit,
        error;

    Error.stackTraceLimit = 20;

    error = Error.apply(this, arguments);

    Error.stackTraceLimit = oldLimit;

    if(Error.captureStackTrace){
        Error.captureStackTrace(this, BaseError);
    }

    this.__genericError = true;

    if(typeof data === 'string'){
        this.message = data;
    } else {
        for(var key in data){
            this[key] = data[key];
        }

        if(!this.message && data && data.message){
            this.message = data.message;
        }
    }

    if(!this.message){
        this.message = this.toString();
    }
}
BaseError.prototype = Object.create(Error.prototype);
BaseError.prototype.constructor = BaseError;
BaseError.prototype.toString = function(){
    return this.message || this.code + ': ' + this.constructor.name;
};
BaseError.prototype.valueOf = function(){
    return this;
};
BaseError.prototype.toJSON = function() {
    var result = {};

    for(var key in this)
    {
        if(typeof this[key] !== 'function')
            result[key] = this[key];
    }

    return result;
};
BaseError.prototype.code = 500;
BaseError.isGenericError = function(obj){
    return obj instanceof BaseError || (obj != null && obj.__genericError);
};

module.exports = BaseError;

var captureStackTrace = require('capture-stack-trace');

function BaseError(data){
    var oldLimit = Error.stackTraceLimit,
        error;

    Error.stackTraceLimit = 20;

    error = Error.apply(this, arguments);

    Error.stackTraceLimit = oldLimit;

    captureStackTrace(this, BaseError);

    this.__genericError = true;

    if(typeof data === 'string'){
        this.message = data;
    } else {
        for(var key in data){
            this[key] = data[key];
        }

        if(!this.message && data && data.message){
            this.message = data.message;
        }
    }

    if(!this.message){
        this.message = this.toString();
    }
}
BaseError.prototype = Object.create(Error.prototype);
BaseError.prototype.constructor = BaseError;
BaseError.prototype.toString = function(){
    return this.message || this.code + ': ' + this.constructor.name;
};
BaseError.prototype.valueOf = function(){
    return this;
};
BaseError.prototype.toJSON = function() {
    var result = {};

    for(var key in this)
    {
        if(typeof this[key] !== 'function')
            result[key] = this[key];
    }

    return result;
};
BaseError.prototype.code = 500;
BaseError.isGenericError = function(obj){
    return obj instanceof BaseError || (obj != null && obj.__genericError);
};

module.exports = BaseError;

Use ponyfil for base error


var ntf = require('ntf')
  , test = ntf.http('http://ntfjs.org')

exports.ntf = test.get('/', function(test) {
  test.statusCode(200)
  test.body('ntf')
  test.done()
})

var ntf = require('ntf')
  , test = ntf.http('http://ntfjs.org')

exports.frontpage = test.get('/', function(test) {
  test.statusCode(200)
  test.body('ntf')
  test.done()
})

exports.fail = test.get('/fail', function(test) {
  test.statusCode(200)
  test.done()
})

Add failing test to example


'use strict';

// @ngInject
var ParameterSearchController = function($scope, $location, $controller, npdcAppConfig, Parameter) {
  // Extend NpolarApiBaseController
  $controller("NpolarBaseController", {
    $scope: $scope
  });
  $scope.resource = Parameter;

  npdcAppConfig.cardTitle = 'Environmental monitoring parameters';

  let query = function() {
    let defaults = {
      start: 0,
      limit: 50,
      "size-facet": 5,
      format: "json",
      variant: "atom",
      facets: "systems,collection,species,themes,dataseries,label,warn,variable,unit,locations.placename,links.rel"
    };
    return Object.assign({}, defaults, $location.search());
  };

  let detail = function(p) {
    let subtitle = '';
    if (p.timeseries && p.timeseries.length > 0) {
      subtitle = `Timeseries: ${p.timeseries.length}`;
    }
    //subtitle += `. Updates: ${ $filter('date')(t.updated)}`;
    return subtitle;
  };
  npdcAppConfig.search.local.results.subtitle = function(p) { return p.species || ''; };
  npdcAppConfig.search.local.results.detail = detail;

  $scope.search(query());

  $scope.$on('$locationChangeSuccess', (event, data) => {
    $scope.search(query());
  });

};

module.exports = ParameterSearchController;

'use strict';

// @ngInject
var ParameterSearchController = function($scope, $location, $controller, npdcAppConfig, Parameter) {
  // Extend NpolarApiBaseController
  $controller("NpolarBaseController", {
    $scope: $scope
  });
  $scope.resource = Parameter;

  npdcAppConfig.cardTitle = 'Environmental monitoring parameters';

  let query = function() {
    let defaults = {
      start: 0,
      limit: 50,
      "size-facet": 5,
      format: "json",
      variant: "atom",
      sort: "-updated",
      facets: "systems,collection,species,themes,dataseries,label,warn,variable,unit,locations.placename,links.rel"
    };
    return Object.assign({}, defaults, $location.search());
  };

  let detail = function(p) {
    let subtitle = '';
    if (p.timeseries && p.timeseries.length > 0) {
      subtitle = `Timeseries: ${p.timeseries.length}`;
    }
    //subtitle += `. Updates: ${ $filter('date')(t.updated)}`;
    return subtitle;
  };
  npdcAppConfig.search.local.results.subtitle = function(p) { return p.species || ''; };
  npdcAppConfig.search.local.results.detail = detail;

  $scope.search(query());

  $scope.$on('$locationChangeSuccess', (event, data) => {
    $scope.search(query());
  });

};

module.exports = ParameterSearchController;

Sort on last updated first


/**
 * Run the first test with "focus" tag.
 *
 * @param {Object} hydro
 * @api public
 */

module.exports = function(hydro) {
  if (!hydro.get('focus')) return;
  var focus = false;
  hydro.on('pre:test', function(test) {
    if (focus) return test.skip();
    if (test.meta.indexOf('focus') != -1) focus = true;
  });
};

/**
 * CLI flags.
 */

module.exports.flags = {
  '--focus': 'run the first test with "focus" tag'
};

/**
 * Run the first test with "focus" tag.
 *
 * @param {Object} hydro
 * @api public
 */

module.exports = function(hydro) {
  if (!hydro.get('focus')) return;
  var focus = false;
  hydro.on('pre:test', function(test) {
    if (focus || test.meta.indexOf('focus') == -1) return test.skip();
    focus = true;
  });
};

/**
 * CLI flags.
 */

module.exports.flags = {
  '--focus': 'run the first test with "focus" tag'
};

Fix bug where it will run more tests than desired


'use strict';

const naked = require('naked-string');

module.exports = function equalsish(stringOne, stringTwo) {
	if (stringOne === undefined) {
		throw new Error('No arguments provided.');
	} else if (stringTwo === undefined) {
		return (futureString) => equalsish(stringOne, futureString);
	} else {
		return naked(stringOne) === naked(stringTwo);
	}
};

'use strict';

const naked = require('naked-string');

module.exports = function equalsish(stringOne, stringTwo) {
	if (stringOne === undefined) {
		throw new Error('No arguments provided.');
	} else if (stringTwo === undefined) {
		return futureString => equalsish(stringOne, futureString);
	} else {
		return naked(stringOne) === naked(stringTwo);
	}
};

Remove parentheses from around arrow function arg


var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var nano = require('nano')('http://localhost:5984');
var todo = nano.db.use('todo');

var app = express();

app.use(cors());
app.use(bodyParser.json());

app.get('/', function(req, res, next) {
  console.log('get triggered');
  res.json([]);
});

app.post('/', function(req, res, next) {
  console.log('post triggered');
  var task = {title: req.body.title};
  todo.insert(task, function(err, body) {
    if (err) {
      console.log(err);
    }
    console.log(JSON.stringify(body));
    task._id = body.id;
    task._rev = body.rev;
    res.json(task);
  });
});

app.delete('/', function(req, res, next) {
  console.log('delete triggered');
  res.json([]);
});

app.listen(3000, function() {
  console.log('Cors enabled server listening on port 3000');
});

var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var nano = require('nano')('http://localhost:5984');
var todo = nano.db.use('todo');

var app = express();

app.use(cors());
app.use(bodyParser.json());

app.get('/', function(req, res, next) {
  console.log('get triggered');
  todo.view('todos', 'all_todos', function(err, body) {
    res.json(body.rows);
  });
});

app.post('/', function(req, res, next) {
  console.log('post triggered');
  var task = {title: req.body.title};
  todo.insert(task, function(err, body) {
    if (err) {
      console.log(err);
    }
    console.log(JSON.stringify(body));
    task._id = body.id;
    task._rev = body.rev;
    res.json(task);
  });
});

app.delete('/', function(req, res, next) {
  console.log('delete triggered');
  res.json([]);
});

app.listen(3000, function() {
  console.log('Cors enabled server listening on port 3000');
});

Return database results in root GET (3/16).


import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

import Home from './Home';
// import Counter from './Counter'

const Counter = resolve => require.ensure([], () => resolve(require('./Counter').default), 'counter');
const GeographicalIp = resolve => require.ensure([], () => resolve(require('./GeographicalIp').default));

const routes = [
  {
    name: 'home',
    path: '/',
    component: Home,
    meta: {
      title: 'Home'
    }
  },
  {
    name: 'counter',
    path: '/counter',
    component: Counter,
    meta: {
      title: 'Counter'
    }
  },
  {
    name: 'geographicalIp',
    path: '/geographical-ip',
    component: GeographicalIp,
    meta: {
      title: 'Geographical Ip'
    }
  }
]

const router = new VueRouter({
  routes,
  mode: 'history'
})

export default router

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

import Home from './Home';
// import Counter from './Counter'

const Counter = resolve => require.ensure([], () => resolve(require('./Counter').default), 'counter');
const GeographicalIp = resolve => require.ensure([], () => resolve(require('./GeographicalIp').default));

const routes = [
  {
    name: 'home',
    path: '/',
    component: Home,
    meta: {
      title: 'Home'
    }
  },
  {
    name: 'counter',
    path: '/counter',
    component: Counter,
    meta: {
      title: 'Counter'
    }
  },
  {
    name: 'geographicalIp',
    path: '/geographical-ip',
    component: GeographicalIp,
    meta: {
      title: 'Geographical Ip'
    }
  }
]

const router = new VueRouter({
  routes,
  mode: 'history'
})

router.afterEach(to => {
  if (to.meta.title !== undefined) {
    document.title = `${ to.meta.title } - Vue-vuex-starter-kit`
  }
})

export default router

Add title for every router


import React from 'react'

const GroupRolesView = () => (
  <div/>
)

export default GroupRolesView

import React from 'react'
import {connect} from 'react-redux'
import {compose, withHandlers, withProps, withState} from 'recompose'
import {addMemberToRole, addRoleToGroup} from '../actions/groups'

const mapStateToProps = ({groups}) => ({
  groups
})

const enhance = compose(
  connect(mapStateToProps),
  withProps(({match}) => ({
    groupId: match.params.groupId
  })),
  withState('newRole', 'updateNewRole', {roleName: ''}),
  withHandlers({
    onNewRoleNameChange: props => event => {
      props.updateNewRole({
        ...props.newRole,
        roleName: event.target.value,
      })
    },
    onNewRoleSubmit: props => event => {
      event.preventDefault()
      props.dispatch(addRoleToGroup({
        groupId: props.groupId,
        roleName: props.newRoleName,
      }))
    }
  }),
)

const GroupRolesView = ({
                          groups,
                          groupId,
                          onNewRoleNameChange,
                          onNewRoleSubmit,
                          newRole,
                        }) => (
  <div>
    <form onSubmit={onNewRoleSubmit}>
      <textarea
        placeholder='New Role Name'
        value={newRole.roleName}
        onChange={onNewRoleNameChange}
      />
      <input
        type='submit'
        value='submit'
      />
    </form>
  </div>
)

export default enhance(GroupRolesView)

Add form for role view


module.exports = {
    preset: "ts-jest",
    testEnvironment: "node",
    moduleNameMapper: {
        "^(admin|site|charts|utils|db|settings)/(.*)$": "<rootDir>/$1/$2",
        "^settings$": "<rootDir>/settings",
        "^serverSettings$": "<rootDir>/serverSettings"
    },
    setupFilesAfterEnv: ['<rootDir>/test/enzymeSetup.ts']
}

module.exports = {
    preset: "ts-jest",
    testEnvironment: "jsdom",
    moduleNameMapper: {
        "^(admin|site|charts|utils|db|settings)/(.*)$": "<rootDir>/$1/$2",
        "^settings$": "<rootDir>/settings",
        "^serverSettings$": "<rootDir>/serverSettings"
    },
    setupFilesAfterEnv: ['<rootDir>/test/enzymeSetup.ts']
}

Switch jest environment to `jsdom`


/* eslint-env node */
'use strict';

const fastbootTransform = require('fastboot-transform');

const filesToImport = [
  'dependencyLibs/inputmask.dependencyLib.js',
  'inputmask.js',
  'inputmask.extensions.js',
  'inputmask.date.extensions.js',
  'inputmask.numeric.extensions.js',
  'inputmask.phone.extensions.js'
];

module.exports = {
  name: 'ember-inputmask',
  options: {
    nodeAssets: {
      inputmask: () => ({
        vendor: filesToImport.map(file => `dist/inputmask/${file}`),
        processTree: input => fastbootTransform(input)
      })
    }
  },
  included() {
    this._super.included.apply(this, arguments);
    filesToImport.forEach(file => {
      this.import(`vendor/inputmask/dist/inputmask/${file}`);
    });
  }
};

/* eslint-env node */
'use strict';

const fastbootTransform = require('fastboot-transform');

const filesToImport = [
  'dependencyLibs/inputmask.dependencyLib.js',
  'inputmask.js',
  'inputmask.extensions.js',
  'inputmask.date.extensions.js',
  'inputmask.numeric.extensions.js',
  'inputmask.phone.extensions.js'
];

module.exports = {
  name: 'ember-inputmask',
  options: {
    nodeAssets: {
      inputmask: () => ({
        vendor: {
          include: filesToImport.map(file => `dist/inputmask/${file}`),
          processTree: input => fastbootTransform(input)
        }
      })
    }
  },
  included() {
    this._super.included.apply(this, arguments);
    filesToImport.forEach(file => {
      this.import(`vendor/inputmask/dist/inputmask/${file}`);
    });
  }
};

Make fastboot transform actually work


//
// types.js - type predicators
//

BiwaScheme.isNil = function(obj){
  return (obj === BiwaScheme.nil);
};

BiwaScheme.isUndef = function(obj){
  return (obj === BiwaScheme.undef);
};

BiwaScheme.isChar = function(obj){
  return (obj instanceof BiwaScheme.Char);
};

BiwaScheme.isSymbol = function(obj){
  return (obj instanceof BiwaScheme.Symbol);
};

BiwaScheme.isPort = function(obj){
  return (obj instanceof BiwaScheme.Port);
};

// Note: '() is not a pair in scheme
BiwaScheme.isPair = function(obj){
  return (obj instanceof BiwaScheme.Pair) && (obj !== BiwaScheme.nil);
};

// Note: isList returns true for '()
BiwaScheme.isList = function(obj){
  return (obj instanceof BiwaScheme.Pair);
  // should check it is proper and not cyclic..
};

BiwaScheme.isVector = function(obj){
  return (obj instanceof Array) && (obj.closure_p !== true);
};

BiwaScheme.isHashtable = function(obj){
  return (obj instanceof BiwaScheme.Hashtable);
};

BiwaScheme.isMutableHashtable = function(obj){
  return (obj instanceof BiwaScheme.Hashtable) && obj.mutable;
};

BiwaScheme.isClosure = function(obj){
  return (obj instanceof Array) && (obj.closure_p === true);
};

//
// types.js - type predicators
//

BiwaScheme.isNil = function(obj){
  return (obj === BiwaScheme.nil);
};

BiwaScheme.isUndef = function(obj){
  return (obj === BiwaScheme.undef);
};

BiwaScheme.isChar = function(obj){
  return (obj instanceof BiwaScheme.Char);
};

BiwaScheme.isSymbol = function(obj){
  return (obj instanceof BiwaScheme.Symbol);
};

BiwaScheme.isPort = function(obj){
  return (obj instanceof BiwaScheme.Port);
};

// Note: '() is not a pair in scheme
BiwaScheme.isPair = function(obj){
  return (obj instanceof BiwaScheme.Pair) && (obj !== BiwaScheme.nil);
};

// Note: isList returns true for '()
BiwaScheme.isList = function(obj){
    if(obj === BiwaScheme.nil) return true; // null base case
    if(!(obj instanceof BiwaScheme.Pair)) return false;
    return BiwaScheme.isList(obj.cdr);
  //TODO: should check if it is not cyclic..
};

BiwaScheme.isVector = function(obj){
  return (obj instanceof Array) && (obj.closure_p !== true);
};

BiwaScheme.isHashtable = function(obj){
  return (obj instanceof BiwaScheme.Hashtable);
};

BiwaScheme.isMutableHashtable = function(obj){
  return (obj instanceof BiwaScheme.Hashtable) && obj.mutable;
};

BiwaScheme.isClosure = function(obj){
  return (obj instanceof Array) && (obj.closure_p === true);
};

Fix isList to check recursively.


'use babel'

import {transform} from 'babel-core'
import Path from 'path'

export const compiler = true
export const minifier = false
export function process(contents, {rootDirectory, filePath, config}) {
  const beginning = contents.substr(0, 11)
  if (beginning !== '"use babel"' && beginning !== "'use babel'") {
    return null
  }

  const fileName = Path.dirname(filePath)
  const relativePath = Path.relative(rootDirectory, filePath)
  const transpiled = transform(contents, Object.assign({}, config.babel, {
    filename: fileName,
    filenameRelative: relativePath,
    sourceRoot: rootDirectory,
    sourceMaps: true,
    highlightCode: false
  }))
  return {
    contents: transpiled.code,
    sourceMap: transpiled.map
  }
}

'use babel'

import {transform} from 'babel-core'
import Path from 'path'

export const compiler = true
export const minifier = false
export function process(contents, {rootDirectory, filePath, config}) {
  const fileName = Path.dirname(filePath)
  const relativePath = Path.relative(rootDirectory, filePath)
  const transpiled = transform(contents, Object.assign({}, config.babel, {
    filename: fileName,
    filenameRelative: relativePath,
    sourceRoot: rootDirectory,
    sourceMaps: true,
    highlightCode: false
  }))
  return {
    contents: transpiled.code,
    sourceMap: transpiled.map
  }
}

Remove beginning check for 'use babel'


#!/usr/bin/env node

'use strict';

var program = require('commander')
  , gulp    = require('gulp')
  , chalk   = require('chalk')
  , exec    = require('exec')
  , pjson   = require('./package.json')

var strings = {
  create: 'Creating new project',
  install: 'Installing dependencies',
  complete: 'Done!'
}

var paths = {
  basefiles: __dirname + '/assets/**/*',
  dotfiles: __dirname + '/assets/.*'
}

function notify(message) {
  if (!program.quiet)
    console.log(chalk.green(message))
}

function installDependencies(name) {
  notify(strings.install)

  exec('cd ' + name + ' && npm install', function () {
    notify(strings.complete)
  })
}

function newProject(name) {
  notify(strings.create)

  gulp.src([paths.basefiles, paths.dotfiles])
    .pipe(gulp.dest(process.cwd() + '/' + name))
    .on('end', installDependencies.bind(this, name))
}

program
  .version(pjson.version)
  .option('-q, --quiet', 'Hide logging information')

program
  .command('new <name>')
  .description('Scaffold out a new app with given name')
  .action(newProject)

program.parse(process.argv);

#!/usr/bin/env node

'use strict';

var program = require('commander')
  , gulp    = require('gulp')
  , chalk   = require('chalk')
  , exec    = require('exec')
  , pjson   = require('./package.json')

var strings = {
  create: 'Creating new project',
  install: 'Installing dependencies',
  complete: 'Done!'
}

var paths = {
  basefiles: __dirname + '/assets/**/*',
  dotfiles: __dirname + '/assets/.*',
  gitignore: __dirname + '/assets/.gitignore'
}

function notify(message) {
  if (!program.quiet)
    console.log(chalk.green(message))
}

function installDependencies(name) {
  notify(strings.install)

  exec('cd ' + name + ' && npm install', function () {
    notify(strings.complete)
  })
}

function newProject(name) {
  notify(strings.create)

  gulp.src([paths.basefiles, paths.dotfiles, paths.gitignore])
    .pipe(gulp.dest(process.cwd() + '/' + name))
    .on('end', installDependencies.bind(this, name))
}

program
  .version(pjson.version)
  .option('-q, --quiet', 'Hide logging information')

program
  .command('new <name>')
  .description('Scaffold out a new app with given name')
  .action(newProject)

program.parse(process.argv);

Fix bug where .gitignore was not being generated


'use strict';
const seneca = require('seneca')()
const senecaContet = require('seneca-context')

seneca.add({role:'api', cmd:'post'}, (args, done) => {
  seneca.make('blog/posts').save$(args.post, done)
})

seneca.act({role:'web', use:{
  prefix: '/api/',
  pin: {role:'api', cmd:'*'},
  map: {
    'post': {GET: true}
  }
}})

const app = require('express')()
const bodyparser = require('body-parser')
app.use(bodyparser.json())
app.use(bodyparser.urlencoded({ extended: true }))
app.use(seneca.export('web'))
app.listen(8020)

'use strict'
const seneca = require('seneca')()
const senecaContext = require('seneca-context')

seneca.use(require('seneca-context/plugins/setContext'), {createContext: (req, res, context, done) => {
  const tenant = req.hostname.match(/([^\.]+)/)[1]
  setImmediate(() => done(null, {tenant}))
}})

seneca.add({role:'api', cmd:'post'}, function (args, done) {
  const si = this
  console.log('Context is', senecaContext.getContext(si).tenant)
  si.make('blog/posts').save$(args.post, done)
})

seneca.act({role:'web', use:{
  prefix: '/api/',
  pin: {role:'api', cmd:'*'},
  map: {
    'post': {GET: true}
  }
}})

const app = require('express')()
const bodyparser = require('body-parser')
app.use(bodyparser.json())
app.use(bodyparser.urlencoded({ extended: true }))
app.use(seneca.export('web'))
app.listen(8020)

Add tenant context based on subdomain


const React = require('react');
var { NativeModules, Platform } = require('react-native');

if (Platform.OS === 'android') {
  module.exports = {
    get(dim) {
      try {
        if(!NativeModules.ExtraDimensions) {
          throw "ExtraDimensions not defined. Try rebuilding your project. e.g. react-native run-android";
        }
        const result = NativeModules.ExtraDimensions[dim];

        if(typeof result !== 'number') {
            return result;
        }
        return result;
      } catch (e) {
        console.error(e);
      }
    }
  };
} else {
  module.exports = {
    get(dim) {
      console.warn('react-native-extra-dimensions-android is only available on Android');
      return 0;
    }
  };
}

const React = require('react');
var { NativeModules, Platform } = require('react-native');

if (Platform.OS === 'android') {
  module.exports = {
    get(dim) {
      try {
        if(!NativeModules.ExtraDimensions) {
          throw "ExtraDimensions not defined. Try rebuilding your project. e.g. react-native run-android";
        }
        const result = NativeModules.ExtraDimensions[dim];

        if(typeof result !== 'number') {
            return result;
        }
        return result;
      } catch (e) {
        console.error(e);
      }
    },
    getRealWidthHeight() {
      return this.get('REAL_WINDOW_HEIGHT');
    },
    getRealWindowWidth() {
      return this.get('REAL_WIDTH_WIDTH');
    },
    getStatusBarHeight() {
      return this.get('STATUS_BAR_HEIGHT');
    },
    getSoftMenuBarHeight() {
      return this.get('SOFT_MENU_BAR_HEIGHT');
    },
    getSmartBarHeight() {
      return this.get('SMART_BAR_HEIGHT');
    },
    isSoftMenuBarEnabled() {
      return this.get('SOFT_MENU_BAR_ENABLED');
    }
  };
} else {
  module.exports = {
    get(dim) {
      console.warn('react-native-extra-dimensions-android is only available on Android');
      return 0;
    }
  };
}

Make constants accessible through funcs


"use strict";
global.use = function (path) {
    if(path === 'config'){
        return require.main.require('./' + path);
    }else{
        return require('./' + path);
    }
};

const Server                    = use('core/server');
const Message                   = use('core/messages');

Message.request.addInterceptor(function requestInterceptorLogConsole(){
    console.log('-> Request interceptor to: ' + this.request.path);
});

Message.response.addInterceptor(function responseInterceptorLogConsole(body){
    console.log('<- Response interceptor from: ' + this.request.path);
    return body;
});

Message.response.addInterceptor(function responseInterceptorAddServerNameHeader(body){
    this.response.headers['Server'] = 'Dominion';
    return body;
});

module.exports = new Server();

global.use = function (path) {
    if (path === "config") {
        return require.main.require("./" + path);
    } else {
        return require("./" + path);
    }
};

const Config                    = use("config");
const Server                    = use("core/server");
const Message                   = use("core/messages");

if (Config.env.development) {
    Message.request.addInterceptor(function requestInterceptorLogConsole() {
        console.log("-> Request interceptor to: " + this.request.path);
    });

    Message.response.addInterceptor(function responseInterceptorLogConsole(body) {
        console.log("<- Response interceptor from: " + this.request.path);
        return body;
    });
}

Message.response.addInterceptor(function responseInterceptorAddServerNameHeader(body) {
    this.response.headers["Server"] = "Dominion";
    return body;
});

module.exports = new Server();

Add console interceptors only in dev env


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

var path = require('path');

module.exports = {
  name: 'ember-cli-octicons',
  blueprintsPath: function() {
    return path.join(__dirname, 'blueprints');
  }
};

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

module.exports = {
  name: 'ember-cli-octicons',

  included: function(app) {
    this._super.included(app);

    app.import(app.bowerDirectory + '/octicons/octicons/octicons.css');
    app.import(app.bowerDirectory + '/octicons/octicons/octicons.eot', { destDir: 'assets' });
    app.import(app.bowerDirectory + '/octicons/octicons/octicons.woff', { destDir: 'assets' });
    app.import(app.bowerDirectory + '/octicons/octicons/octicons.ttf', { destDir: 'assets' });
    app.import(app.bowerDirectory + '/octicons/octicons/octicons.svg', { destDir: 'assets' });
  }
};

Add app.import statements for octicons css and font files


import React from 'react'
import PropTypes from 'prop-types'

const EditableTableHeader = ({columnNames}) => {

  return(

      {columnNames.map( columnName => {return
columnName
})}

  )

}

export default EditableTableHeader

import React from 'react'
import PropTypes from 'prop-types'

const EditableTableHeader = ({columnNames}) => {

  return(

      {columnNames.map( columnName => {return
columnName
})}

  )

}

EditableTableHeader.propTypes = {
  columnNames: PropTypes.arrayOf(PropTypes.string).isRequired
}

export default EditableTableHeader

Add propTypes check to editableTableHeader


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

module.exports = {
  name: 'ember-devtools',
  isEnabled: function() {
    var addonConfig = this.app.project.config(this.app.env)['ember-devtools'];
    return addonConfig.enabled;
  }
};

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

module.exports = {
  name: 'ember-devtools',
  isEnabled: function() {
    var options = (this.app && this.app.options && this.app.options['ember-devtools']) || {}
    return options.enabled;
  }
};

Update loading of options hash to be compatible with modern ember-cli


var fs = require('fs');

module.exports = function requireAll(options) {
  if (typeof options === 'string') {
    options = {
      dirname: options,
      filter: /(.+)\.js(on)?$/,
      excludeDirs: /^\.(git|svn)$/,
      params: params
    };
  }

  var files = fs.readdirSync(options.dirname);
  var modules = {};
  var resolve = options.resolve || identity;
  var map = options.map || identity;
  var mapSubDirectoryNames = typeof options.mapSubDirectoryNames === "undefined" ?
      true : options.mapSubDirectoryNames

  function excludeDirectory(dirname) {
    return options.excludeDirs && dirname.match(options.excludeDirs);
  }

  files.forEach(function (file) {
    var filepath = options.dirname + '/' + file;
    if (fs.statSync(filepath).isDirectory()) {

      if (excludeDirectory(file)) return;

      if (mapSubDirectoryNames){
        file = map(file, filepath);
      }

      modules[file] = requireAll({
        dirname: filepath,
        filter: options.filter,
        excludeDirs: options.excludeDirs,
        resolve: resolve,
        map: map
      });

    } else {
      var match = file.match(options.filter);
      if (!match) return;

	  if(!options.params) {
	      modules[match[1]] = resolve(require(filepath));
	  } else {
		  modules[match[1]] = resolve(require(filepath))(params);
	  }
    }
  });

  return modules;
};

function identity(val) {
  return val;
}

var fs = require('fs');

module.exports = function requireAll(options) {
  if (typeof options === 'string') {
    options = {
      dirname: options,
      filter: /(.+)\.js(on)?$/,
      excludeDirs: /^\.(git|svn)$/,
      params: params
    };
  }

  var files = fs.readdirSync(options.dirname);
  var modules = {};
  var resolve = options.resolve || identity;
  var map = options.map || identity;
  var mapSubDirectoryNames = typeof options.mapSubDirectoryNames === "undefined" ?
      true : options.mapSubDirectoryNames

  function excludeDirectory(dirname) {
    return options.excludeDirs && dirname.match(options.excludeDirs);
  }

  files.forEach(function (file) {
    var filepath = options.dirname + '/' + file;
    if (fs.statSync(filepath).isDirectory()) {

      if (excludeDirectory(file)) return;

      if (mapSubDirectoryNames){
        file = map(file, filepath, false);
      }

      modules[file] = requireAll({
        dirname: filepath,
        filter: options.filter,
        excludeDirs: options.excludeDirs,
        resolve: resolve,
        map: map
      });

    } else {
      var match = file.match(options.filter);
      if (!match) return;

	  if(!options.params) {
	      modules[map(match[1], filepath, true)] = resolve(require(filepath));
	  } else {
	      modules[map(match[1], filepath, true)] = resolve(require(filepath))(params);
	  }
    }
  });

  return modules;
};

function identity(val) {
  return val;
}

Fix merge conflict & add 3rd paramater for map function; false for directory, true for file


var restify = require('restify');
var messenger = require('./lib/messenger');

var server = restify.createServer();

server.use(restify.queryParser());
server.use(restify.bodyParser());
server.use(restify.authorizationParser());

server.get('/', function (req, res, next) {
  res.send(200, {status: 'ok'});
});

server.post('/messages', function (req, res, next) {
  var phoneNumber = req.params.From;
  messenger.send(phoneNumber, 'Got it.');
  res.send(200, {status: 'ok'});
});

server.listen(process.env.PORT || '3000', function() {
  console.log('%s listening at %s', server.name, server.url);
});

var restify = require('restify');
var messenger = require('./lib/messenger');

var server = restify.createServer();

var users = {};

server.use(restify.queryParser());
server.use(restify.bodyParser());
server.use(restify.authorizationParser());

server.get('/', function (req, res, next) {
  res.send(200, {status: 'ok'});
});

server.post('/messages', function (req, res, next) {
  var phoneNumber = req.params.From;

  if users[phoneNumber] {
    messenger.send(phoneNumber, 'Hello, old friend.');
  } else {
    messenger.send(phoneNumber, 'Nice to meet you.');
    users[phoneNumber] = req.params;
  }

  res.send(200, {status: 'ok'});
});

server.listen(process.env.PORT || '3000', function() {
  console.log('%s listening at %s', server.name, server.url);
});

Store phone numbers in memory and respond differently


var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');

module.exports = function(fn) {

  inherits(fn, EventEmitter);

  var self = new fn();

  fn.prototype.addEventListener = function(ev, cb) {
    self.on(ev,cb);
    //console.log('addEventListener',ev,cb);
  };

  global.postMessage = // unfortunately global for worker (no namespaces?)
  fn.prototype.postMessage = function(msg) {
    self.emit('message', {data:msg});
    //console.log('postMessage',msg);
  };

  return self;
};

var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');

module.exports = function(fn) {

  inherits(fn, EventEmitter);

  var self = new fn();

  self.addEventListener = function(ev, cb) {
    self.on(ev,cb);
  };

  global.postMessage = // unfortunately global for worker (no namespaces?)
  self.postMessage = function(msg) {
    self.emit('message', {data:msg});
  };

  return self;
};

Augment instance instead of prototype


"use strict";

module.exports.Receiver = require( './lib/receiver' );

module.exports.transports = {
	receivers: {
		Express: require( './lib/transport.receiver.express' ),
		Local:   require( './lib/transport.receiver.local' )
	},
	senders:   {
		Http: require( './lib/transport.sender.http' )
	}
};

// convenience method for creating a receiver.
module.exports.createReceiver = function( params ) {

	params = params || {};
	var transConfig = params.transports;

	var receiver = new this.Receiver( {
		baseDir: params.baseDir
	} );

	for ( var name in transConfig ) {
		if ( transConfig.hasOwnProperty( name ) && this.transports.receivers.hasOwnProperty( name ) ) {
			receiver.addTransport( new this.transports.receivers[ name ]( transConfig[ name ] ) );
		}
	}

	return receiver;
};

"use strict";

module.exports.Receiver = require( './lib/receiver' );

module.exports.transports = {
	receivers: {
		Express: require( './lib/transport.receiver.express' ),
		Local:   require( './lib/transport.receiver.local' )
	},
	senders:   {
		Http: require( './lib/transport.sender.http' )
	}
};

// convenience method for creating a receiver.
module.exports.createReceiver = function( params ) {

	params = params || {};
	var transConfig = params.transports;

	var receiver = new this.Receiver( {
		authorize: params.authorize,
		baseDir: params.baseDir
	} );

	for ( var name in transConfig ) {
		if ( transConfig.hasOwnProperty( name ) && this.transports.receivers.hasOwnProperty( name ) ) {
			receiver.addTransport( new this.transports.receivers[ name ]( transConfig[ name ] ) );
		}
	}

	return receiver;
};

Add authorize to createReceiver() convenience method


'use strict';

var
	platform = require('enyo/platform'),
	dispatcher = require('enyo/dispatcher'),
	gesture = require('enyo/gesture');

exports = module.exports = require('./src/options');
exports.version = '2.6.0-pre.17';

// Override the default holdpulse config to account for greater delays between keydown and keyup
// events in Moonstone with certain input devices.
gesture.drag.configureHoldPulse({
	events: [{name: 'hold', time: 400}],
	endHold: 'onLeave'
});

/**
* Registers key mappings for webOS-specific device keys related to media control.
*
* @private
*/
if (platform.webos >= 4) {
	// Table of default keyCode mappings for webOS device
	dispatcher.registerKeyMap({
		415 : 'play',
		413 : 'stop',
		19  : 'pause',
		412 : 'rewind',
		417 : 'fastforward',
		461 : 'back'
	});
}

// ensure that these are registered
require('./src/resolution');
require('./src/fonts');

'use strict';

var
	platform = require('enyo/platform'),
	dispatcher = require('enyo/dispatcher'),
	gesture = require('enyo/gesture');

exports = module.exports = require('./src/options');
exports.version = '2.6.0-pre.17.1';

// Override the default holdpulse config to account for greater delays between keydown and keyup
// events in Moonstone with certain input devices.
gesture.drag.configureHoldPulse({
	events: [{name: 'hold', time: 400}],
	endHold: 'onLeave'
});

/**
* Registers key mappings for webOS-specific device keys related to media control.
*
* @private
*/
if (platform.webos >= 4) {
	// Table of default keyCode mappings for webOS device
	dispatcher.registerKeyMap({
		415 : 'play',
		413 : 'stop',
		19  : 'pause',
		412 : 'rewind',
		417 : 'fastforward',
		461 : 'back'
	});
}

// ensure that these are registered
require('./src/resolution');
require('./src/fonts');

Update version string to 2.6.0-pre.17.1


var browserify = require('browserify');
var watchify = require('watchify');
var koars = require('koars-utils')({module: 'assets', asset:'js'});

module.exports = function(src, dest, excludes) {
	//Setup our cache, timestamp and watchify instance
	var cache, time = new Date();
	var w = watchify(browserify(src, watchify.args));

	//Exclude all specified modules
	if(excludes) excludes.forEach(w.exclude.bind(w));

	//Run the initial bundle and listen for updates
	cache = bundle();
	if(koars.dev()) w.on('update', function() {
		cache = bundle();
	});

	//Exclude handlebars, if needed, so we use the handlebars instance which has our helpers attached
	//Then bundle the files, update the timestamp and log our success/failure
	function bundle() {
		return new Promise(function(resolve, reject) {
			w.bundle(function(err, bundle) {
				if(!err) {
					time = new Date();
					koars.log.debug('Rebuilt js bundle');
					resolve(bundle);
				} else {
					koars.log.warn(err, 'Failed to build js bundle');
					reject(err);
				}
			});
		});
	}

	//Return a middleware generator function to serve our cached bundle upon request
	return function *(next) {
		this.body = yield cache;
		this.lastModified = time;
		this.type = 'text/javascript';
	};
};

var browserify = require('browserify');
var watchify = require('watchify');
var koars = require('koars-utils')({module: 'assets', asset:'js'});
var path = require('path');

module.exports = function(src, excludes) {
	//Setup our cache, timestamp and watchify instance
	var cache, time = new Date();
	var w = watchify(browserify(path.join(process.cwd(), src), watchify.args));

	//Exclude all specified modules
	if(excludes) excludes.forEach(w.exclude.bind(w));

	//Run the initial bundle and listen for updates
	cache = bundle();
	if(koars.dev()) w.on('update', function() {
		cache = bundle();
	});

	//Exclude handlebars, if needed, so we use the handlebars instance which has our helpers attached
	//Then bundle the files, update the timestamp and log our success/failure
	function bundle() {
		return new Promise(function(resolve, reject) {
			w.bundle(function(err, bundle) {
				if(!err) {
					time = new Date();
					koars.log.debug('Rebuilt js bundle');
					resolve(bundle);
				} else {
					koars.log.warn(err, 'Failed to build js bundle');
					reject(err);
				}
			});
		});
	}

	//Return a middleware generator function to serve our cached bundle upon request
	return function *(next) {
		this.body = yield cache;
		this.lastModified = time;
		this.type = 'text/javascript';
	};
};

Remove destination parameter and watch correct path


var detect = require('rtc-tools/detect');
var isTestling = typeof __testlingConsole != 'undefined';

// if we are running in testling then run the media tests
if (isTestling) {
  require('./media');

  if (! detect.moz) {
    // require('./media-reactive');
  }
}

require('./profile');
require('./datachannel');
// require('./heartbeat-disconnect');
require('./custom-id');
require('./request-stream');
require('./reconnect');
require('./events');

if (! detect.moz) {
  require('./reactive');
  require('./reactive-stream-events');
}

var detect = require('rtc-tools/detect');
var isTestling = typeof __testlingConsole != 'undefined';

// if we are running in testling then run the media tests
if (isTestling) {
  require('./media');

  if (! detect.moz) {
    // require('./media-reactive');
  }
}

require('./profile');
require('./datachannel');
// require('./heartbeat-disconnect');
require('./custom-id');
require('./request-stream');
require('./events');

// we need some firefox issues resolved before all tests can be run
if (! detect.moz) {
  // https://bugzilla.mozilla.org/show_bug.cgi?id=852665
  require('./reconnect');

  // https://bugzilla.mozilla.org/show_bug.cgi?id=857115
  require('./reactive');
  require('./reactive-stream-events');
}

Remove the reconnection tests from the firefox testsuite


[
    'lib/jquery/jquery.min.js',
    'lib/angular/angular.js',
    'lib/underscore/underscore-min.js',
    'lib/umbraco/Extensions.js',
    'js/app.js',
    'js/umbraco.resources.js',
    'js/umbraco.services.js',
    'js/umbraco.interceptors.js',
    'ServerVariables',
    'lib/signalr/jquery.signalR.js',
    'BackOffice/signalr/hubs',
    'js/umbraco.preview.js'
]

[
    'lib/jquery/jquery.min.js',
    'lib/angular/angular.js',
    'lib/underscore/underscore-min.js',
    'lib/umbraco/Extensions.js',
    'js/app.js',
    'js/umbraco.resources.js',
    'js/umbraco.services.js',
    'js/umbraco.interceptors.js',
    'ServerVariables',
    'lib/signalr/signalr.min.js',
    'js/umbraco.preview.js'
]

Include new SignalR in preview view


import { addCallback } from 'meteor/vulcan:core';
import { Subscriptions } from './collection'

async function deleteOldSubscriptions(subscription) {
  const { userId, documentId, collectionName, type } = subscription
  Subscriptions.update({userId, documentId, collectionName, type}, {$set: {deleted: true}}, {multi: true})
}

addCallback("subscription.create.async", deleteOldSubscriptions);

import { addCallback } from 'meteor/vulcan:core';
import { Subscriptions } from './collection'

async function deleteOldSubscriptions(subscription) {
  const { userId, documentId, collectionName, type } = subscription
  Subscriptions.update({userId, documentId, collectionName, type}, {$set: {deleted: true}}, {multi: true})
  return subscription;
}

addCallback("subscription.create.before", deleteOldSubscriptions);

Fix run-order issue where callback that was supposed to delete old sub, deleted new sub too


#!/usr/bin/env node

/**
 * This file creates a `tsconfig.json` if it doesn't already exist.
 * tsconfig is the recommended method for configuring TypeScript.
 */

/* global require process */
const exec = require('child_process').exec
const path = require('path')
const fs = require('fs')

const cwd = process.cwd().replace (/\\/g, '/')
const suffix = '/node_modules/preact-cli-plugin-typescript'
const root = cwd.endsWith(suffix) ? cwd.substr(0, cwd.length - suffix.length) : cwd

if (fs.access(path.join(root, 'tsconfig.json'), fs.constants.F_OK, () => {})) {
  console.warn('Detected an existing tsconfig - make sure you have the correct settings.')
}
else {
  // TODO: Proper node way of copying/writing files. exec with strings is nasty.

  exec(`cp ${path.join('src', 'tsconfig.json')} ${root}`, {cwd: root}, (error) => {
    if (error) {
        console.error(`An error occurred while creating tsconfig: ${error}`)
        return
    }
  })
}

#!/usr/bin/env node

/**
 * This file creates a `tsconfig.json` if it doesn't already exist.
 * tsconfig is the recommended method for configuring TypeScript.
 */

/* global require process */
const exec = require('child_process').exec
const path = require('path')
const fs = require('fs')

const cwd = process.cwd().replace (/\\/g, '/')
const suffix = '/node_modules/preact-cli-plugin-typescript'
const root = cwd.endsWith(suffix) ? cwd.substr(0, cwd.length - suffix.length) : cwd

if (fs.access(path.join(root, 'tsconfig.json'), fs.constants.F_OK, () => {})) {
  // TODO: If file exists, get existing config and merge correct values.
  console.warn('Detected an existing tsconfig - make sure you have the correct settings.')
}
else {
  try {
    fs.createReadStream(path.join('src', 'tsconfig.json'))
      .pipe(fs.createWriteStream(path.join(root, 'tsconfig.json')));
  }
  catch (e) {
    console.error('An error occurred while creating the tsconfig', e);
  }
}

Move from exec to fs


module.exports= {
	views: [{
		"name": "Raw Match Data",
		"view": "matches"
	}],

	matches: function (mongoCollection, callback) {
		mongoCollection.find().toArray(function (err, matches) {
			callback([
				{
						name: "Matches",
						headers: [
							{
								text: "Team",
								value: "team"
							},
							{
								text: "Comments",
								value: "comments"
							},
							{
								text: "Device",
								value: "sender"
							}
						],
						data: matches
				}
			]);

			db.close();
		});
	}
};

module.exports= {
	views: [{
		"name": "Raw Match Data",
		"view": "matches"
	}],

	matches: function (mongoCollection, callback) {
		mongoCollection
			.find()
			.sort({"_id": -1})
			.toArray(function (err, matches) {
				callback([
					{
							name: "Matches",
							headers: [
								{
									text: "Team",
									value: "team"
								},
								{
									text: "Comments",
									value: "comments"
								},
								{
									text: "Device",
									value: "sender"
								}
							],
							data: matches
					}
				]);

				db.close();
			});
	}
};

Return Raw Match Data in Inverse Order


var fs = require('fs');
var path = require('path');
var argv = require('optimist').argv;

// Load options into JS object.
exports.options = JSON.parse(fs.readFileSync(path.resolve(__dirname,'../'+argv.optionsFile)));

var fs = require('fs');
var path = require('path');
var argv = require('optimist').argv;

// Load options into JS object.
exports.options = JSON.parse(fs.readFileSync(argv.optionsFile));

Change options handler to use filepath instead of filename.


import columnify from 'columnify';
import figures from 'figures';
import chalk from 'chalk';

export default function TextFormatter(errorsGroupedByFile) {
  const files = Object.keys(errorsGroupedByFile);

  const errorsText = files
    .map(file => {
      return generateErrorsForFile(file, errorsGroupedByFile[file]);
    })
    .join('\n\n');

  const summary = generateSummary(errorsGroupedByFile);

  return errorsText + '\n\n' + summary + '\n';
}

function generateErrorsForFile(file, errors) {
  const formattedErrors = errors.map(error => {
    const location = error.locations[0];

    return {
      location: chalk.dim(`${location.line}:${location.column * 4}`),
      message: error.message,
      // TODO: Add rule name
    };
  });

  const errorsText = columnify(formattedErrors, {
    showHeaders: false,
  });

  return chalk.underline(file) + '\n' + errorsText;
}

function generateSummary(errorsGroupedByFile) {
  const files = Object.keys(errorsGroupedByFile);

  const errorsCount = files.reduce((sum, file) => {
    return sum + errorsGroupedByFile[file].length;
  }, 0);

  if (errorsCount == 0) {
    return chalk.green(`${figures.tick} 0 errors detected\n`);
  }

  const summary = chalk.red(
    `${figures.cross} ${errorsCount} error` +
      (errorsCount > 1 ? 's' : '') +
      ' detected'
  );

  return summary;
}

import columnify from 'columnify';
import figures from 'figures';
import chalk from 'chalk';

export default function TextFormatter(errorsGroupedByFile) {
  const files = Object.keys(errorsGroupedByFile);

  const errorsText = files
    .map(file => {
      return generateErrorsForFile(file, errorsGroupedByFile[file]);
    })
    .join('\n\n');

  const summary = generateSummary(errorsGroupedByFile);

  return errorsText + '\n\n' + summary + '\n';
}

function generateErrorsForFile(file, errors) {
  const formattedErrors = errors.map(error => {
    const location = error.locations[0];

    return {
      location: chalk.dim(`${location.line}:${location.column * 4}`),
      message: error.message,
      rule: chalk.dim(` ${error.ruleName}`),
    };
  });

  const errorsText = columnify(formattedErrors, {
    showHeaders: false,
  });

  return chalk.underline(file) + '\n' + errorsText;
}

function generateSummary(errorsGroupedByFile) {
  const files = Object.keys(errorsGroupedByFile);

  const errorsCount = files.reduce((sum, file) => {
    return sum + errorsGroupedByFile[file].length;
  }, 0);

  if (errorsCount == 0) {
    return chalk.green(`${figures.tick} 0 errors detected\n`);
  }

  const summary = chalk.red(
    `${figures.cross} ${errorsCount} error` +
      (errorsCount > 1 ? 's' : '') +
      ' detected'
  );

  return summary;
}

Include name of `rule` that caused error in text formatter


export const RUNNING = 'RUNNING';

export const START_LOAD_RUNTIME = 'START_LOAD_RUNTIME';
export const FINISH_LOAD_RUNTIME = 'FINISH_LOAD_RUNTIME';
export const FAIL_LOAD_RUNTIME = 'FAIL_LOAD_RUNTIME';

export const START_LOAD_RUNTIME = 'START_LOAD_RUNTIME';
export const FINISH_LOAD_RUNTIME = 'FINISH_LOAD_RUNTIME';
export const FAIL_LOAD_RUNTIME = 'FAIL_LOAD_RUNTIME';

export const START_PARSE = 'START_PARSE';
export const FINISH_PARSE = 'FINISH_PARSE';
export const FAIL_PARSE = 'FAIL_PARSE';

export const START_COMPILE = 'START_COMPILE';
export const FINISH_COMPILE = 'FINISH_COMPILE';
export const FAIL_COMPILE = 'FAIL_COMPILE';
export const STOP_COMPILE = "STOP_COMPILE";

export const START_EXECUTE = 'START_EXECUTE';
export const FINISH_EXECUTE = 'FINISH_EXECUTE';
export const FAIL_EXECUTE = 'FAIL_EXECUTE';
export const STOP_EXECUTE = "STOP_EXECUTE";

export const PAUSE_RUN = 'PAUSE_RUN';
export const CLEAR_STATE = 'CLEAR_STATE';

Add action types for running code


import Measurement from 'esri/dijit/Measurement';
import React, {
  Component,
  PropTypes
} from 'react';

export default class InfoWindow extends Component {
  static contextTypes = {
    map: PropTypes.object.isRequired
  }

  initialized = false

  componentWillUpdate(prevProps) {
    if (
      this.context.map.loaded
      // the Measurement tool depends on navigationManager so we
      // need to explicitly check for that before starting the widget
      && this.context.map.navigationManager
      && !this.initialized
    ) {
      this.initialized = true;

      const measurementDiv = document.createElement('DIV');
      this.measurementContainer.appendChild(measurementDiv);

      this.measurement = new Measurement({
        map: this.context.map
      }, measurementDiv);
      this.measurement.startup();
      this.measurement.on('measure-end', (event) => {
        // deactivate the tool after drawing
        const toolName = event.toolName;
        this.measurement.setTool(toolName, false);
      });
    }

    if (prevProps.activeWebmap !== undefined && prevProps.activeWebmap !== this.props.activeWebmap) {
      if (this.context.map.destroy && this.initialized) {
        this.measurement.clearResult();
        this.initialized = false;
      }
    }

  }

  componentWillUnmount() {
    this.measurement.destroy();
  }

  render () {
    return <div
      ref={(div) => { this.measurementContainer = div; }}
      className='measurement-container'
    />;
  }
}

import Measurement from 'esri/dijit/Measurement';
import React, {
  Component,
  PropTypes
} from 'react';

export default class InfoWindow extends Component {
  static contextTypes = {
    map: PropTypes.object.isRequired
  }

  initialized = false

  componentWillUpdate(prevProps) {
    if (
      this.context.map.loaded
      // the Measurement tool depends on navigationManager so we
      // need to explicitly check for that before starting the widget
      && this.context.map.navigationManager
      && !this.initialized
    ) {
      this.initialized = true;

      const measurementDiv = document.createElement('DIV');
      this.measurementContainer.appendChild(measurementDiv);

      this.measurement = new Measurement({
        map: this.context.map
      }, measurementDiv);
      this.measurement.startup();
      // this.measurement.on('measure-end', (event) => {
      //   // deactivate the tool after drawing
      //   const toolName = event.toolName;
      //   this.measurement.setTool(toolName, false);
      // });
    }

    if (prevProps.activeWebmap !== undefined && prevProps.activeWebmap !== this.props.activeWebmap) {
      if (this.context.map.destroy && this.initialized) {
        this.measurement.clearResult();
        this.initialized = false;
      }
    }

  }

  componentWillUnmount() {
    this.measurement.destroy();
  }

  render () {
    return <div
      ref={(div) => { this.measurementContainer = div; }}
      className='measurement-container'
    />;
  }
}

Remove measurement on-end event listener that was preventing the measurement result from being displayed


'use strict';

var express = require('express'),
	index = require('./routes/index.js');

var app = express();

app.get('/', index.get);

var server = app.listen(3000, function () {

  var host = server.address().address;
  var port = server.address().port;
  console.log('Listening at http://%s:%s', host, port);

});

'use strict';

var express = require('express'),
	index = require('./routes/index.js');

var app = express();

app.get('/', index.get);

var server = app.listen(process.env.PORT || 3000, function () {

  var host = server.address().address;
  var port = server.address().port;
  console.log('Listening at http://%s:%s', host, port);

});

Fix port to be compatible with heroku


import { onBlur } from "../display/focus.js"
import { on } from "../util/event.js"

// These must be handled carefully, because naively registering a
// handler for each editor will cause the editors to never be
// garbage collected.

function forEachCodeMirror(f) {
  if (!document.getElementsByClassName) return
  let byClass = document.getElementsByClassName("CodeMirror")
  for (let i = 0; i < byClass.length; i++) {
    let cm = byClass[i].CodeMirror
    if (cm) f(cm)
  }
}

let globalsRegistered = false
export function ensureGlobalHandlers() {
  if (globalsRegistered) return
  registerGlobalHandlers()
  globalsRegistered = true
}
function registerGlobalHandlers() {
  // When the window resizes, we need to refresh active editors.
  let resizeTimer
  on(window, "resize", () => {
    if (resizeTimer == null) resizeTimer = setTimeout(() => {
      resizeTimer = null
      forEachCodeMirror(onResize)
    }, 100)
  })
  // When the window loses focus, we want to show the editor as blurred
  on(window, "blur", () => forEachCodeMirror(onBlur))
}
// Called when the window resizes
function onResize(cm) {
  let d = cm.display
  if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
    return
  // Might be a text scaling operation, clear size caches.
  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
  d.scrollbarsClipped = false
  cm.setSize()
}

import { onBlur } from "../display/focus.js"
import { on } from "../util/event.js"

// These must be handled carefully, because naively registering a
// handler for each editor will cause the editors to never be
// garbage collected.

function forEachCodeMirror(f) {
  if (!document.getElementsByClassName) return
  let byClass = document.getElementsByClassName("CodeMirror")
  for (let i = 0; i < byClass.length; i++) {
    let cm = byClass[i].CodeMirror
    if (cm) f(cm)
  }
}

let globalsRegistered = false
export function ensureGlobalHandlers() {
  if (globalsRegistered) return
  registerGlobalHandlers()
  globalsRegistered = true
}
function registerGlobalHandlers() {
  // When the window resizes, we need to refresh active editors.
  let resizeTimer
  on(window, "resize", () => {
    if (resizeTimer == null) resizeTimer = setTimeout(() => {
      resizeTimer = null
      forEachCodeMirror(onResize)
    }, 100)
  })
  // When the window loses focus, we want to show the editor as blurred
  on(window, "blur", () => forEachCodeMirror(onBlur))
}
// Called when the window resizes
function onResize(cm) {
  let d = cm.display
  // Might be a text scaling operation, clear size caches.
  d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null
  d.scrollbarsClipped = false
  cm.setSize()
}

Remove fast path in resize handler


(function (angular) {
    'use strict';

    function FlotDirective(eehFlot, $interval) {
        return {
            restrict: 'AE',
            template: '

',
            scope: {
                dataset: '=',
                options: '@',
                updateCallback: '&',
                updateCallbackTime: '@'
            },
            link: function link(scope, element) {
                scope.updateCallbackTime = scope.updateCallbackTime || 1000;
                var renderArea = element.find('.eeh-flot');
                var chart = eehFlot(renderArea, scope.dataset, scope.options);
                if (angular.isDefined(scope.updateCallback) &&
                    angular.isFunction(scope.updateCallback)) {
                    $interval(function() {
                        scope.updateCallback(chart, scope.dataset);
                    }, scope.updateCallbackTime);
                }
            }
        };
    }

    angular.module('eehFlot').directive('eehFlot', FlotDirective);
})(angular);

(function (angular) {
    'use strict';

    function FlotDirective(eehFlot, $interval) {
        return {
            restrict: 'AE',
            template: '

',
            scope: {
                dataset: '=',
                options: '@',
                updateCallback: '=',
                updateCallbackTime: '@'
            },
            link: function link(scope, element) {
                scope.updateCallbackTime = scope.updateCallbackTime || 40;
                var renderArea = element.find('.eeh-flot');
                var chart = eehFlot(renderArea, scope.dataset, scope.options);
                if (angular.isFunction(scope.updateCallback)) {
                    $interval(function() {
                        scope.updateCallback(chart, scope.dataset);
                    }, scope.updateCallbackTime);
                }
            }
        };
    }

    angular.module('eehFlot').directive('eehFlot', FlotDirective);
})(angular);

Fix issues with callback function


function randomise ({
  count = 1,
  min = 0,
  max = 100,
  precision = 0,
  join = ', '
}) {
  const delta = max - min
  const array = []
  let index = count
  while (index-- > 0) {
    const number = min + Math.random() * delta
    const fixed = Number(number.toFixed(precision))
    array.push(fixed)
  }
  const result = array.join(join)
  return result
}

module.exports = randomise

function randomise ({
  count = 1,
  min = 0,
  max = 100,
  precision = 0,
  join = ', '
} = {}) {
  const delta = max - min
  const array = []
  let index = count
  while (index-- > 0) {
    const number = min + Math.random() * delta
    const fixed = Number(number.toFixed(precision))
    array.push(fixed)
  }
  const result = array.join(join)
  return result
}

module.exports = randomise

Fix default params by setting empty object


const axios = require('axios')
const sharp = require('sharp')

async function fetchPostProcessedRadarFrame(url) {
  const data = await fetchRadarImage(url)
  return processImage(data)
}

async function fetchRadarImage(url) {
  const response = await axios({url, method: 'get', responseType: 'arraybuffer'})
  return Buffer.from(response.data)
}

async function processImage(input) {
  const {data, info} = await sharp(input)
    .ensureAlpha()
    .raw()
    .toBuffer({resolveWithObject: true})

  applyAlphaChannel(data)

  const {width, height, channels} = info
  const pipeline = sharp(data, {raw: {width, height, channels}})
    .overlayWith(`${__dirname}/radar-edges.png`)
  const png = await pipeline.clone().png().toBuffer()
  const webp = await pipeline.clone().webp({nearLossless: true}).toBuffer()
  return {png, webp}
}

function applyAlphaChannel(data) {
  for (let i = 0; i < data.length; i += 4) {
    // eslint-disable-next-line no-bitwise, no-mixed-operators
    const color = data[i] << 16 | data[i + 1] << 8 | data[i + 2]
    if (color === 0xffffff || color === 0xf7f7f7) {
      data[i + 3] = 0
    }
  }
}

module.exports = {
  fetchPostProcessedRadarFrame
}

const axios = require('axios')
const sharp = require('sharp')

sharp.cache(false)

async function fetchPostProcessedRadarFrame(url) {
  const data = await fetchRadarImage(url)
  return processImage(data)
}

async function fetchRadarImage(url) {
  const response = await axios({url, method: 'get', responseType: 'arraybuffer'})
  return Buffer.from(response.data)
}

async function processImage(input) {
  const {data, info} = await sharp(input)
    .ensureAlpha()
    .raw()
    .toBuffer({resolveWithObject: true})

  applyAlphaChannel(data)

  const {width, height, channels} = info
  const pipeline = sharp(data, {raw: {width, height, channels}})
    .overlayWith(`${__dirname}/radar-edges.png`)
  const png = await pipeline.clone().png().toBuffer()
  const webp = await pipeline.clone().webp({nearLossless: true}).toBuffer()
  return {png, webp}
}

function applyAlphaChannel(data) {
  for (let i = 0; i < data.length; i += 4) {
    // eslint-disable-next-line no-bitwise, no-mixed-operators
    const color = data[i] << 16 | data[i + 1] << 8 | data[i + 2]
    if (color === 0xffffff || color === 0xf7f7f7) {
      data[i + 3] = 0
    }
  }
}

module.exports = {
  fetchPostProcessedRadarFrame
}

Disable sharp cache (helps with Heroku)


var BlueprintClient = require('xively-blueprint-client-js');

var client = new BlueprintClient({
  authorization: process.env.BLUEPRINT_AUTHORIZATION
});

console.log('Client initialized with authorization >', process.env.BLUEPRINT_AUTHORIZATION);

module.exports = client;

var BlueprintClient = require('xively-blueprint-client-js');

var client = new BlueprintClient({
  authorization: 'Basic ' + process.env.BLUEPRINT_AUTHORIZATION
});

module.exports = client;

Remove log and Prefix Authorization token with 'Basic '


'use strict';

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

var Stats = require('lib/common/components/stats');

var ReadStream  = require('lib/common/streams/read-stream');
var WriteStream = require('lib/common/streams/write-stream');

var SyncWriteStream = require('lib/common/streams/sync-write-stream');

module.exports = function (fs, getElement, version) {

  describe('members', function () {

    it('should expose Stats', function () {
      expect(fs.Stats).to.equal(Stats);
    });

    it('should expose ReadStream', function () {
      expect(fs.ReadStream).to.be.a('function');
      expect(new fs.ReadStream('/file')).to.be.an.instanceof(ReadStream);
    });

    it('should expose WriteStream', function () {
      expect(fs.WriteStream).to.be.a('function');
      expect(new fs.WriteStream('/file')).to.be.an.instanceof(WriteStream);
    });

    if (['v0.10', 'v0.12'].indexOf(version) !== -1) {

      it('should expose SyncWriteStream', function () {
        expect(fs.SyncWriteStream).to.be.a('function');
        expect(new fs.SyncWriteStream('/file')).to.be.an.instanceof(SyncWriteStream);
      });

    }

  });

};

'use strict';

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

var Stats = require('lib/common/components/stats');

var ReadStream  = require('lib/common/streams/read-stream');
var WriteStream = require('lib/common/streams/write-stream');

var SyncWriteStream = require('lib/common/streams/sync-write-stream');

module.exports = function (fs, getElement, version) {

  describe('members', function () {

    it('should expose Stats', function () {
      expect(fs.Stats).to.equal(Stats);
    });

    it('should expose ReadStream', function () {
      expect(fs.ReadStream).to.be.a('function');
      expect(new fs.ReadStream('/file')).to.be.an.instanceof(ReadStream);
    });

    it('should expose WriteStream', function () {
      expect(fs.WriteStream).to.be.a('function');
      expect(new fs.WriteStream('/file')).to.be.an.instanceof(WriteStream);
    });

    if (['v0.10', 'v0.12'].indexOf(version) !== -1) {

      it('should expose SyncWriteStream', function () {
        expect(fs.SyncWriteStream).to.be.a('function');
        expect(new fs.SyncWriteStream('/file')).to.be.an.instanceof(SyncWriteStream);
      });

    }

    if (version !== 'v0.10') {

      it('should expose access flags', function () {
        expect(fs).to.contain.keys([
          'F_OK',
          'R_OK',
          'W_OK',
          'X_OK'
        ]);
      });

    }

  });

};

Add unit test for access flags


import React, { Component } from 'react'
import HouseholdService from '../services/HouseholdService'

class Household extends Component {
  constructor(props) {
    super(props)

    this.state = {
      name: ''
    }
  }
  componentWillReceiveProps(nextProps) {
    const { id } = nextProps.match.params

    HouseholdService.fetchHousehold(id)
      .then(household => this.setState({
        name: household.name
      }))
  }

  componentDidMount() {
    const { id } = this.props.match.params
    HouseholdService.fetchHousehold(id)
      .then(household => this.setState({
        name: household.name
      }))
  }

  render() {
    const { name } = this.props
    return (

{name}

    )

  }
}

export default Household

import React, { Component } from 'react'
import HouseholdService from '../services/HouseholdService'

class Household extends Component {
  constructor(props) {
    super(props)

    this.state = {
      name: ''
    }
  }
  componentWillReceiveProps(nextProps) {
    const { id } = nextProps.match.params

    HouseholdService.fetchHousehold(id)
      .then(household => this.setState({
        name: household.name
      }))
  }

  componentDidMount() {
    const { id } = this.props.match.params
    HouseholdService.fetchHousehold(id)
      .then(household => this.setState({
        name: household.name
      }))
  }

  render() {
    const { name } = this.state
    return (

{name}

    )

  }
}

export default Household

Update to take name from state and not props


export const withUpdated = (arr, select, update) => (
  arr.map(el => select(el) ? update(el) : el)
);

export const withInsertedBefore = (arr, selectBefore, element) => {
  const reference = arr.findIndex(selectBefore);

  if (reference < 0) {
    return arr;
  }

  if (reference === 0) {
    return [element, ...arr];
  }

  return [].concat(
    arr.slice(0, reference),
    element,
    arr.slice(reference, arr.length),
  );
};

export const moveUp = (arr, select) => {
  const pos = arr.findIndex(select);
  if (pos <= 0) {
    return arr;
  }
  return arr.map((el, idx) => {
    if (idx === pos - 1) {
      return arr[idx + 1];
    } else if (idx === pos) {
      return arr[idx - 1]
    } else {
      return el;
    }
  });
};

export const moveDown = (arr, select) => {
  const pos = arr.findIndex(select);
  if (pos < -1 || pos >= arr.length - 1) {
    return arr;
  }
  return arr.map((el, idx) => {
    if (idx === pos + 1) {
      return arr[idx - 1];
    } else if (idx === pos) {
      return arr[idx + 1]
    } else {
      return el;
    }
  });
};

export const withUpdated = (arr, select, update) => (
  arr.map(el => select(el) ? update(el) : el)
);

export const withInsertedBefore = (arr, selectBefore, element) => {
  const reference = arr.findIndex(selectBefore);

  if (reference < 0) {
    return arr;
  }

  if (reference === 0) {
    return [element, ...arr];
  }

  return [].concat(
    arr.slice(0, reference),
    element,
    arr.slice(reference, arr.length),
  );
};

export const moveUp = (arr, select) => {
  const pos = arr.findIndex(select);
  if (pos <= 0) {
    return arr;
  }
  return arr.map((el, idx) => {
    if (idx === pos - 1) {
      return arr[idx + 1];
    } else if (idx === pos) {
      return arr[idx - 1]
    } else {
      return el;
    }
  });
};

export const moveDown = (arr, select) => {
  const pos = arr.findIndex(select);
  if (pos < 0 || pos >= arr.length - 1) {
    return arr;
  }
  return arr.map((el, idx) => {
    if (idx === pos + 1) {
      return arr[idx - 1];
    } else if (idx === pos) {
      return arr[idx + 1]
    } else {
      return el;
    }
  });
};

Fix arrayHelper move down when selector does not match


'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;
  });

'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},
        mark: {
          tickThickness: 2
        }
      };
    };

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

    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 tick thicker to facilitate hovering


const r = require('./../../../db');
const config = require('config');

const check = id =>
	new Promise((resolve, reject) => {
		r.table('registrations')
			.get(id)
			.run(r.conn, (err1, res) => {
				if (err1) {
					reject('Could not search RethonkDB');
				} else if (!res) {
					reject(`You or the guild are not registered! Please register for ${config.get('name')} using the \`register\` command`);
				} else {
					resolve(res);
				}
			});
	});

const name = string => string.replace(/ /g, '+').replace(/\W/g, '=').toLowerCase();

module.exports.check = check;
module.exports.name = name;

const r = require('./../../../db');
const config = require('config');

const check = id =>
	new Promise((resolve, reject) => {
		r.table('registrations')
			.get(id)
			.run(r.conn, (err1, res) => {
				if (err1) {
					reject('Could not search RethonkDB');
				} else if (!res) {
					reject(`You or the guild are not registered! Please register for ${config.get('name')} using the \`register\` command`);
				} else {
					resolve(res);
				}
			});
	});

const name = string => string.replace(/ /g, '+').replace(/[^\w\d!#$&'*+\-/=?^_`{|}~\u007F-\uFFFF]+/g, '=').toLowerCase();

module.exports.check = check;
module.exports.name = name;

Support most ASCII characters and all Unicode above U+007F


// This require this file to load all the models into the
// interactive note console

process.env.NODE_ENV = 'development'
require('coffee-script')
o = require('./models/organization')
b = require('./models/badge')
u = require('./models/user')

module.exports = {
  Badge: b,
  Organization: o,
  User: u
}

// Require this file to load all the models into the
// interactive note console

process.env.NODE_ENV = 'development'
require('coffee-script')
o = require('./models/organization')
b = require('./models/badge')
u = require('./models/user')

module.exports = {
  Badge: b,
  Organization: o,
  User: u
}

Remove extra word for more better englishes


var padManager = require('../../db/PadManager');
var url = require('url');

exports.expressCreateServer = function (hook_name, args, cb) {
  //redirects browser to the pad's sanitized url if needed. otherwise, renders the html
  args.app.param('pad', function (req, res, next, padId) {
    //ensure the padname is valid and the url doesn't end with a /
    if(!padManager.isValidPadId(padId) || /\/$/.test(req.url))
    {
      res.status(404).send('Such a padname is forbidden');
    }
    else
    {
      padManager.sanitizePadId(padId, function(sanitizedPadId) {
        //the pad id was sanitized, so we redirect to the sanitized version
        if(sanitizedPadId != padId)
        {
          var real_url = sanitizedPadId;
          var query = url.parse(req.url).query;
          if ( query ) real_url += '?' + query;
          res.header('Location', real_url);
          res.status(302).send('You should be redirected to ' + real_url + '');
        }
        //the pad id was fine, so just render it
        else
        {
          next();
        }
      });
    }
  });
}

var padManager = require('../../db/PadManager');
var url = require('url');

exports.expressCreateServer = function (hook_name, args, cb) {
  //redirects browser to the pad's sanitized url if needed. otherwise, renders the html
  args.app.param('pad', function (req, res, next, padId) {
    //ensure the padname is valid and the url doesn't end with a /
    if(!padManager.isValidPadId(padId) || /\/$/.test(req.url))
    {
      res.status(404).send('Such a padname is forbidden');
    }
    else
    {
      padManager.sanitizePadId(padId, function(sanitizedPadId) {
        //the pad id was sanitized, so we redirect to the sanitized version
        if(sanitizedPadId != padId)
        {
          var real_url = sanitizedPadId;
          real_url = encodeURIComponent(real_url);
          var query = url.parse(req.url).query;
          if ( query ) real_url += '?' + query;
          res.header('Location', real_url);
          res.status(302).send('You should be redirected to ' + real_url + '');
        }
        //the pad id was fine, so just render it
        else
        {
          next();
        }
      });
    }
  });
}

Fix decode error if pad name contains special characters and is sanitized