Add failing spec for fetch from isolated world

--- spec/fixtures/api/isolated-preload.js
+++ spec/fixtures/api/isolated-preload.js
@@ -1,8 +1,14 @@
+// Ensure fetch works from isolated world origin
+fetch('http://localhost:1234')
+fetch('https://localhost:1234')
+fetch(`file://${__filename}`)
+
 const {ipcRenderer, webFrame} = require('electron')

 window.foo = 3

 webFrame.executeJavaScript('window.preloadExecuteJavaScriptProperty = 1234;')
+

 window.addEventListener('message', (event) => {
   ipcRenderer.send('isolated-world', {

<|original_code|>
const {ipcRenderer, webFrame} = require('electron')

window.foo = 3

webFrame.executeJavaScript('window.preloadExecuteJavaScriptProperty = 1234;')

window.addEventListener('message', (event) => {
  ipcRenderer.send('isolated-world', {
    preloadContext: {
      preloadProperty: typeof window.foo,
      pageProperty: typeof window.hello,
      typeofRequire: typeof require,
      typeofProcess: typeof process,
      typeofArrayPush: typeof Array.prototype.push,
      typeofFunctionApply: typeof Function.prototype.apply
    },
    pageContext: event.data
  })
})

<|edits_diff|>
--- spec/fixtures/api/isolated-preload.js
+++ spec/fixtures/api/isolated-preload.js
@@ -1,3 +1,8 @@
+// Ensure fetch works from isolated world origin
+fetch('http://localhost:1234')
+fetch('https://localhost:1234')
+fetch(`file://${__filename}`)
+
 const {ipcRenderer, webFrame} = require('electron')

 window.foo = 3
<|current_version|>
// Ensure fetch works from isolated world origin
fetch('http://localhost:1234')
fetch('https://localhost:1234')
fetch(`file://${__filename}`)

const {ipcRenderer, webFrame} = require('electron')

window.foo = 3

webFrame.executeJavaScript('window.preloadExecuteJavaScriptProperty = 1234;')

window.addEventListener('message', (event) => {
  ipcRenderer.send('isolated-world', {
    preloadContext: {
      preloadProperty: typeof window.foo,
      pageProperty: typeof window.hello,
      typeofRequire: typeof require,
      typeofProcess: typeof process,
      typeofArrayPush: typeof Array.prototype.push,
      typeofFunctionApply: typeof Function.prototype.apply
    },
    pageContext: event.data
  })
})

<|next_version|>
// Ensure fetch works from isolated world origin
fetch('http://localhost:1234')
fetch('https://localhost:1234')
fetch(`file://${__filename}`)

const {ipcRenderer, webFrame} = require('electron')

window.foo = 3

webFrame.executeJavaScript('window.preloadExecuteJavaScriptProperty = 1234;')

window.addEventListener('message', (event) => {
  ipcRenderer.send('isolated-world', {
    preloadContext: {
      preloadProperty: typeof window.foo,
      pageProperty: typeof window.hello,
      typeofRequire: typeof require,
      typeofProcess: typeof process,
      typeofArrayPush: typeof Array.prototype.push,
      typeofFunctionApply: typeof Function.prototype.apply
    },
    pageContext: event.data
  })
})


Add 404 catch all route to boilerplate module code

--- app/modules/boilerplate/router.js
+++ app/modules/boilerplate/router.js
@@ -8,12 +8,17 @@

         routes: {
             "": "home",
+            "*404": "404" // catch-all route
         },

         home: function() {
             // var homeView = new HomeView();
             // var renderedView = homeView.render();
             // renderedView.$el.appendTo("body");
+        },
+
+        "404": function() {
+            console.error("Route 404");
         }

     });

<|original_code|>
define([
    'backbone',
    'modules/boilerplate/module',
    'modules/boilerplate/views/home',
], function (Backbone, BoilerplateModule, HomeView) {

    var Router = Backbone.SubRoute.extend({

        routes: {
            "": "home",
        },

        home: function() {
            // var homeView = new HomeView();
            // var renderedView = homeView.render();
            // renderedView.$el.appendTo("body");
        }

    });

    return Router;

});

<|edits_diff|>
--- app/modules/boilerplate/router.js
+++ app/modules/boilerplate/router.js
@@ -8,6 +8,7 @@

         routes: {
             "": "home",
+            "*404": "404" // catch-all route
         },

         home: function() {
<|current_version|>
define([
    'backbone',
    'modules/boilerplate/module',
    'modules/boilerplate/views/home',
], function (Backbone, BoilerplateModule, HomeView) {

    var Router = Backbone.SubRoute.extend({

        routes: {
            "": "home",
            "*404": "404" // catch-all route
        },

        home: function() {
            // var homeView = new HomeView();
            // var renderedView = homeView.render();
            // renderedView.$el.appendTo("body");
        }

    });

    return Router;

});

<|next_version|>
define([
    'backbone',
    'modules/boilerplate/module',
    'modules/boilerplate/views/home',
], function (Backbone, BoilerplateModule, HomeView) {

    var Router = Backbone.SubRoute.extend({

        routes: {
            "": "home",
            "*404": "404" // catch-all route
        },

        home: function() {
            // var homeView = new HomeView();
            // var renderedView = homeView.render();
            // renderedView.$el.appendTo("body");
        },

        "404": function() {
            console.error("Route 404");
        }

    });

    return Router;

});


Move babel cache to local project

Move babel cache to local project

This removes potentially large performance overhead from loading the babel cache across many unrelated projects.

--- runtime-init.js
+++ runtime-init.js
@@ -1,4 +1,11 @@
+/* eslint-disable no-process-env */
+var Path = require('path');
+
 Error.stackTraceLimit = Infinity;   // And beyond
+
+if (!process.env.BABEL_CACHE_PATH) {
+  process.env.BABEL_CACHE_PATH = Path.resolve('./.babel.cache.json');
+}

 require('babel-core/register')(require('./babel-defaults'));

<|original_code|>
Error.stackTraceLimit = Infinity;   // And beyond

require('babel-core/register')(require('./babel-defaults'));

// Must be after babel so our fork overrides the one installed by babel.
// Aren't unresponsive OSS projects fun!.
require('source-map-support').install({
  environment: 'node',
  handleUncaughtExceptions: false,
  hookRequire: true
});

<|edits_diff|>
--- runtime-init.js
+++ runtime-init.js
@@ -1,3 +1,6 @@
+/* eslint-disable no-process-env */
+var Path = require('path');
+
 Error.stackTraceLimit = Infinity;   // And beyond

 require('babel-core/register')(require('./babel-defaults'));
<|current_version|>
/* eslint-disable no-process-env */
var Path = require('path');

Error.stackTraceLimit = Infinity;   // And beyond

require('babel-core/register')(require('./babel-defaults'));

// Must be after babel so our fork overrides the one installed by babel.
// Aren't unresponsive OSS projects fun!.
require('source-map-support').install({
  environment: 'node',
  handleUncaughtExceptions: false,
  hookRequire: true
});

<|next_version|>
/* eslint-disable no-process-env */
var Path = require('path');

Error.stackTraceLimit = Infinity;   // And beyond

if (!process.env.BABEL_CACHE_PATH) {
  process.env.BABEL_CACHE_PATH = Path.resolve('./.babel.cache.json');
}

require('babel-core/register')(require('./babel-defaults'));

// Must be after babel so our fork overrides the one installed by babel.
// Aren't unresponsive OSS projects fun!.
require('source-map-support').install({
  environment: 'node',
  handleUncaughtExceptions: false,
  hookRequire: true
});


Resolve configuration file to absolute path before loading

--- index.js
+++ index.js
@@ -1,7 +1,10 @@
+var path = require('path');
 var configFilePath = process.argv[2];
 var config = {};

 if (configFilePath) {
+  configFilePath = path.resolve(configFilePath);
+
   try {
     config = require(configFilePath);
   } catch(e) {

<|original_code|>
var configFilePath = process.argv[2];
var config = {};

if (configFilePath) {
  try {
    config = require(configFilePath);
  } catch(e) {
    console.log('Cannot load '+configFilePath);
    process.exit(1);
  }
}

var utils = require('./lib')(config);

<|edits_diff|>
--- index.js
+++ index.js
@@ -1,3 +1,4 @@
+var path = require('path');
 var configFilePath = process.argv[2];
 var config = {};

<|current_version|>
var path = require('path');
var configFilePath = process.argv[2];
var config = {};

if (configFilePath) {
  try {
    config = require(configFilePath);
  } catch(e) {
    console.log('Cannot load '+configFilePath);
    process.exit(1);
  }
}

var utils = require('./lib')(config);

<|next_version|>
var path = require('path');
var configFilePath = process.argv[2];
var config = {};

if (configFilePath) {
  configFilePath = path.resolve(configFilePath);

  try {
    config = require(configFilePath);
  } catch(e) {
    console.log('Cannot load '+configFilePath);
    process.exit(1);
  }
}

var utils = require('./lib')(config);


Improve code comments for undocumented API

--- index.js
+++ index.js
@@ -20,6 +20,10 @@
   })

   function asyncFunctionInitialized () {
+    // Record the state currently set on on the async-state object and return a
+    // snapshot of it. The returned object will later be passed as the `data`
+    // arg in the functions below.
+
     var data = {}
     for (var key in state) {
       data[key] = state[key]
@@ -28,12 +32,17 @@
   }

   function asyncCallbackBefore (context, data) {
+    // We just returned from the event-loop: We'll now restore the state
+    // previously saved by `asyncFunctionInitialized`.
+
     for (var key in data) {
       state[key] = data[key]
     }
   }

   function asyncCallbackAfter (context, data) {
+    // Clear the state so that it doesn't leak between isolated async stacks.
+
     for (var key in state) {
       delete state[key]
     }

<|original_code|>
'use strict'

module.exports = new AsyncState()

function AsyncState () {
  var tracing
  var state = this

  try {
    tracing = require('tracing')
  } catch (e) {
    tracing = require('./lib/tracing_polyfill.js')
  }

  tracing.addAsyncListener({
    'create': asyncFunctionInitialized,
    'before': asyncCallbackBefore,
    'error': function () {},
    'after': asyncCallbackAfter
  })

  function asyncFunctionInitialized () {
    var data = {}
    for (var key in state) {
      data[key] = state[key]
    }
    return data
  }

  function asyncCallbackBefore (context, data) {
    for (var key in data) {
      state[key] = data[key]
    }
  }

  function asyncCallbackAfter (context, data) {
    for (var key in state) {
      delete state[key]
    }
  }
}

<|edits_diff|>
--- index.js
+++ index.js
@@ -20,6 +20,10 @@
   })

   function asyncFunctionInitialized () {
+    // Record the state currently set on on the async-state object and return a
+    // snapshot of it. The returned object will later be passed as the `data`
+    // arg in the functions below.
+
     var data = {}
     for (var key in state) {
       data[key] = state[key]
@@ -28,6 +32,9 @@
   }

   function asyncCallbackBefore (context, data) {
+    // We just returned from the event-loop: We'll now restore the state
+    // previously saved by `asyncFunctionInitialized`.
+
     for (var key in data) {
       state[key] = data[key]
     }
<|current_version|>
'use strict'

module.exports = new AsyncState()

function AsyncState () {
  var tracing
  var state = this

  try {
    tracing = require('tracing')
  } catch (e) {
    tracing = require('./lib/tracing_polyfill.js')
  }

  tracing.addAsyncListener({
    'create': asyncFunctionInitialized,
    'before': asyncCallbackBefore,
    'error': function () {},
    'after': asyncCallbackAfter
  })

  function asyncFunctionInitialized () {
    // Record the state currently set on on the async-state object and return a
    // snapshot of it. The returned object will later be passed as the `data`
    // arg in the functions below.

    var data = {}
    for (var key in state) {
      data[key] = state[key]
    }
    return data
  }

  function asyncCallbackBefore (context, data) {
    // We just returned from the event-loop: We'll now restore the state
    // previously saved by `asyncFunctionInitialized`.

    for (var key in data) {
      state[key] = data[key]
    }
  }

  function asyncCallbackAfter (context, data) {
    for (var key in state) {
      delete state[key]
    }
  }
}

<|next_version|>
'use strict'

module.exports = new AsyncState()

function AsyncState () {
  var tracing
  var state = this

  try {
    tracing = require('tracing')
  } catch (e) {
    tracing = require('./lib/tracing_polyfill.js')
  }

  tracing.addAsyncListener({
    'create': asyncFunctionInitialized,
    'before': asyncCallbackBefore,
    'error': function () {},
    'after': asyncCallbackAfter
  })

  function asyncFunctionInitialized () {
    // Record the state currently set on on the async-state object and return a
    // snapshot of it. The returned object will later be passed as the `data`
    // arg in the functions below.

    var data = {}
    for (var key in state) {
      data[key] = state[key]
    }
    return data
  }

  function asyncCallbackBefore (context, data) {
    // We just returned from the event-loop: We'll now restore the state
    // previously saved by `asyncFunctionInitialized`.

    for (var key in data) {
      state[key] = data[key]
    }
  }

  function asyncCallbackAfter (context, data) {
    // Clear the state so that it doesn't leak between isolated async stacks.

    for (var key in state) {
      delete state[key]
    }
  }
}


Fix QUnit output for equal assertions

Fix QUnit output for equal assertions

Display a friendlier message than 'undefined' when an equal assertion fails.

--- tests/test_helper.js
+++ tests/test_helper.js
@@ -12,7 +12,13 @@
   return !!find(selector).length;
 }

+function equal(actual, expected, message) {
+  message = message || QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual);
+  QUnit.equal.call(this, expected, actual, message);
+}
+
 window.exists = exists;
+window.equal = equal;

 Ember.Container.prototype.stub = function(fullName, instance) {
   instance.destroy = instance.destroy || function() {};

<|original_code|>
document.write('

');

Ember.testing = true;

var App = requireModule('appkit/app');

App.rootElement = '#ember-testing';
App.setupForTesting();
App.injectTestHelpers();

function exists(selector) {
  return !!find(selector).length;
}

window.exists = exists;

Ember.Container.prototype.stub = function(fullName, instance) {
  instance.destroy = instance.destroy || function() {};
  this.cache.dict[fullName] = instance;
};

<|edits_diff|>
--- tests/test_helper.js
+++ tests/test_helper.js
@@ -12,6 +12,11 @@
   return !!find(selector).length;
 }

+function equal(actual, expected, message) {
+  message = message || QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual);
+  QUnit.equal.call(this, expected, actual, message);
+}
+
 window.exists = exists;

 Ember.Container.prototype.stub = function(fullName, instance) {
<|current_version|>
document.write('

');

Ember.testing = true;

var App = requireModule('appkit/app');

App.rootElement = '#ember-testing';
App.setupForTesting();
App.injectTestHelpers();

function exists(selector) {
  return !!find(selector).length;
}

function equal(actual, expected, message) {
  message = message || QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual);
  QUnit.equal.call(this, expected, actual, message);
}

window.exists = exists;

Ember.Container.prototype.stub = function(fullName, instance) {
  instance.destroy = instance.destroy || function() {};
  this.cache.dict[fullName] = instance;
};

<|next_version|>
document.write('

');

Ember.testing = true;

var App = requireModule('appkit/app');

App.rootElement = '#ember-testing';
App.setupForTesting();
App.injectTestHelpers();

function exists(selector) {
  return !!find(selector).length;
}

function equal(actual, expected, message) {
  message = message || QUnit.jsDump.parse(expected) + " expected but was " + QUnit.jsDump.parse(actual);
  QUnit.equal.call(this, expected, actual, message);
}

window.exists = exists;
window.equal = equal;

Ember.Container.prototype.stub = function(fullName, instance) {
  instance.destroy = instance.destroy || function() {};
  this.cache.dict[fullName] = instance;
};


Add doc comments for program builder

docs: Add doc comments for program builder

--- bin/programBuiider.js
+++ bin/programBuiider.js
@@ -8,12 +8,18 @@
 var newCommand = require('./commands/new')(appDir);
 var pkg        = require(path.resolve(__dirname, '..', 'package.json'));

+/**
+ * Get the ball-rolling for the whole program
+ */
 module.exports = function() {
 	setProgramBaseSettings();
 	setNewCommand();
 	initProgram();
 }

+/**
+ * Setup the 'new' command
+ */
 function setNewCommand() {
 	program
 		.command('new')
@@ -23,6 +29,9 @@
 		});
 }

+/**
+ * Initialise program
+ */
 function initProgram() {
 	program.parse(process.argv);

@@ -31,6 +40,9 @@
 	}
 }

+/**
+ * Get program option flags
+ */
 function getProgramOptions() {
 	return {
 		silent: program.silent,
@@ -38,6 +50,9 @@
 	}
 }

+/**
+ * Set program base settings: version, option flags
+ */
 function setProgramBaseSettings() {
 	program
 		.version(pkg.version)

<|original_code|>
"use strict";

var program = require('commander');
var path    = require('path');
var os = require('os');
var appDir  = path.resolve(os.tmpDir(), 'cartridge');

var newCommand = require('./commands/new')(appDir);
var pkg        = require(path.resolve(__dirname, '..', 'package.json'));

module.exports = function() {
	setProgramBaseSettings();
	setNewCommand();
	initProgram();
}

function setNewCommand() {
	program
		.command('new')
		.description('Create a new project')
		.action(function() {
			newCommand.init(getProgramOptions());
		});
}

function initProgram() {
	program.parse(process.argv);

	if (!process.argv.slice(2).length) {
		program.outputHelp();
	}
}

function getProgramOptions() {
	return {
		silent: program.silent,
		verbose: program.verbose
	}
}

function setProgramBaseSettings() {
	program
		.version(pkg.version)
		.option('-s, --silent', 'Surpress all on-screen messages')
		.option('-v, --verbose', 'Show all on-screen messages');
}

<|edits_diff|>
--- bin/programBuiider.js
+++ bin/programBuiider.js
@@ -8,12 +8,18 @@
 var newCommand = require('./commands/new')(appDir);
 var pkg        = require(path.resolve(__dirname, '..', 'package.json'));

+/**
+ * Get the ball-rolling for the whole program
+ */
 module.exports = function() {
 	setProgramBaseSettings();
 	setNewCommand();
 	initProgram();
 }

+/**
+ * Setup the 'new' command
+ */
 function setNewCommand() {
 	program
 		.command('new')
@@ -23,6 +29,9 @@
 		});
 }

+/**
+ * Initialise program
+ */
 function initProgram() {
 	program.parse(process.argv);

@@ -31,6 +40,9 @@
 	}
 }

+/**
+ * Get program option flags
+ */
 function getProgramOptions() {
 	return {
 		silent: program.silent,
<|current_version|>
"use strict";

var program = require('commander');
var path    = require('path');
var os = require('os');
var appDir  = path.resolve(os.tmpDir(), 'cartridge');

var newCommand = require('./commands/new')(appDir);
var pkg        = require(path.resolve(__dirname, '..', 'package.json'));

/**
 * Get the ball-rolling for the whole program
 */
module.exports = function() {
	setProgramBaseSettings();
	setNewCommand();
	initProgram();
}

/**
 * Setup the 'new' command
 */
function setNewCommand() {
	program
		.command('new')
		.description('Create a new project')
		.action(function() {
			newCommand.init(getProgramOptions());
		});
}

/**
 * Initialise program
 */
function initProgram() {
	program.parse(process.argv);

	if (!process.argv.slice(2).length) {
		program.outputHelp();
	}
}

/**
 * Get program option flags
 */
function getProgramOptions() {
	return {
		silent: program.silent,
		verbose: program.verbose
	}
}

function setProgramBaseSettings() {
	program
		.version(pkg.version)
		.option('-s, --silent', 'Surpress all on-screen messages')
		.option('-v, --verbose', 'Show all on-screen messages');
}

<|next_version|>
"use strict";

var program = require('commander');
var path    = require('path');
var os = require('os');
var appDir  = path.resolve(os.tmpDir(), 'cartridge');

var newCommand = require('./commands/new')(appDir);
var pkg        = require(path.resolve(__dirname, '..', 'package.json'));

/**
 * Get the ball-rolling for the whole program
 */
module.exports = function() {
	setProgramBaseSettings();
	setNewCommand();
	initProgram();
}

/**
 * Setup the 'new' command
 */
function setNewCommand() {
	program
		.command('new')
		.description('Create a new project')
		.action(function() {
			newCommand.init(getProgramOptions());
		});
}

/**
 * Initialise program
 */
function initProgram() {
	program.parse(process.argv);

	if (!process.argv.slice(2).length) {
		program.outputHelp();
	}
}

/**
 * Get program option flags
 */
function getProgramOptions() {
	return {
		silent: program.silent,
		verbose: program.verbose
	}
}

/**
 * Set program base settings: version, option flags
 */
function setProgramBaseSettings() {
	program
		.version(pkg.version)
		.option('-s, --silent', 'Surpress all on-screen messages')
		.option('-v, --verbose', 'Show all on-screen messages');
}


Clear views array on job_create event

Clear views array on job_create event

Fixes juttle/outrigger#83

When running a different program from our original program, there
was an issue with the old views getting reinstantiated because they
still existed in redux store. This change resets the views in the store
to an empty object so new views are only instantiated when we have info
about them.

--- src/view/reducers.js
+++ src/view/reducers.js
@@ -4,6 +4,9 @@

 function views(state = {}, action) {
     switch (action.type) {
+        // reset views on new job
+        case JOB_CREATED:
+            return {};

         case JOB_START:
             let views = {};
@@ -14,6 +17,7 @@
             });

             return views;
+
         default:
             return state;

<|original_code|>
import { combineReducers } from "redux";

import { JOB_START, JOB_CREATED } from "./actions";

function views(state = {}, action) {
    switch (action.type) {

        case JOB_START:
            let views = {};

            // XXX need to change outrigger to return view_id instead of sink_id
            action.views.forEach(view => {
                views[view.sink_id] = view;
            });

            return views;
        default:
            return state;

    }
}

function job_id(state = null, action) {
    switch (action.type) {

        case JOB_CREATED:
            return action.job_id;
        default:
            return state;

    }
}

export default combineReducers({
    views,
    job_id
});

<|edits_diff|>
--- src/view/reducers.js
+++ src/view/reducers.js
@@ -4,6 +4,9 @@

 function views(state = {}, action) {
     switch (action.type) {
+        // reset views on new job
+        case JOB_CREATED:
+            return {};

         case JOB_START:
             let views = {};
<|current_version|>
import { combineReducers } from "redux";

import { JOB_START, JOB_CREATED } from "./actions";

function views(state = {}, action) {
    switch (action.type) {
        // reset views on new job
        case JOB_CREATED:
            return {};

        case JOB_START:
            let views = {};

            // XXX need to change outrigger to return view_id instead of sink_id
            action.views.forEach(view => {
                views[view.sink_id] = view;
            });

            return views;
        default:
            return state;

    }
}

function job_id(state = null, action) {
    switch (action.type) {

        case JOB_CREATED:
            return action.job_id;
        default:
            return state;

    }
}

export default combineReducers({
    views,
    job_id
});

<|next_version|>
import { combineReducers } from "redux";

import { JOB_START, JOB_CREATED } from "./actions";

function views(state = {}, action) {
    switch (action.type) {
        // reset views on new job
        case JOB_CREATED:
            return {};

        case JOB_START:
            let views = {};

            // XXX need to change outrigger to return view_id instead of sink_id
            action.views.forEach(view => {
                views[view.sink_id] = view;
            });

            return views;

        default:
            return state;

    }
}

function job_id(state = null, action) {
    switch (action.type) {

        case JOB_CREATED:
            return action.job_id;
        default:
            return state;

    }
}

export default combineReducers({
    views,
    job_id
});


Add a small delay to startup of puppeteer

--- streetvoice/src/start-puppeteer.js
+++ streetvoice/src/start-puppeteer.js
@@ -1,6 +1,13 @@
 const puppeteer = require("puppeteer-core");

+function sleep(ms) {
+  return new Promise(resolve => setTimeout(resolve, ms));
+}
+
 async function main () {
+  // Wait a second to give mitmproxy time to start up
+  await sleep(1000);
+
   const browser = await puppeteer.launch({
     headless: false,
     executablePath: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome",

<|original_code|>
const puppeteer = require("puppeteer-core");

async function main () {
  const browser = await puppeteer.launch({
    headless: false,
    executablePath: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome",
    args: [ '--proxy-server=http://127.0.0.1:8080' ],
  });
  const page = await browser.newPage();
  await page.goto('https://streetvoice.com/megafeihong');
  page.once("close", async () => {
     await browser.close();
     console.log("\nDone!");
  });
}

main();

<|edits_diff|>
--- streetvoice/src/start-puppeteer.js
+++ streetvoice/src/start-puppeteer.js
@@ -1,4 +1,8 @@
 const puppeteer = require("puppeteer-core");
+
+function sleep(ms) {
+  return new Promise(resolve => setTimeout(resolve, ms));
+}

 async function main () {
   const browser = await puppeteer.launch({
<|current_version|>
const puppeteer = require("puppeteer-core");

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main () {
  const browser = await puppeteer.launch({
    headless: false,
    executablePath: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome",
    args: [ '--proxy-server=http://127.0.0.1:8080' ],
  });
  const page = await browser.newPage();
  await page.goto('https://streetvoice.com/megafeihong');
  page.once("close", async () => {
     await browser.close();
     console.log("\nDone!");
  });
}

main();

<|next_version|>
const puppeteer = require("puppeteer-core");

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function main () {
  // Wait a second to give mitmproxy time to start up
  await sleep(1000);

  const browser = await puppeteer.launch({
    headless: false,
    executablePath: "/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome",
    args: [ '--proxy-server=http://127.0.0.1:8080' ],
  });
  const page = await browser.newPage();
  await page.goto('https://streetvoice.com/megafeihong');
  page.once("close", async () => {
     await browser.close();
     console.log("\nDone!");
  });
}

main();


Refresh hostings after closing modal

[DASH-2397] Refresh hostings after closing modal

--- src/apps/Hosting/HostingStore.js
+++ src/apps/Hosting/HostingStore.js
@@ -55,10 +55,12 @@
   },

   onCreateHostingCompleted(payload) {
+    this.refreshData();
     this.sendHostingAnalytics('add', payload);
   },

   onUpdateHostingCompleted(payload) {
+    this.refreshData();
     this.sendHostingAnalytics('edit', payload);
   },

<|original_code|>
import Reflux from 'reflux';
import _ from 'lodash';

import { CheckListStoreMixin, HostingMixin, WaitForStoreMixin, StoreLoadingMixin } from '../../mixins';

import SessionActions from '../Session/SessionActions';
import Actions from './HostingActions';

export default Reflux.createStore({
  listenables: Actions,

  mixins: [
    CheckListStoreMixin,
    HostingMixin,
    WaitForStoreMixin,
    StoreLoadingMixin
  ],

  getInitialState() {
    return {
      items: [],
      isLoading: false
    };
  },

  init() {
    this.data = this.getInitialState();
    this.waitFor(
      SessionActions.setInstance,
      this.refreshData
    );
    this.setLoadingStates();
  },

  sendHostingAnalytics(type, payload) {
    window.analytics.track('Used Dashboard Sockets API', {
      type,
      instance: payload.instanceName,
      socketId: payload.label,
      socket: 'hosting'
    });
  },

  setHosting(data) {
    this.data.items = _.forEach(data, this.prepareHosting);
    this.trigger(this.data);
  },

  refreshData() {
    Actions.fetchHostings();
  },

  onFetchHostingsCompleted(data) {
    Actions.setHosting(data);
  },

  onCreateHostingCompleted(payload) {
    this.sendHostingAnalytics('add', payload);
  },

  onUpdateHostingCompleted(payload) {
    this.sendHostingAnalytics('edit', payload);
  },

  onRemoveHostingsCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('delete', payload);
  }
});

<|edits_diff|>
--- src/apps/Hosting/HostingStore.js
+++ src/apps/Hosting/HostingStore.js
@@ -55,6 +55,7 @@
   },

   onCreateHostingCompleted(payload) {
+    this.refreshData();
     this.sendHostingAnalytics('add', payload);
   },

<|current_version|>
import Reflux from 'reflux';
import _ from 'lodash';

import { CheckListStoreMixin, HostingMixin, WaitForStoreMixin, StoreLoadingMixin } from '../../mixins';

import SessionActions from '../Session/SessionActions';
import Actions from './HostingActions';

export default Reflux.createStore({
  listenables: Actions,

  mixins: [
    CheckListStoreMixin,
    HostingMixin,
    WaitForStoreMixin,
    StoreLoadingMixin
  ],

  getInitialState() {
    return {
      items: [],
      isLoading: false
    };
  },

  init() {
    this.data = this.getInitialState();
    this.waitFor(
      SessionActions.setInstance,
      this.refreshData
    );
    this.setLoadingStates();
  },

  sendHostingAnalytics(type, payload) {
    window.analytics.track('Used Dashboard Sockets API', {
      type,
      instance: payload.instanceName,
      socketId: payload.label,
      socket: 'hosting'
    });
  },

  setHosting(data) {
    this.data.items = _.forEach(data, this.prepareHosting);
    this.trigger(this.data);
  },

  refreshData() {
    Actions.fetchHostings();
  },

  onFetchHostingsCompleted(data) {
    Actions.setHosting(data);
  },

  onCreateHostingCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('add', payload);
  },

  onUpdateHostingCompleted(payload) {
    this.sendHostingAnalytics('edit', payload);
  },

  onRemoveHostingsCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('delete', payload);
  }
});

<|next_version|>
import Reflux from 'reflux';
import _ from 'lodash';

import { CheckListStoreMixin, HostingMixin, WaitForStoreMixin, StoreLoadingMixin } from '../../mixins';

import SessionActions from '../Session/SessionActions';
import Actions from './HostingActions';

export default Reflux.createStore({
  listenables: Actions,

  mixins: [
    CheckListStoreMixin,
    HostingMixin,
    WaitForStoreMixin,
    StoreLoadingMixin
  ],

  getInitialState() {
    return {
      items: [],
      isLoading: false
    };
  },

  init() {
    this.data = this.getInitialState();
    this.waitFor(
      SessionActions.setInstance,
      this.refreshData
    );
    this.setLoadingStates();
  },

  sendHostingAnalytics(type, payload) {
    window.analytics.track('Used Dashboard Sockets API', {
      type,
      instance: payload.instanceName,
      socketId: payload.label,
      socket: 'hosting'
    });
  },

  setHosting(data) {
    this.data.items = _.forEach(data, this.prepareHosting);
    this.trigger(this.data);
  },

  refreshData() {
    Actions.fetchHostings();
  },

  onFetchHostingsCompleted(data) {
    Actions.setHosting(data);
  },

  onCreateHostingCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('add', payload);
  },

  onUpdateHostingCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('edit', payload);
  },

  onRemoveHostingsCompleted(payload) {
    this.refreshData();
    this.sendHostingAnalytics('delete', payload);
  }
});


Include keyBindingsReducer is initial reducers.

Part of STRPCORE-2.

--- src/initialReducers.js
+++ src/initialReducers.js
@@ -1,10 +1,12 @@
 import { reducer as form } from 'redux-form';
 import okapiReducer from './okapiReducer';
 import { discoveryReducer } from './discoverServices';
+import { keyBindingsReducer } from './discoverKeyBindings';

 export default {
   // TODO: here's where you'd pull in a reducer to handle Okapi actions like auth
   okapi: okapiReducer,
   discovery: discoveryReducer,
+  bindings: keyBindingsReducer,
   form,
 };

<|original_code|>
import { reducer as form } from 'redux-form';
import okapiReducer from './okapiReducer';
import { discoveryReducer } from './discoverServices';

export default {
  // TODO: here's where you'd pull in a reducer to handle Okapi actions like auth
  okapi: okapiReducer,
  discovery: discoveryReducer,
  form,
};

<|edits_diff|>
--- src/initialReducers.js
+++ src/initialReducers.js
@@ -1,6 +1,7 @@
 import { reducer as form } from 'redux-form';
 import okapiReducer from './okapiReducer';
 import { discoveryReducer } from './discoverServices';
+import { keyBindingsReducer } from './discoverKeyBindings';

 export default {
   // TODO: here's where you'd pull in a reducer to handle Okapi actions like auth
<|current_version|>
import { reducer as form } from 'redux-form';
import okapiReducer from './okapiReducer';
import { discoveryReducer } from './discoverServices';
import { keyBindingsReducer } from './discoverKeyBindings';

export default {
  // TODO: here's where you'd pull in a reducer to handle Okapi actions like auth
  okapi: okapiReducer,
  discovery: discoveryReducer,
  form,
};

<|next_version|>
import { reducer as form } from 'redux-form';
import okapiReducer from './okapiReducer';
import { discoveryReducer } from './discoverServices';
import { keyBindingsReducer } from './discoverKeyBindings';

export default {
  // TODO: here's where you'd pull in a reducer to handle Okapi actions like auth
  okapi: okapiReducer,
  discovery: discoveryReducer,
  bindings: keyBindingsReducer,
  form,
};


Add route for creating processes.

Add route for creating processes.

--- backend/server/resources/projects-routes.js
+++ backend/server/resources/projects-routes.js
@@ -6,8 +6,10 @@
     let router = require('koa-router')();
     let projects = require('./projects')(model.projects);
     let samples = require('./samples')(model.samples, schema);
+    let processes = require('./processes')(model.processes, schema);

     router.get('/projects', projects.all);
+    router.post('/projects/:project_id/processes', validateProjectAccess, processes.create);
     router.post('/projects/:project_id/samples', validateProjectAccess, samples.create);
     router.put('/projects/:project_id/samples/:sample_id', validateProjectAccess, samples.update);

<|original_code|>
module.exports = function(model) {
    'use strict';

    let validateProjectAccess = require('./project-access')(model.access);
    let schema = require('.././schema')(model);
    let router = require('koa-router')();
    let projects = require('./projects')(model.projects);
    let samples = require('./samples')(model.samples, schema);

    router.get('/projects', projects.all);
    router.post('/projects/:project_id/samples', validateProjectAccess, samples.create);
    router.put('/projects/:project_id/samples/:sample_id', validateProjectAccess, samples.update);

    return router;
};

<|edits_diff|>
--- backend/server/resources/projects-routes.js
+++ backend/server/resources/projects-routes.js
@@ -6,6 +6,7 @@
     let router = require('koa-router')();
     let projects = require('./projects')(model.projects);
     let samples = require('./samples')(model.samples, schema);
+    let processes = require('./processes')(model.processes, schema);

     router.get('/projects', projects.all);
     router.post('/projects/:project_id/samples', validateProjectAccess, samples.create);
<|current_version|>
module.exports = function(model) {
    'use strict';

    let validateProjectAccess = require('./project-access')(model.access);
    let schema = require('.././schema')(model);
    let router = require('koa-router')();
    let projects = require('./projects')(model.projects);
    let samples = require('./samples')(model.samples, schema);
    let processes = require('./processes')(model.processes, schema);

    router.get('/projects', projects.all);
    router.post('/projects/:project_id/samples', validateProjectAccess, samples.create);
    router.put('/projects/:project_id/samples/:sample_id', validateProjectAccess, samples.update);

    return router;
};

<|next_version|>
module.exports = function(model) {
    'use strict';

    let validateProjectAccess = require('./project-access')(model.access);
    let schema = require('.././schema')(model);
    let router = require('koa-router')();
    let projects = require('./projects')(model.projects);
    let samples = require('./samples')(model.samples, schema);
    let processes = require('./processes')(model.processes, schema);

    router.get('/projects', projects.all);
    router.post('/projects/:project_id/processes', validateProjectAccess, processes.create);
    router.post('/projects/:project_id/samples', validateProjectAccess, samples.create);
    router.put('/projects/:project_id/samples/:sample_id', validateProjectAccess, samples.update);

    return router;
};


Set both url and uri in config for cordova create

With changes related to CB-6776 cordova now expects the urls for custom
platform files to be called url rather than uri. Setting both here
so that the current released version of cordova-lib and the future ones
can both use it. Should remove the uri once we release the next version
of lib.

--- src/default-config.js
+++ src/default-config.js
@@ -9,9 +9,12 @@
         ],
     lib: {
       android: {
+        // TODO: Remove uri here and below after cordova-lib@0.21.7 is released.
+        uri: path.join(ccaRoot, 'cordova', 'cordova-android'),
         url: path.join(ccaRoot, 'cordova', 'cordova-android')
       },
       ios: {
+        uri: path.join(ccaRoot, 'cordova', 'cordova-ios'),
         url: path.join(ccaRoot, 'cordova', 'cordova-ios')
       }
     }

<|original_code|>
var path = require('path');

module.exports = exports = function defaultConfig(ccaRoot) {
  return {
    plugin_search_path: [
        path.join(ccaRoot, 'cordova'),
        path.join(ccaRoot, 'cordova', 'cordova-plugins'),
        path.join(ccaRoot, 'chrome-cordova', 'plugins'),
        ],
    lib: {
      android: {
        url: path.join(ccaRoot, 'cordova', 'cordova-android')
      },
      ios: {
        url: path.join(ccaRoot, 'cordova', 'cordova-ios')
      }
    }
  };
};

<|edits_diff|>
--- src/default-config.js
+++ src/default-config.js
@@ -9,6 +9,8 @@
         ],
     lib: {
       android: {
+        // TODO: Remove uri here and below after cordova-lib@0.21.7 is released.
+        uri: path.join(ccaRoot, 'cordova', 'cordova-android'),
         url: path.join(ccaRoot, 'cordova', 'cordova-android')
       },
       ios: {
<|current_version|>
var path = require('path');

module.exports = exports = function defaultConfig(ccaRoot) {
  return {
    plugin_search_path: [
        path.join(ccaRoot, 'cordova'),
        path.join(ccaRoot, 'cordova', 'cordova-plugins'),
        path.join(ccaRoot, 'chrome-cordova', 'plugins'),
        ],
    lib: {
      android: {
        // TODO: Remove uri here and below after cordova-lib@0.21.7 is released.
        uri: path.join(ccaRoot, 'cordova', 'cordova-android'),
        url: path.join(ccaRoot, 'cordova', 'cordova-android')
      },
      ios: {
        url: path.join(ccaRoot, 'cordova', 'cordova-ios')
      }
    }
  };
};

<|next_version|>
var path = require('path');

module.exports = exports = function defaultConfig(ccaRoot) {
  return {
    plugin_search_path: [
        path.join(ccaRoot, 'cordova'),
        path.join(ccaRoot, 'cordova', 'cordova-plugins'),
        path.join(ccaRoot, 'chrome-cordova', 'plugins'),
        ],
    lib: {
      android: {
        // TODO: Remove uri here and below after cordova-lib@0.21.7 is released.
        uri: path.join(ccaRoot, 'cordova', 'cordova-android'),
        url: path.join(ccaRoot, 'cordova', 'cordova-android')
      },
      ios: {
        uri: path.join(ccaRoot, 'cordova', 'cordova-ios'),
        url: path.join(ccaRoot, 'cordova', 'cordova-ios')
      }
    }
  };
};


Add version updater and server health messages

--- server/webapp/WEB-INF/rails.new/webpack/single_page_apps/artifact_stores.js
+++ server/webapp/WEB-INF/rails.new/webpack/single_page_apps/artifact_stores.js
@@ -17,10 +17,13 @@
 const $                    = require('jquery');
 const m                    = require('mithril');
 const ArtifactStoresWidget = require('views/artifact_stores/artifact_stores_widget');
+const VersionUpdater       = require('models/shared/version_updater');
+require('helpers/server_health_messages_helper');
 require('foundation-sites');

 $(() => {
   $(document).foundation();
+  new VersionUpdater().update();

   m.mount($("#artifact-stores").get(0), ArtifactStoresWidget);

<|original_code|>
/*
 * Copyright 2018 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const $                    = require('jquery');
const m                    = require('mithril');
const ArtifactStoresWidget = require('views/artifact_stores/artifact_stores_widget');
require('foundation-sites');

$(() => {
  $(document).foundation();

  m.mount($("#artifact-stores").get(0), ArtifactStoresWidget);

});

<|edits_diff|>
--- server/webapp/WEB-INF/rails.new/webpack/single_page_apps/artifact_stores.js
+++ server/webapp/WEB-INF/rails.new/webpack/single_page_apps/artifact_stores.js
@@ -17,6 +17,8 @@
 const $                    = require('jquery');
 const m                    = require('mithril');
 const ArtifactStoresWidget = require('views/artifact_stores/artifact_stores_widget');
+const VersionUpdater       = require('models/shared/version_updater');
+require('helpers/server_health_messages_helper');
 require('foundation-sites');

 $(() => {
<|current_version|>
/*
 * Copyright 2018 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const $                    = require('jquery');
const m                    = require('mithril');
const ArtifactStoresWidget = require('views/artifact_stores/artifact_stores_widget');
const VersionUpdater       = require('models/shared/version_updater');
require('helpers/server_health_messages_helper');
require('foundation-sites');

$(() => {
  $(document).foundation();

  m.mount($("#artifact-stores").get(0), ArtifactStoresWidget);

});

<|next_version|>
/*
 * Copyright 2018 ThoughtWorks, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const $                    = require('jquery');
const m                    = require('mithril');
const ArtifactStoresWidget = require('views/artifact_stores/artifact_stores_widget');
const VersionUpdater       = require('models/shared/version_updater');
require('helpers/server_health_messages_helper');
require('foundation-sites');

$(() => {
  $(document).foundation();
  new VersionUpdater().update();

  m.mount($("#artifact-stores").get(0), ArtifactStoresWidget);

});


Add link to github on about us page

Add link to github on about us page

--- src/components/AboutUs.js
+++ src/components/AboutUs.js
@@ -1,11 +1,14 @@
 // Page to create/About Us

 import React from 'react';
+import { Link } from 'react-router-dom';
+import links from '../constants/links';

 const AboutUs = (props) => {
   return (

AboutUs page

+      Check us out on Github!

   );
 };

<|original_code|>
// Page to create/About Us

import React from 'react';

const AboutUs = (props) => {
  return (

AboutUs page

  );
};

export default AboutUs;
<|edits_diff|>
--- src/components/AboutUs.js
+++ src/components/AboutUs.js
@@ -1,6 +1,8 @@
 // Page to create/About Us

 import React from 'react';
+import { Link } from 'react-router-dom';
+import links from '../constants/links';

 const AboutUs = (props) => {
   return (
<|current_version|>
// Page to create/About Us

import React from 'react';
import { Link } from 'react-router-dom';
import links from '../constants/links';

const AboutUs = (props) => {
  return (

AboutUs page

  );
};

export default AboutUs;
<|next_version|>
// Page to create/About Us

import React from 'react';
import { Link } from 'react-router-dom';
import links from '../constants/links';

const AboutUs = (props) => {
  return (

AboutUs page

      Check us out on Github!

  );
};

export default AboutUs;


SFX: Fix issue where sound effects could be loaded more than once

--- src/core/sfx.js
+++ src/core/sfx.js
@@ -11,9 +11,15 @@
     },

     load: function(soundId) {
+        if (typeof Sfx.sounds[soundId] != 'undefined') {
+            return Sfx.sounds[soundId];
+        }
+
         console.info('[SFX] Loading sound effect', soundId);
+
         Sfx.sounds[soundId] = new Audio('assets/sfx/' + soundId + '.wav');
         Sfx.sounds[soundId].load();
+
         return Sfx.sounds[soundId];
     },

<|original_code|>
var Sfx = {
    sounds: { },

    preload: function() {
        this.load('pickup_donut');
        this.load('pickup_veggie');
        this.load('omnom');
        this.load('burp');
        this.load('running');
        this.load('puke');
    },

    load: function(soundId) {
        console.info('[SFX] Loading sound effect', soundId);
        Sfx.sounds[soundId] = new Audio('assets/sfx/' + soundId + '.wav');
        Sfx.sounds[soundId].load();
        return Sfx.sounds[soundId];
    },

    play: function(soundId) {
        if (typeof Sfx.sounds[soundId] == 'undefined') {
            Sfx.load(soundId);
        } else {
            Sfx.sounds[soundId].load(); // call load() every time to fix Chrome issue where sound only plays first time
        }

        Sfx.sounds[soundId].play();
    },

    pickupDonut: function ()    { this.play('pickup_donut'); },
    pickupVeggie: function ()   { this.play('pickup_veggie'); },
    omNom: function()           { this.play('omnom'); },
    burp: function()            { this.play('burp'); },
    puke: function()            { this.play('puke'); }
};
<|edits_diff|>
--- src/core/sfx.js
+++ src/core/sfx.js
@@ -11,7 +11,12 @@
     },

     load: function(soundId) {
+        if (typeof Sfx.sounds[soundId] != 'undefined') {
+            return Sfx.sounds[soundId];
+        }
+
         console.info('[SFX] Loading sound effect', soundId);
+
         Sfx.sounds[soundId] = new Audio('assets/sfx/' + soundId + '.wav');
         Sfx.sounds[soundId].load();
         return Sfx.sounds[soundId];
<|current_version|>
var Sfx = {
    sounds: { },

    preload: function() {
        this.load('pickup_donut');
        this.load('pickup_veggie');
        this.load('omnom');
        this.load('burp');
        this.load('running');
        this.load('puke');
    },

    load: function(soundId) {
        if (typeof Sfx.sounds[soundId] != 'undefined') {
            return Sfx.sounds[soundId];
        }

        console.info('[SFX] Loading sound effect', soundId);

        Sfx.sounds[soundId] = new Audio('assets/sfx/' + soundId + '.wav');
        Sfx.sounds[soundId].load();
        return Sfx.sounds[soundId];
    },

    play: function(soundId) {
        if (typeof Sfx.sounds[soundId] == 'undefined') {
            Sfx.load(soundId);
        } else {
            Sfx.sounds[soundId].load(); // call load() every time to fix Chrome issue where sound only plays first time
        }

        Sfx.sounds[soundId].play();
    },

    pickupDonut: function ()    { this.play('pickup_donut'); },
    pickupVeggie: function ()   { this.play('pickup_veggie'); },
    omNom: function()           { this.play('omnom'); },
    burp: function()            { this.play('burp'); },
    puke: function()            { this.play('puke'); }
};
<|next_version|>
var Sfx = {
    sounds: { },

    preload: function() {
        this.load('pickup_donut');
        this.load('pickup_veggie');
        this.load('omnom');
        this.load('burp');
        this.load('running');
        this.load('puke');
    },

    load: function(soundId) {
        if (typeof Sfx.sounds[soundId] != 'undefined') {
            return Sfx.sounds[soundId];
        }

        console.info('[SFX] Loading sound effect', soundId);

        Sfx.sounds[soundId] = new Audio('assets/sfx/' + soundId + '.wav');
        Sfx.sounds[soundId].load();

        return Sfx.sounds[soundId];
    },

    play: function(soundId) {
        if (typeof Sfx.sounds[soundId] == 'undefined') {
            Sfx.load(soundId);
        } else {
            Sfx.sounds[soundId].load(); // call load() every time to fix Chrome issue where sound only plays first time
        }

        Sfx.sounds[soundId].play();
    },

    pickupDonut: function ()    { this.play('pickup_donut'); },
    pickupVeggie: function ()   { this.play('pickup_veggie'); },
    omNom: function()           { this.play('omnom'); },
    burp: function()            { this.play('burp'); },
    puke: function()            { this.play('puke'); }
};


Add client side link action

Add client side link action

--- next/pages/index.js
+++ next/pages/index.js
@@ -1,5 +1,11 @@
+// This is the Link API
+import Link from 'next/link'
+
 const Index = () => (

+    <Link href="/about">
+      About Page
+    </Link>

Hello Next.js

 )

<|original_code|>
const Index = () => (

Hello Next.js

)

export default Index

<|edits_diff|>
--- next/pages/index.js
+++ next/pages/index.js
@@ -1,3 +1,6 @@
+// This is the Link API
+import Link from 'next/link'
+
 const Index = () => (

Hello Next.js

<|current_version|>
// This is the Link API
import Link from 'next/link'

const Index = () => (

Hello Next.js

)

export default Index

<|next_version|>
// This is the Link API
import Link from 'next/link'

const Index = () => (

    <Link href="/about">
      About Page
    </Link>

Hello Next.js

)

export default Index


Use normalizer as plugin in example.

Use normalizer as plugin in example.

--- example/app.js
+++ example/app.js
@@ -4,6 +4,7 @@

 var Zeditor = require('zeditor');
 var ZeditorPaste = require('zeditor-paste');
+var ZeditorNormalizer = require('zeditor-normalizer');

 /**
  * Get DOM nodes
@@ -16,6 +17,7 @@
  */

 Zeditor(editorNode);
+ZeditorNormalizer(editorNode);
 ZeditorPaste(editorNode);

 /**

<|original_code|>
/**
 * Module dependencies
 */

var Zeditor = require('zeditor');
var ZeditorPaste = require('zeditor-paste');

/**
 * Get DOM nodes
 */

var editorNode = document.getElementById('editor');

/**
 * Instantiate editor
 */

Zeditor(editorNode);
ZeditorPaste(editorNode);

/**
 * Other functionality
 */

Zeditor(editorNode).on('error', function (err) {
  // for now, any "error" event log to the console
  console.error('editor "error" event: %o', err);
});

var outputNode = document.getElementById('output');
var showEditorButtonNode = document.getElementById('showEditor');
var showOutputButtonNode = document.getElementById('showOutput');

showEditorButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'none';
  editorNode.style.display = 'block';

  showOutputButtonNode.style.display = 'inline';
  outputNode.style.display = 'none';
}, false);

showOutputButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'inline';
  editorNode.style.display = 'none';

  showOutputButtonNode.style.display = 'none';
  outputNode.style.display = 'block';

  outputNode.textContent = editor.serializer.serializeRoot();
}, false);
<|edits_diff|>
--- example/app.js
+++ example/app.js
@@ -4,6 +4,7 @@

 var Zeditor = require('zeditor');
 var ZeditorPaste = require('zeditor-paste');
+var ZeditorNormalizer = require('zeditor-normalizer');

 /**
  * Get DOM nodes
<|current_version|>
/**
 * Module dependencies
 */

var Zeditor = require('zeditor');
var ZeditorPaste = require('zeditor-paste');
var ZeditorNormalizer = require('zeditor-normalizer');

/**
 * Get DOM nodes
 */

var editorNode = document.getElementById('editor');

/**
 * Instantiate editor
 */

Zeditor(editorNode);
ZeditorPaste(editorNode);

/**
 * Other functionality
 */

Zeditor(editorNode).on('error', function (err) {
  // for now, any "error" event log to the console
  console.error('editor "error" event: %o', err);
});

var outputNode = document.getElementById('output');
var showEditorButtonNode = document.getElementById('showEditor');
var showOutputButtonNode = document.getElementById('showOutput');

showEditorButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'none';
  editorNode.style.display = 'block';

  showOutputButtonNode.style.display = 'inline';
  outputNode.style.display = 'none';
}, false);

showOutputButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'inline';
  editorNode.style.display = 'none';

  showOutputButtonNode.style.display = 'none';
  outputNode.style.display = 'block';

  outputNode.textContent = editor.serializer.serializeRoot();
}, false);
<|next_version|>
/**
 * Module dependencies
 */

var Zeditor = require('zeditor');
var ZeditorPaste = require('zeditor-paste');
var ZeditorNormalizer = require('zeditor-normalizer');

/**
 * Get DOM nodes
 */

var editorNode = document.getElementById('editor');

/**
 * Instantiate editor
 */

Zeditor(editorNode);
ZeditorNormalizer(editorNode);
ZeditorPaste(editorNode);

/**
 * Other functionality
 */

Zeditor(editorNode).on('error', function (err) {
  // for now, any "error" event log to the console
  console.error('editor "error" event: %o', err);
});

var outputNode = document.getElementById('output');
var showEditorButtonNode = document.getElementById('showEditor');
var showOutputButtonNode = document.getElementById('showOutput');

showEditorButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'none';
  editorNode.style.display = 'block';

  showOutputButtonNode.style.display = 'inline';
  outputNode.style.display = 'none';
}, false);

showOutputButtonNode.addEventListener('click', function (e) {
  e.preventDefault();

  showEditorButtonNode.style.display = 'inline';
  editorNode.style.display = 'none';

  showOutputButtonNode.style.display = 'none';
  outputNode.style.display = 'block';

  outputNode.textContent = editor.serializer.serializeRoot();
}, false);


Set timezone explicitly to UTC on server-side

--- server/database/config.js
+++ server/database/config.js
@@ -6,17 +6,22 @@
 const url = process.env.DATABASE_URL
 const dialect = process.env.DATABASE_DIALECT || 'postgres'

+const timezone = '+00:00' // UTC
+
 module.exports = {
   development: {
     url,
     dialect,
+    timezone,
   },
   staging: {
     url,
     dialect,
+    timezone,
   },
   production: {
     url,
     dialect,
+    timezone,
   },
 }

<|original_code|>
const dotenv = require('dotenv')
const path = require('path')

dotenv.config({ path: path.join(__dirname, '..', '..', '.env') })

const url = process.env.DATABASE_URL
const dialect = process.env.DATABASE_DIALECT || 'postgres'

module.exports = {
  development: {
    url,
    dialect,
  },
  staging: {
    url,
    dialect,
  },
  production: {
    url,
    dialect,
  },
}

<|edits_diff|>
--- server/database/config.js
+++ server/database/config.js
@@ -6,14 +6,18 @@
 const url = process.env.DATABASE_URL
 const dialect = process.env.DATABASE_DIALECT || 'postgres'

+const timezone = '+00:00' // UTC
+
 module.exports = {
   development: {
     url,
     dialect,
+    timezone,
   },
   staging: {
     url,
     dialect,
+    timezone,
   },
   production: {
     url,
<|current_version|>
const dotenv = require('dotenv')
const path = require('path')

dotenv.config({ path: path.join(__dirname, '..', '..', '.env') })

const url = process.env.DATABASE_URL
const dialect = process.env.DATABASE_DIALECT || 'postgres'

const timezone = '+00:00' // UTC

module.exports = {
  development: {
    url,
    dialect,
    timezone,
  },
  staging: {
    url,
    dialect,
    timezone,
  },
  production: {
    url,
    dialect,
  },
}

<|next_version|>
const dotenv = require('dotenv')
const path = require('path')

dotenv.config({ path: path.join(__dirname, '..', '..', '.env') })

const url = process.env.DATABASE_URL
const dialect = process.env.DATABASE_DIALECT || 'postgres'

const timezone = '+00:00' // UTC

module.exports = {
  development: {
    url,
    dialect,
    timezone,
  },
  staging: {
    url,
    dialect,
    timezone,
  },
  production: {
    url,
    dialect,
    timezone,
  },
}


Use match() in meteor methods to be able to use the "audit-argument-checks" MDG package

--- logglyMeteorMethods.js
+++ logglyMeteorMethods.js
@@ -12,26 +12,41 @@

 Meteor.methods({
   logglyLog: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.log(param, tag);
     }
   },
   logglyTrace: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.trace(param, tag);
     }
   },
   logglyInfo: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.info(param, tag);
     }
   },
   logglyWarn:  function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.warn(param, tag);
     }
   },
   logglyError:  function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()) {
       Logger.error(param, tag);
     }

<|original_code|>
/***
 * loggerSet - checks to see if the Logger object has been created on server
 * @returns {boolean} - return true if the Logger object has been created on server
 */
var loggerSet = function () {
  if (typeof Logger !== 'undefined' && Logger !== null) {
    return true;
  }
  console.log('Logger object was not created on the Meteor Server');
  return false;
};

Meteor.methods({
  logglyLog: function(param, tag) {
    if (loggerSet()){
      Logger.log(param, tag);
    }
  },
  logglyTrace: function(param, tag) {
    if (loggerSet()){
      Logger.trace(param, tag);
    }
  },
  logglyInfo: function(param, tag) {
    if (loggerSet()){
      Logger.info(param, tag);
    }
  },
  logglyWarn:  function(param, tag) {
    if (loggerSet()){
      Logger.warn(param, tag);
    }
  },
  logglyError:  function(param, tag) {
    if (loggerSet()) {
      Logger.error(param, tag);
    }
  }
});

<|edits_diff|>
--- logglyMeteorMethods.js
+++ logglyMeteorMethods.js
@@ -12,21 +12,33 @@

 Meteor.methods({
   logglyLog: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.log(param, tag);
     }
   },
   logglyTrace: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.trace(param, tag);
     }
   },
   logglyInfo: function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.info(param, tag);
     }
   },
   logglyWarn:  function(param, tag) {
+    check(param,Object);
+    check(tag,Match.Optional([String]));
+
     if (loggerSet()){
       Logger.warn(param, tag);
     }
<|current_version|>
/***
 * loggerSet - checks to see if the Logger object has been created on server
 * @returns {boolean} - return true if the Logger object has been created on server
 */
var loggerSet = function () {
  if (typeof Logger !== 'undefined' && Logger !== null) {
    return true;
  }
  console.log('Logger object was not created on the Meteor Server');
  return false;
};

Meteor.methods({
  logglyLog: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.log(param, tag);
    }
  },
  logglyTrace: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.trace(param, tag);
    }
  },
  logglyInfo: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.info(param, tag);
    }
  },
  logglyWarn:  function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.warn(param, tag);
    }
  },
  logglyError:  function(param, tag) {
    if (loggerSet()) {
      Logger.error(param, tag);
    }
  }
});

<|next_version|>
/***
 * loggerSet - checks to see if the Logger object has been created on server
 * @returns {boolean} - return true if the Logger object has been created on server
 */
var loggerSet = function () {
  if (typeof Logger !== 'undefined' && Logger !== null) {
    return true;
  }
  console.log('Logger object was not created on the Meteor Server');
  return false;
};

Meteor.methods({
  logglyLog: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.log(param, tag);
    }
  },
  logglyTrace: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.trace(param, tag);
    }
  },
  logglyInfo: function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.info(param, tag);
    }
  },
  logglyWarn:  function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()){
      Logger.warn(param, tag);
    }
  },
  logglyError:  function(param, tag) {
    check(param,Object);
    check(tag,Match.Optional([String]));

    if (loggerSet()) {
      Logger.error(param, tag);
    }
  }
});


Add config for client ID for premium g maps users

--- index.js
+++ index.js
@@ -10,10 +10,13 @@
          placeAutocompleteConfig = config['place-autocomplete'] || {},
          params = [],
          exclude = placeAutocompleteConfig.exclude,
+         client = placeAutocompleteConfig.client,
          key = placeAutocompleteConfig.key;
       if (!exclude) {
         if (key)
           params.push('key=' + encodeURIComponent(key));
+        if (client)
+          params.push('client=' + encodeURIComponent(client) + '&v=3.24');
         src += '?' + params.join('&') + "&libraries=places";
         content = '<script type="text/javascript" src="' + src + '"></script>';
       }

<|original_code|>
/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-place-autocomplete',
  contentFor: function(type, config) {
    var content = '';
    if (type === 'body-footer') {
      var src = "//maps.googleapis.com/maps/api/js",
         placeAutocompleteConfig = config['place-autocomplete'] || {},
         params = [],
         exclude = placeAutocompleteConfig.exclude,
         key = placeAutocompleteConfig.key;
      if (!exclude) {
        if (key)
          params.push('key=' + encodeURIComponent(key));
        src += '?' + params.join('&') + "&libraries=places";
        content = '<script type="text/javascript" src="' + src + '"></script>';
      }
    }
    return content;
  }
};

<|edits_diff|>
--- index.js
+++ index.js
@@ -10,6 +10,7 @@
          placeAutocompleteConfig = config['place-autocomplete'] || {},
          params = [],
          exclude = placeAutocompleteConfig.exclude,
+         client = placeAutocompleteConfig.client,
          key = placeAutocompleteConfig.key;
       if (!exclude) {
         if (key)
<|current_version|>
/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-place-autocomplete',
  contentFor: function(type, config) {
    var content = '';
    if (type === 'body-footer') {
      var src = "//maps.googleapis.com/maps/api/js",
         placeAutocompleteConfig = config['place-autocomplete'] || {},
         params = [],
         exclude = placeAutocompleteConfig.exclude,
         client = placeAutocompleteConfig.client,
         key = placeAutocompleteConfig.key;
      if (!exclude) {
        if (key)
          params.push('key=' + encodeURIComponent(key));
        src += '?' + params.join('&') + "&libraries=places";
        content = '<script type="text/javascript" src="' + src + '"></script>';
      }
    }
    return content;
  }
};

<|next_version|>
/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-place-autocomplete',
  contentFor: function(type, config) {
    var content = '';
    if (type === 'body-footer') {
      var src = "//maps.googleapis.com/maps/api/js",
         placeAutocompleteConfig = config['place-autocomplete'] || {},
         params = [],
         exclude = placeAutocompleteConfig.exclude,
         client = placeAutocompleteConfig.client,
         key = placeAutocompleteConfig.key;
      if (!exclude) {
        if (key)
          params.push('key=' + encodeURIComponent(key));
        if (client)
          params.push('client=' + encodeURIComponent(client) + '&v=3.24');
        src += '?' + params.join('&') + "&libraries=places";
        content = '<script type="text/javascript" src="' + src + '"></script>';
      }
    }
    return content;
  }
};


Add comment for timer.unref check

Add comment for timer.unref check

--- index.js
+++ index.js
@@ -15,9 +15,11 @@

     return Promise.race([timeoutPromise, promise])
         .then(function (value) {
+            // For browser support: timer.unref is only available in Node.
             if (timer.unref) timer.unref();
             return value;
         }, function (error) {
+            // For browser support: timer.unref is only available in Node.
             if (timer.unref) timer.unref();
             throw error;
         });

<|original_code|>
module.exports = function (promise, timeout, opts) {
    var Promise     = promise.constructor;
    var rejectWith  = opts && opts.rejectWith;
    var resolveWith = opts && opts.resolveWith;
    var timer;

    var timeoutPromise = new Promise(function (resolve, reject) {
        timer = setTimeout(function () {
            if (rejectWith !== void 0)
                reject(rejectWith);
            else
                resolve(resolveWith);
        }, timeout);
    });

    return Promise.race([timeoutPromise, promise])
        .then(function (value) {
            if (timer.unref) timer.unref();
            return value;
        }, function (error) {
            if (timer.unref) timer.unref();
            throw error;
        });
};

<|edits_diff|>
--- index.js
+++ index.js
@@ -15,6 +15,7 @@

     return Promise.race([timeoutPromise, promise])
         .then(function (value) {
+            // For browser support: timer.unref is only available in Node.
             if (timer.unref) timer.unref();
             return value;
         }, function (error) {
<|current_version|>
module.exports = function (promise, timeout, opts) {
    var Promise     = promise.constructor;
    var rejectWith  = opts && opts.rejectWith;
    var resolveWith = opts && opts.resolveWith;
    var timer;

    var timeoutPromise = new Promise(function (resolve, reject) {
        timer = setTimeout(function () {
            if (rejectWith !== void 0)
                reject(rejectWith);
            else
                resolve(resolveWith);
        }, timeout);
    });

    return Promise.race([timeoutPromise, promise])
        .then(function (value) {
            // For browser support: timer.unref is only available in Node.
            if (timer.unref) timer.unref();
            return value;
        }, function (error) {
            if (timer.unref) timer.unref();
            throw error;
        });
};

<|next_version|>
module.exports = function (promise, timeout, opts) {
    var Promise     = promise.constructor;
    var rejectWith  = opts && opts.rejectWith;
    var resolveWith = opts && opts.resolveWith;
    var timer;

    var timeoutPromise = new Promise(function (resolve, reject) {
        timer = setTimeout(function () {
            if (rejectWith !== void 0)
                reject(rejectWith);
            else
                resolve(resolveWith);
        }, timeout);
    });

    return Promise.race([timeoutPromise, promise])
        .then(function (value) {
            // For browser support: timer.unref is only available in Node.
            if (timer.unref) timer.unref();
            return value;
        }, function (error) {
            // For browser support: timer.unref is only available in Node.
            if (timer.unref) timer.unref();
            throw error;
        });
};


Replace file extension when optimizing

Replace file extension when optimizing

--- index.js
+++ index.js
@@ -2,6 +2,7 @@

 var ExecBuffer = require('exec-buffer');
 var imageType = require('image-type');
+var path = require('path');
 var through = require('through2');
 var webp = require('cwebp-bin').path;

@@ -42,6 +43,11 @@
 					return;
 				}

+				if (file.path && typeof file.path === 'string') {
+					var name = path.basename(file.path, path.extname(file.path)) + '.webp';
+					file.path = path.join(path.dirname(file.path), name);
+				}
+
 				file.contents = buf;
 				cb(null, file);
 			});

<|original_code|>
'use strict';

var ExecBuffer = require('exec-buffer');
var imageType = require('image-type');
var through = require('through2');
var webp = require('cwebp-bin').path;

/**
 * webp imagemin plugin
 *
 * @param {Object} opts
 * @api public
 */

module.exports = function (opts) {
	opts = opts || {};

	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			cb(null, file);
			return;
		}

		if (file.isStream()) {
			cb(new Error('Streaming is not supported'));
			return;
		}

		if (['jpg', 'png', 'tif'].indexOf(imageType(file.contents)) === -1) {
			cb(null, file);
			return;
		}

		var exec = new ExecBuffer();
		var args = ['-quiet'];

		exec
			.use(webp, args.concat([exec.src(), '-o', exec.dest()]))
			.run(file.contents, function (err, buf) {
				if (err) {
					cb(err);
					return;
				}

				file.contents = buf;
				cb(null, file);
			});
	});
};

<|edits_diff|>
--- index.js
+++ index.js
@@ -2,6 +2,7 @@

 var ExecBuffer = require('exec-buffer');
 var imageType = require('image-type');
+var path = require('path');
 var through = require('through2');
 var webp = require('cwebp-bin').path;

<|current_version|>
'use strict';

var ExecBuffer = require('exec-buffer');
var imageType = require('image-type');
var path = require('path');
var through = require('through2');
var webp = require('cwebp-bin').path;

/**
 * webp imagemin plugin
 *
 * @param {Object} opts
 * @api public
 */

module.exports = function (opts) {
	opts = opts || {};

	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			cb(null, file);
			return;
		}

		if (file.isStream()) {
			cb(new Error('Streaming is not supported'));
			return;
		}

		if (['jpg', 'png', 'tif'].indexOf(imageType(file.contents)) === -1) {
			cb(null, file);
			return;
		}

		var exec = new ExecBuffer();
		var args = ['-quiet'];

		exec
			.use(webp, args.concat([exec.src(), '-o', exec.dest()]))
			.run(file.contents, function (err, buf) {
				if (err) {
					cb(err);
					return;
				}

				file.contents = buf;
				cb(null, file);
			});
	});
};

<|next_version|>
'use strict';

var ExecBuffer = require('exec-buffer');
var imageType = require('image-type');
var path = require('path');
var through = require('through2');
var webp = require('cwebp-bin').path;

/**
 * webp imagemin plugin
 *
 * @param {Object} opts
 * @api public
 */

module.exports = function (opts) {
	opts = opts || {};

	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			cb(null, file);
			return;
		}

		if (file.isStream()) {
			cb(new Error('Streaming is not supported'));
			return;
		}

		if (['jpg', 'png', 'tif'].indexOf(imageType(file.contents)) === -1) {
			cb(null, file);
			return;
		}

		var exec = new ExecBuffer();
		var args = ['-quiet'];

		exec
			.use(webp, args.concat([exec.src(), '-o', exec.dest()]))
			.run(file.contents, function (err, buf) {
				if (err) {
					cb(err);
					return;
				}

				if (file.path && typeof file.path === 'string') {
					var name = path.basename(file.path, path.extname(file.path)) + '.webp';
					file.path = path.join(path.dirname(file.path), name);
				}

				file.contents = buf;
				cb(null, file);
			});
	});
};


Hide any alerts when user starts to interact with "Features" page again after completing an action.

--- ode/public/js/ode.js
+++ ode/public/js/ode.js
@@ -6,11 +6,13 @@
   $("#new-feature-button").on("click", function(event) {
     event.preventDefault();
     $(this).hide();
+    $(".alert").hide();
     $("#interaction-block").html($("#new-feature").html());
   });

   $(".feature-item").on("click", function(event) {
     event.preventDefault();
+    $(".alert").hide();
     $("#interaction-block").html($("#"+$(this).text()).html());
     $("#new-feature-button").show();
   });

<|original_code|>
$(document).ready(function() {

  $("#new-feature").hide();
  $(".edit-feature").hide();

  $("#new-feature-button").on("click", function(event) {
    event.preventDefault();
    $(this).hide();
    $("#interaction-block").html($("#new-feature").html());
  });

  $(".feature-item").on("click", function(event) {
    event.preventDefault();
    $("#interaction-block").html($("#"+$(this).text()).html());
    $("#new-feature-button").show();
  });

  $("#feature-filter").on("keyup", function(event) {
    // ...
  });

  $("#value-filter").on("keyup", function(event) {
    // ...
  });

});

<|edits_diff|>
--- ode/public/js/ode.js
+++ ode/public/js/ode.js
@@ -6,6 +6,7 @@
   $("#new-feature-button").on("click", function(event) {
     event.preventDefault();
     $(this).hide();
+    $(".alert").hide();
     $("#interaction-block").html($("#new-feature").html());
   });

<|current_version|>
$(document).ready(function() {

  $("#new-feature").hide();
  $(".edit-feature").hide();

  $("#new-feature-button").on("click", function(event) {
    event.preventDefault();
    $(this).hide();
    $(".alert").hide();
    $("#interaction-block").html($("#new-feature").html());
  });

  $(".feature-item").on("click", function(event) {
    event.preventDefault();
    $("#interaction-block").html($("#"+$(this).text()).html());
    $("#new-feature-button").show();
  });

  $("#feature-filter").on("keyup", function(event) {
    // ...
  });

  $("#value-filter").on("keyup", function(event) {
    // ...
  });

});

<|next_version|>
$(document).ready(function() {

  $("#new-feature").hide();
  $(".edit-feature").hide();

  $("#new-feature-button").on("click", function(event) {
    event.preventDefault();
    $(this).hide();
    $(".alert").hide();
    $("#interaction-block").html($("#new-feature").html());
  });

  $(".feature-item").on("click", function(event) {
    event.preventDefault();
    $(".alert").hide();
    $("#interaction-block").html($("#"+$(this).text()).html());
    $("#new-feature-button").show();
  });

  $("#feature-filter").on("keyup", function(event) {
    // ...
  });

  $("#value-filter").on("keyup", function(event) {
    // ...
  });

});


Add option to provide callback for request, ok and error actions

The callbacks are passed dispatch and getState along with the other
arguments.

--- src/createActionAsync.js
+++ src/createActionAsync.js
@@ -18,12 +18,15 @@
   let actionAsync = (...args) => {
     return (dispatch) => {
       dispatch(actions.request(...args));
+      if(options.request.callback) options.request.callback(dispatch, getState, ...args)
       return api(...args)
       .then(res => {
         dispatch(actions.ok(res, ...args))
+        if(options.ok.callback) options.ok.callback(dispatch, getState, res, ...args)
       })
       .catch(err => {
         dispatch(actions.error(err, ...args))
+        if(options.error.callback) options.error.callback(dispatch, getState, err, ...args)
         if(options.rethrow) throw err;
       })
     }

<|original_code|>
import {createAction} from 'redux-act'
import _defaults from 'lodash.defaults';

const defaultOption = {
  request:{},
  ok:{},
  error:{}
}

export default function createActionAsync(description, api, options = defaultOption) {
  _defaults(options, defaultOption);
  let actions = {
    request: createAction(`${description}_REQUEST`, options.request.payloadReducer, options.request.metaReducer),
    ok: createAction(`${description}_OK`, options.ok.payloadReducer, options.ok.metaReducer),
    error: createAction(`${description}_ERROR`, options.error.payloadReducer, options.error.metaReducer)
  }

  let actionAsync = (...args) => {
    return (dispatch) => {
      dispatch(actions.request(...args));
      return api(...args)
      .then(res => {
        dispatch(actions.ok(res, ...args))
      })
      .catch(err => {
        dispatch(actions.error(err, ...args))
        if(options.rethrow) throw err;
      })
    }
  }

  actionAsync.request = actions.request;
  actionAsync.ok = actions.ok;
  actionAsync.error = actions.error;
  return actionAsync;

};

<|edits_diff|>
--- src/createActionAsync.js
+++ src/createActionAsync.js
@@ -18,9 +18,11 @@
   let actionAsync = (...args) => {
     return (dispatch) => {
       dispatch(actions.request(...args));
+      if(options.request.callback) options.request.callback(dispatch, getState, ...args)
       return api(...args)
       .then(res => {
         dispatch(actions.ok(res, ...args))
+        if(options.ok.callback) options.ok.callback(dispatch, getState, res, ...args)
       })
       .catch(err => {
         dispatch(actions.error(err, ...args))
<|current_version|>
import {createAction} from 'redux-act'
import _defaults from 'lodash.defaults';

const defaultOption = {
  request:{},
  ok:{},
  error:{}
}

export default function createActionAsync(description, api, options = defaultOption) {
  _defaults(options, defaultOption);
  let actions = {
    request: createAction(`${description}_REQUEST`, options.request.payloadReducer, options.request.metaReducer),
    ok: createAction(`${description}_OK`, options.ok.payloadReducer, options.ok.metaReducer),
    error: createAction(`${description}_ERROR`, options.error.payloadReducer, options.error.metaReducer)
  }

  let actionAsync = (...args) => {
    return (dispatch) => {
      dispatch(actions.request(...args));
      if(options.request.callback) options.request.callback(dispatch, getState, ...args)
      return api(...args)
      .then(res => {
        dispatch(actions.ok(res, ...args))
        if(options.ok.callback) options.ok.callback(dispatch, getState, res, ...args)
      })
      .catch(err => {
        dispatch(actions.error(err, ...args))
        if(options.rethrow) throw err;
      })
    }
  }

  actionAsync.request = actions.request;
  actionAsync.ok = actions.ok;
  actionAsync.error = actions.error;
  return actionAsync;

};

<|next_version|>
import {createAction} from 'redux-act'
import _defaults from 'lodash.defaults';

const defaultOption = {
  request:{},
  ok:{},
  error:{}
}

export default function createActionAsync(description, api, options = defaultOption) {
  _defaults(options, defaultOption);
  let actions = {
    request: createAction(`${description}_REQUEST`, options.request.payloadReducer, options.request.metaReducer),
    ok: createAction(`${description}_OK`, options.ok.payloadReducer, options.ok.metaReducer),
    error: createAction(`${description}_ERROR`, options.error.payloadReducer, options.error.metaReducer)
  }

  let actionAsync = (...args) => {
    return (dispatch) => {
      dispatch(actions.request(...args));
      if(options.request.callback) options.request.callback(dispatch, getState, ...args)
      return api(...args)
      .then(res => {
        dispatch(actions.ok(res, ...args))
        if(options.ok.callback) options.ok.callback(dispatch, getState, res, ...args)
      })
      .catch(err => {
        dispatch(actions.error(err, ...args))
        if(options.error.callback) options.error.callback(dispatch, getState, err, ...args)
        if(options.rethrow) throw err;
      })
    }
  }

  actionAsync.request = actions.request;
  actionAsync.ok = actions.ok;
  actionAsync.error = actions.error;
  return actionAsync;

};


Add server folder copy to build

Add server folder copy to build

--- webpack.common.js
+++ webpack.common.js
@@ -1,10 +1,12 @@
 const path = require('path');
 const webpack = require('webpack');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
 const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const extractSass = new ExtractTextPlugin({
     filename: '[name].css', // '[name].[contenthash].css'
     // disable: process.env.NODE_ENV === 'development'
 });
+

 module.exports = {
     entry: {
@@ -53,5 +55,8 @@
         //     $: 'jquery',
         //     jQuery: 'jquery'
         // }),
+        new CopyWebpackPlugin([
+            { from: 'server' /*, to: 'server'*/ },
+        ])
     ],
 };

<|original_code|>
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractSass = new ExtractTextPlugin({
    filename: '[name].css', // '[name].[contenthash].css'
    // disable: process.env.NODE_ENV === 'development'
});

module.exports = {
    entry: {
        app: './build/app',
        worker: './build/worker'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        loaders: [{
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env']
                    }
                }
            },
            {
                test: /\.(css|scss)$/,
                use: extractSass.extract({
                    use: [{
                        loader: 'css-loader'
                    }, {
                        loader: 'sass-loader'
                    }],
                    // use style-loader in development
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'url-loader',
                options: {
                    limit: 10000
                }
            },
        ]
    },
    plugins: [
        extractSass,
        // new webpack.ProvidePlugin({
        //     $: 'jquery',
        //     jQuery: 'jquery'
        // }),
    ],
};

<|edits_diff|>
--- webpack.common.js
+++ webpack.common.js
@@ -1,10 +1,12 @@
 const path = require('path');
 const webpack = require('webpack');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
 const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const extractSass = new ExtractTextPlugin({
     filename: '[name].css', // '[name].[contenthash].css'
     // disable: process.env.NODE_ENV === 'development'
 });
+

 module.exports = {
     entry: {
<|current_version|>
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractSass = new ExtractTextPlugin({
    filename: '[name].css', // '[name].[contenthash].css'
    // disable: process.env.NODE_ENV === 'development'
});

module.exports = {
    entry: {
        app: './build/app',
        worker: './build/worker'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        loaders: [{
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env']
                    }
                }
            },
            {
                test: /\.(css|scss)$/,
                use: extractSass.extract({
                    use: [{
                        loader: 'css-loader'
                    }, {
                        loader: 'sass-loader'
                    }],
                    // use style-loader in development
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'url-loader',
                options: {
                    limit: 10000
                }
            },
        ]
    },
    plugins: [
        extractSass,
        // new webpack.ProvidePlugin({
        //     $: 'jquery',
        //     jQuery: 'jquery'
        // }),
    ],
};

<|next_version|>
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractSass = new ExtractTextPlugin({
    filename: '[name].css', // '[name].[contenthash].css'
    // disable: process.env.NODE_ENV === 'development'
});

module.exports = {
    entry: {
        app: './build/app',
        worker: './build/worker'
    },
    output: {
        path: path.join(__dirname, 'dist'),
        filename: '[name].js'
    },
    module: {
        loaders: [{
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['env']
                    }
                }
            },
            {
                test: /\.(css|scss)$/,
                use: extractSass.extract({
                    use: [{
                        loader: 'css-loader'
                    }, {
                        loader: 'sass-loader'
                    }],
                    // use style-loader in development
                    fallback: 'style-loader'
                })
            },
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'url-loader',
                options: {
                    limit: 10000
                }
            },
        ]
    },
    plugins: [
        extractSass,
        // new webpack.ProvidePlugin({
        //     $: 'jquery',
        //     jQuery: 'jquery'
        // }),
        new CopyWebpackPlugin([
            { from: 'server' /*, to: 'server'*/ },
        ])
    ],
};


Add http error 415 Unsupported Media Type

--- lib/plugins/body_parser.js
+++ lib/plugins/body_parser.js
@@ -3,6 +3,10 @@
 var jsonParser = require('./json_body_parser');
 var formParser = require('./form_body_parser');
 var multipartParser = require('./multipart_parser');
+
+var errors = require('../errors');
+
+var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

 function bodyParser(options) {
@@ -21,6 +25,8 @@
       return parseForm(req, res, next);
     } else if (req.contentType === 'multipart/form-data') {
       return parseMultipart(req, res, next);
+    } else {
+      return next(new UnsupportedMediaTypeError('Unsupported Content-Type: ' + req.contentType));
     }

     return next();

<|original_code|>
// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var jsonParser = require('./json_body_parser');
var formParser = require('./form_body_parser');
var multipartParser = require('./multipart_parser');

function bodyParser(options) {

  var parseForm = formParser(options);
  var parseJson = jsonParser(options);
  var parseMultipart = multipartParser(options);

  return function parseBody(req, res, next) {
    if (req.contentLength === 0 && !req.chunked)
      return next();

    if (req.contentType === 'application/json') {
      return parseJson(req, res, next);
    } else if (req.contentType === 'application/x-www-form-urlencoded') {
      return parseForm(req, res, next);
    } else if (req.contentType === 'multipart/form-data') {
      return parseMultipart(req, res, next);
    }

    return next();
  };
}

module.exports = bodyParser;

<|edits_diff|>
--- lib/plugins/body_parser.js
+++ lib/plugins/body_parser.js
@@ -3,6 +3,10 @@
 var jsonParser = require('./json_body_parser');
 var formParser = require('./form_body_parser');
 var multipartParser = require('./multipart_parser');
+
+var errors = require('../errors');
+
+var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

 function bodyParser(options) {
<|current_version|>
// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var jsonParser = require('./json_body_parser');
var formParser = require('./form_body_parser');
var multipartParser = require('./multipart_parser');

var errors = require('../errors');

var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

function bodyParser(options) {

  var parseForm = formParser(options);
  var parseJson = jsonParser(options);
  var parseMultipart = multipartParser(options);

  return function parseBody(req, res, next) {
    if (req.contentLength === 0 && !req.chunked)
      return next();

    if (req.contentType === 'application/json') {
      return parseJson(req, res, next);
    } else if (req.contentType === 'application/x-www-form-urlencoded') {
      return parseForm(req, res, next);
    } else if (req.contentType === 'multipart/form-data') {
      return parseMultipart(req, res, next);
    }

    return next();
  };
}

module.exports = bodyParser;

<|next_version|>
// Copyright 2012 Mark Cavage, Inc.  All rights reserved.

var jsonParser = require('./json_body_parser');
var formParser = require('./form_body_parser');
var multipartParser = require('./multipart_parser');

var errors = require('../errors');

var UnsupportedMediaTypeError = errors.UnsupportedMediaTypeError;

function bodyParser(options) {

  var parseForm = formParser(options);
  var parseJson = jsonParser(options);
  var parseMultipart = multipartParser(options);

  return function parseBody(req, res, next) {
    if (req.contentLength === 0 && !req.chunked)
      return next();

    if (req.contentType === 'application/json') {
      return parseJson(req, res, next);
    } else if (req.contentType === 'application/x-www-form-urlencoded') {
      return parseForm(req, res, next);
    } else if (req.contentType === 'multipart/form-data') {
      return parseMultipart(req, res, next);
    } else {
      return next(new UnsupportedMediaTypeError('Unsupported Content-Type: ' + req.contentType));
    }

    return next();
  };
}

module.exports = bodyParser;


Expand Keys enum to include: backspace, delete, and insert.
RELNOTES: n/a

PiperOrigin-RevId: 315440495

--- closure/goog/events/keys.js
+++ closure/goog/events/keys.js
@@ -20,12 +20,15 @@
 goog.events.Keys = {
   ALT: 'Meta',
   ALTGRAPH: 'AltGraph',
+  BACKSPACE: 'Backspace',
   CTRL: 'Control',
+  DELETE: 'Delete',
   DOWN: 'ArrowDown',
   END: 'End',
   ENTER: 'Enter',
   ESCAPE: 'Escape',
   HOME: 'Home',
+  INSERT: 'Insert',
   LEFT: 'ArrowLeft',
   PAGE_DOWN: 'PageDown',
   PAGE_UP: 'PageUp',

<|original_code|>
/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Constant declarations for common key values.
 */

goog.provide('goog.events.Keys');

/**
 * Key values for common characters.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 * @enum {string}
 */
goog.events.Keys = {
  ALT: 'Meta',
  ALTGRAPH: 'AltGraph',
  CTRL: 'Control',
  DOWN: 'ArrowDown',
  END: 'End',
  ENTER: 'Enter',
  ESCAPE: 'Escape',
  HOME: 'Home',
  LEFT: 'ArrowLeft',
  PAGE_DOWN: 'PageDown',
  PAGE_UP: 'PageUp',
  RIGHT: 'ArrowRight',
  SHIFT: 'Shift',
  SPACE: ' ',
  TAB: 'Tab',
  UP: 'ArrowUp',
};

<|edits_diff|>
--- closure/goog/events/keys.js
+++ closure/goog/events/keys.js
@@ -20,7 +20,9 @@
 goog.events.Keys = {
   ALT: 'Meta',
   ALTGRAPH: 'AltGraph',
+  BACKSPACE: 'Backspace',
   CTRL: 'Control',
+  DELETE: 'Delete',
   DOWN: 'ArrowDown',
   END: 'End',
   ENTER: 'Enter',
<|current_version|>
/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Constant declarations for common key values.
 */

goog.provide('goog.events.Keys');

/**
 * Key values for common characters.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 * @enum {string}
 */
goog.events.Keys = {
  ALT: 'Meta',
  ALTGRAPH: 'AltGraph',
  BACKSPACE: 'Backspace',
  CTRL: 'Control',
  DELETE: 'Delete',
  DOWN: 'ArrowDown',
  END: 'End',
  ENTER: 'Enter',
  ESCAPE: 'Escape',
  HOME: 'Home',
  LEFT: 'ArrowLeft',
  PAGE_DOWN: 'PageDown',
  PAGE_UP: 'PageUp',
  RIGHT: 'ArrowRight',
  SHIFT: 'Shift',
  SPACE: ' ',
  TAB: 'Tab',
  UP: 'ArrowUp',
};

<|next_version|>
/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview Constant declarations for common key values.
 */

goog.provide('goog.events.Keys');

/**
 * Key values for common characters.
 *
 * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
 * @enum {string}
 */
goog.events.Keys = {
  ALT: 'Meta',
  ALTGRAPH: 'AltGraph',
  BACKSPACE: 'Backspace',
  CTRL: 'Control',
  DELETE: 'Delete',
  DOWN: 'ArrowDown',
  END: 'End',
  ENTER: 'Enter',
  ESCAPE: 'Escape',
  HOME: 'Home',
  INSERT: 'Insert',
  LEFT: 'ArrowLeft',
  PAGE_DOWN: 'PageDown',
  PAGE_UP: 'PageUp',
  RIGHT: 'ArrowRight',
  SHIFT: 'Shift',
  SPACE: ' ',
  TAB: 'Tab',
  UP: 'ArrowUp',
};