Load extensions into express app

Load extensions into express app

--- src/server.js
+++ src/server.js
@@ -8,6 +8,7 @@
 let bodyParser = require('body-parser')
 let morgan = require('morgan')
 let routes = require('./api/routes')
+let extensions = require('./extensions/registry')

 dotenv.config({silent: true})

@@ -22,12 +23,15 @@
   extended: true
 }))

+app.locals.ext = extensions.load()
+
 // Load routes
 routes(app)

 let server = app.listen(port, () => {

   console.log('Mission Control listening at http://%s:%s', host, port)
+  console.log('app locals', app.locals.ext)

 })

<|original_code|>
'use strict'

let fs = require('fs')
let dotenv = require('dotenv')
let express = require('express')
let session = require('express-session')
let cookieParser = require('cookie-parser')
let bodyParser = require('body-parser')
let morgan = require('morgan')
let routes = require('./api/routes')

dotenv.config({silent: true})

let port = process.env.PORT || 3000
let host = process.env.HOST || 'localhost'
let app = express()

app.use(morgan('dev'))
app.use(cookieParser())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: true
}))

// Load routes
routes(app)

let server = app.listen(port, () => {

  console.log('Mission Control listening at http://%s:%s', host, port)

})

module.exports = server
<|edits_diff|>
--- src/server.js
+++ src/server.js
@@ -8,6 +8,7 @@
 let bodyParser = require('body-parser')
 let morgan = require('morgan')
 let routes = require('./api/routes')
+let extensions = require('./extensions/registry')

 dotenv.config({silent: true})

@@ -22,6 +23,8 @@
   extended: true
 }))

+app.locals.ext = extensions.load()
+
 // Load routes
 routes(app)

<|current_version|>
'use strict'

let fs = require('fs')
let dotenv = require('dotenv')
let express = require('express')
let session = require('express-session')
let cookieParser = require('cookie-parser')
let bodyParser = require('body-parser')
let morgan = require('morgan')
let routes = require('./api/routes')
let extensions = require('./extensions/registry')

dotenv.config({silent: true})

let port = process.env.PORT || 3000
let host = process.env.HOST || 'localhost'
let app = express()

app.use(morgan('dev'))
app.use(cookieParser())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: true
}))

app.locals.ext = extensions.load()

// Load routes
routes(app)

let server = app.listen(port, () => {

  console.log('Mission Control listening at http://%s:%s', host, port)

})

module.exports = server

<|next_version|>
'use strict'

let fs = require('fs')
let dotenv = require('dotenv')
let express = require('express')
let session = require('express-session')
let cookieParser = require('cookie-parser')
let bodyParser = require('body-parser')
let morgan = require('morgan')
let routes = require('./api/routes')
let extensions = require('./extensions/registry')

dotenv.config({silent: true})

let port = process.env.PORT || 3000
let host = process.env.HOST || 'localhost'
let app = express()

app.use(morgan('dev'))
app.use(cookieParser())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
  extended: true
}))

app.locals.ext = extensions.load()

// Load routes
routes(app)

let server = app.listen(port, () => {

  console.log('Mission Control listening at http://%s:%s', host, port)
  console.log('app locals', app.locals.ext)

})

module.exports = server


Connect to redis on route

Connect to redis on route

--- routes/index.js
+++ routes/index.js
@@ -1,5 +1,8 @@
 var express = require('express');
+var redis = require('redis');
+
 var router = express.Router();
+var client = redis.createClient();

 /* GET home page. */
 router.get('/', function(req, res) {

<|original_code|>
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'VoteAnon' });
});

router.route('/create')
.get(function(req, res) {
  res.render('create', { title: 'VoteAnon: create poll' });
})
.post(function(req, res) {
  res.render('confirm_create', { title: 'VoteAnon: poll created' });
});

module.exports = router;

<|edits_diff|>
--- routes/index.js
+++ routes/index.js
@@ -1,4 +1,6 @@
 var express = require('express');
+var redis = require('redis');
+
 var router = express.Router();

 /* GET home page. */
<|current_version|>
var express = require('express');
var redis = require('redis');

var router = express.Router();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'VoteAnon' });
});

router.route('/create')
.get(function(req, res) {
  res.render('create', { title: 'VoteAnon: create poll' });
})
.post(function(req, res) {
  res.render('confirm_create', { title: 'VoteAnon: poll created' });
});

module.exports = router;

<|next_version|>
var express = require('express');
var redis = require('redis');

var router = express.Router();
var client = redis.createClient();

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'VoteAnon' });
});

router.route('/create')
.get(function(req, res) {
  res.render('create', { title: 'VoteAnon: create poll' });
})
.post(function(req, res) {
  res.render('confirm_create', { title: 'VoteAnon: poll created' });
});

module.exports = router;


Fix wrong handling of paste event that would result in streaming from a magnet if pasting into input for download for eg

--- src/renderer/mixins/global/readMagnet.js
+++ src/renderer/mixins/global/readMagnet.js
@@ -14,8 +14,13 @@
   },

   methods: {
+    /**
+     * @param {ClipboardEvent} e
+     */
     handlePaste (e) {
       const text = e.clipboardData.getData('text')
+
+      if (e.target.tagName.toUpperCase() === 'INPUT') return

       if (/magnet:\?/.test(text)) {
         if (!this.isClientPage) {

<|original_code|>
export default {
  mounted () {
    document.addEventListener('paste', this.handlePaste)
  },

  beforeDestroy () {
    document.removeEventListener('paste', this.handlePaste)
  },

  computed: {
    isClientPage () {
      return this.$route.path === '/torrenting'
    }
  },

  methods: {
    handlePaste (e) {
      const text = e.clipboardData.getData('text')

      if (/magnet:\?/.test(text)) {
        if (!this.isClientPage) {
          e.preventDefault()

          this.$store.dispatch('streaming/play', {
            link: text,
            isTorrent: true,
            name: null,
            neighbours: null
          })
        }
      }
    }
  }
}

<|edits_diff|>
--- src/renderer/mixins/global/readMagnet.js
+++ src/renderer/mixins/global/readMagnet.js
@@ -14,6 +14,9 @@
   },

   methods: {
+    /**
+     * @param {ClipboardEvent} e
+     */
     handlePaste (e) {
       const text = e.clipboardData.getData('text')

<|current_version|>
export default {
  mounted () {
    document.addEventListener('paste', this.handlePaste)
  },

  beforeDestroy () {
    document.removeEventListener('paste', this.handlePaste)
  },

  computed: {
    isClientPage () {
      return this.$route.path === '/torrenting'
    }
  },

  methods: {
    /**
     * @param {ClipboardEvent} e
     */
    handlePaste (e) {
      const text = e.clipboardData.getData('text')

      if (/magnet:\?/.test(text)) {
        if (!this.isClientPage) {
          e.preventDefault()

          this.$store.dispatch('streaming/play', {
            link: text,
            isTorrent: true,
            name: null,
            neighbours: null
          })
        }
      }
    }
  }
}

<|next_version|>
export default {
  mounted () {
    document.addEventListener('paste', this.handlePaste)
  },

  beforeDestroy () {
    document.removeEventListener('paste', this.handlePaste)
  },

  computed: {
    isClientPage () {
      return this.$route.path === '/torrenting'
    }
  },

  methods: {
    /**
     * @param {ClipboardEvent} e
     */
    handlePaste (e) {
      const text = e.clipboardData.getData('text')

      if (e.target.tagName.toUpperCase() === 'INPUT') return

      if (/magnet:\?/.test(text)) {
        if (!this.isClientPage) {
          e.preventDefault()

          this.$store.dispatch('streaming/play', {
            link: text,
            isTorrent: true,
            name: null,
            neighbours: null
          })
        }
      }
    }
  }
}


Add new fxn to null out chars in str range

--- lib/common.js
+++ lib/common.js
@@ -30,5 +30,10 @@
   return indices;
 };

+var nullOutChars = function(str, start, end, nullChar) {
+  return str.slice(0, start) + nullChar.repeat(end - start) + str.slice(end);
+}
+
 module.exports.findAllIndices = findAllIndices;
 module.exports.findAllIndicesRegex = findAllIndicesRegex;
+module.exports.nullOutChars = nullOutChars;

<|original_code|>
/**
 * Find indices of all occurance of elem in arr. Uses 'indexOf'.
 * @param {array} arr - Array-like element (works with strings too!).
 * @param {array_element} elem - Element to search for in arr.
 * @return {array} indices - Array of indices where elem occurs in arr.
 */
var findAllIndices = function(arr, elem) {
  var indices = [];
  var i = arr.indexOf(elem);
  while (i != -1) {
    indices.push(i);
    i = arr.indexOf(elem, i + 1);
  }
  return indices;
};

/**
 * Find indices of all matches of Regex pattern in str.
 * @param {string} str - string to find Regex patterns in.
 * @param {RegExp} re - Regex patterns
 * @return {array} Array of indices where Regex pattern occurs in str.
 */
var findAllIndicesRegex = function(str, re) {
  var indices = [];
  var m = re.exec(str);
  while (m) {
    indices.push(m.index);
    m = re.exec(str);
  }
  return indices;
};

module.exports.findAllIndices = findAllIndices;
module.exports.findAllIndicesRegex = findAllIndicesRegex;

<|edits_diff|>
--- lib/common.js
+++ lib/common.js
@@ -30,5 +30,9 @@
   return indices;
 };

+var nullOutChars = function(str, start, end, nullChar) {
+  return str.slice(0, start) + nullChar.repeat(end - start) + str.slice(end);
+}
+
 module.exports.findAllIndices = findAllIndices;
 module.exports.findAllIndicesRegex = findAllIndicesRegex;
<|current_version|>
/**
 * Find indices of all occurance of elem in arr. Uses 'indexOf'.
 * @param {array} arr - Array-like element (works with strings too!).
 * @param {array_element} elem - Element to search for in arr.
 * @return {array} indices - Array of indices where elem occurs in arr.
 */
var findAllIndices = function(arr, elem) {
  var indices = [];
  var i = arr.indexOf(elem);
  while (i != -1) {
    indices.push(i);
    i = arr.indexOf(elem, i + 1);
  }
  return indices;
};

/**
 * Find indices of all matches of Regex pattern in str.
 * @param {string} str - string to find Regex patterns in.
 * @param {RegExp} re - Regex patterns
 * @return {array} Array of indices where Regex pattern occurs in str.
 */
var findAllIndicesRegex = function(str, re) {
  var indices = [];
  var m = re.exec(str);
  while (m) {
    indices.push(m.index);
    m = re.exec(str);
  }
  return indices;
};

var nullOutChars = function(str, start, end, nullChar) {
  return str.slice(0, start) + nullChar.repeat(end - start) + str.slice(end);
}

module.exports.findAllIndices = findAllIndices;
module.exports.findAllIndicesRegex = findAllIndicesRegex;

<|next_version|>
/**
 * Find indices of all occurance of elem in arr. Uses 'indexOf'.
 * @param {array} arr - Array-like element (works with strings too!).
 * @param {array_element} elem - Element to search for in arr.
 * @return {array} indices - Array of indices where elem occurs in arr.
 */
var findAllIndices = function(arr, elem) {
  var indices = [];
  var i = arr.indexOf(elem);
  while (i != -1) {
    indices.push(i);
    i = arr.indexOf(elem, i + 1);
  }
  return indices;
};

/**
 * Find indices of all matches of Regex pattern in str.
 * @param {string} str - string to find Regex patterns in.
 * @param {RegExp} re - Regex patterns
 * @return {array} Array of indices where Regex pattern occurs in str.
 */
var findAllIndicesRegex = function(str, re) {
  var indices = [];
  var m = re.exec(str);
  while (m) {
    indices.push(m.index);
    m = re.exec(str);
  }
  return indices;
};

var nullOutChars = function(str, start, end, nullChar) {
  return str.slice(0, start) + nullChar.repeat(end - start) + str.slice(end);
}

module.exports.findAllIndices = findAllIndices;
module.exports.findAllIndicesRegex = findAllIndicesRegex;
module.exports.nullOutChars = nullOutChars;


Add error handling to browser requests.

Add error handling to browser requests.

--- lib/util/request-browser.js
+++ lib/util/request-browser.js
@@ -23,7 +23,12 @@
     response.statusCode = jqXHR.status;
     response.headers = { 'content-type': jqXHR.getResponseHeader('content-type') };
     request.emit('response', response);
+  })
+  // Emit an error if the request fails
+  .fail(function () {
+    request.emit('error', new Error('Error requesting ' + settings.url));
   });
+  // Aborts the request
   request.abort = function () { jqXHR.abort(); };

   return request;

<|original_code|>
/*! @license ©2013 Ruben Verborgh - Multimedia Lab / iMinds / Ghent University */
/** Browser replacement for the request module using jQuery. */

var EventEmitter = require('events').EventEmitter,
    SingleIterator = require('../../lib/iterators/Iterator').SingleIterator;

require('setimmediate');

// Requests the given resource as an iterator
function createRequest(settings) {
  var request = new EventEmitter();

  // Delegate the request to jQuery's AJAX module
  var jqXHR = jQuery.ajax({
    url: settings.url,
    timeout: settings.timeout,
    type: settings.method,
    headers: { accept: settings.headers && settings.headers.accept || '*/*' },
  })
  // Emit the result as a readable response iterator
  .success(function () {
    var response = new SingleIterator(jqXHR.responseText || '');
    response.statusCode = jqXHR.status;
    response.headers = { 'content-type': jqXHR.getResponseHeader('content-type') };
    request.emit('response', response);
  });
  request.abort = function () { jqXHR.abort(); };

  return request;
}

module.exports = createRequest;

<|edits_diff|>
--- lib/util/request-browser.js
+++ lib/util/request-browser.js
@@ -23,6 +23,10 @@
     response.statusCode = jqXHR.status;
     response.headers = { 'content-type': jqXHR.getResponseHeader('content-type') };
     request.emit('response', response);
+  })
+  // Emit an error if the request fails
+  .fail(function () {
+    request.emit('error', new Error('Error requesting ' + settings.url));
   });
   request.abort = function () { jqXHR.abort(); };

<|current_version|>
/*! @license ©2013 Ruben Verborgh - Multimedia Lab / iMinds / Ghent University */
/** Browser replacement for the request module using jQuery. */

var EventEmitter = require('events').EventEmitter,
    SingleIterator = require('../../lib/iterators/Iterator').SingleIterator;

require('setimmediate');

// Requests the given resource as an iterator
function createRequest(settings) {
  var request = new EventEmitter();

  // Delegate the request to jQuery's AJAX module
  var jqXHR = jQuery.ajax({
    url: settings.url,
    timeout: settings.timeout,
    type: settings.method,
    headers: { accept: settings.headers && settings.headers.accept || '*/*' },
  })
  // Emit the result as a readable response iterator
  .success(function () {
    var response = new SingleIterator(jqXHR.responseText || '');
    response.statusCode = jqXHR.status;
    response.headers = { 'content-type': jqXHR.getResponseHeader('content-type') };
    request.emit('response', response);
  })
  // Emit an error if the request fails
  .fail(function () {
    request.emit('error', new Error('Error requesting ' + settings.url));
  });
  request.abort = function () { jqXHR.abort(); };

  return request;
}

module.exports = createRequest;

<|next_version|>
/*! @license ©2013 Ruben Verborgh - Multimedia Lab / iMinds / Ghent University */
/** Browser replacement for the request module using jQuery. */

var EventEmitter = require('events').EventEmitter,
    SingleIterator = require('../../lib/iterators/Iterator').SingleIterator;

require('setimmediate');

// Requests the given resource as an iterator
function createRequest(settings) {
  var request = new EventEmitter();

  // Delegate the request to jQuery's AJAX module
  var jqXHR = jQuery.ajax({
    url: settings.url,
    timeout: settings.timeout,
    type: settings.method,
    headers: { accept: settings.headers && settings.headers.accept || '*/*' },
  })
  // Emit the result as a readable response iterator
  .success(function () {
    var response = new SingleIterator(jqXHR.responseText || '');
    response.statusCode = jqXHR.status;
    response.headers = { 'content-type': jqXHR.getResponseHeader('content-type') };
    request.emit('response', response);
  })
  // Emit an error if the request fails
  .fail(function () {
    request.emit('error', new Error('Error requesting ' + settings.url));
  });
  // Aborts the request
  request.abort = function () { jqXHR.abort(); };

  return request;
}

module.exports = createRequest;


Add notifications for changes in the user module

--- app/js/models/user/User.Module.js
+++ app/js/models/user/User.Module.js
@@ -42,7 +42,10 @@
     },

     logout : function() {
+        var that = this;
         return this._http(this.app.options.logoutApiUrl).then(function(user) {
+            return that.notify();
+        }).then(function() {
             return user;
         });
     },

<|original_code|>
var _ = require('underscore');
var Mosaic = require('mosaic-commons');
var App = require('mosaic-core').App;
var Api = App.Api;
var Teleport = require('mosaic-teleport');

/** This module manages resource statistics. */
module.exports = Api.extend({

    /**
     * Initializes internal fields.
     */
    _initFields : function() {
        this._user = null;
    },

    /**
     * Loads information about selected/active entities.
     */
    start : function() {
    },

    /** Closes this module. */
    stop : function() {
    },

    _http : function(url, method) {
        method = method || 'GET';
        var client = Teleport.HttpClient.newInstance({
            baseUrl : url
        });
        return client.exec({
            path : '',
            method : method
        }).then(function(json) {
            try {
                return _.isObject(json) ? json : JSON.parse(json);
            } catch (err) {
                return;
            }
        });
    },

    logout : function() {
        return this._http(this.app.options.logoutApiUrl).then(function(user) {
            return user;
        });
    },

    getUserInfo : function() {
        return this._http(this.app.options.userInfoApiUrl).then(function(user) {
            if (!user || !user.displayName)
                return;
            return user;
        });
    },

});

<|edits_diff|>
--- app/js/models/user/User.Module.js
+++ app/js/models/user/User.Module.js
@@ -42,6 +42,7 @@
     },

     logout : function() {
+        var that = this;
         return this._http(this.app.options.logoutApiUrl).then(function(user) {
             return user;
         });
<|current_version|>
var _ = require('underscore');
var Mosaic = require('mosaic-commons');
var App = require('mosaic-core').App;
var Api = App.Api;
var Teleport = require('mosaic-teleport');

/** This module manages resource statistics. */
module.exports = Api.extend({

    /**
     * Initializes internal fields.
     */
    _initFields : function() {
        this._user = null;
    },

    /**
     * Loads information about selected/active entities.
     */
    start : function() {
    },

    /** Closes this module. */
    stop : function() {
    },

    _http : function(url, method) {
        method = method || 'GET';
        var client = Teleport.HttpClient.newInstance({
            baseUrl : url
        });
        return client.exec({
            path : '',
            method : method
        }).then(function(json) {
            try {
                return _.isObject(json) ? json : JSON.parse(json);
            } catch (err) {
                return;
            }
        });
    },

    logout : function() {
        var that = this;
        return this._http(this.app.options.logoutApiUrl).then(function(user) {
            return user;
        });
    },

    getUserInfo : function() {
        return this._http(this.app.options.userInfoApiUrl).then(function(user) {
            if (!user || !user.displayName)
                return;
            return user;
        });
    },

});

<|next_version|>
var _ = require('underscore');
var Mosaic = require('mosaic-commons');
var App = require('mosaic-core').App;
var Api = App.Api;
var Teleport = require('mosaic-teleport');

/** This module manages resource statistics. */
module.exports = Api.extend({

    /**
     * Initializes internal fields.
     */
    _initFields : function() {
        this._user = null;
    },

    /**
     * Loads information about selected/active entities.
     */
    start : function() {
    },

    /** Closes this module. */
    stop : function() {
    },

    _http : function(url, method) {
        method = method || 'GET';
        var client = Teleport.HttpClient.newInstance({
            baseUrl : url
        });
        return client.exec({
            path : '',
            method : method
        }).then(function(json) {
            try {
                return _.isObject(json) ? json : JSON.parse(json);
            } catch (err) {
                return;
            }
        });
    },

    logout : function() {
        var that = this;
        return this._http(this.app.options.logoutApiUrl).then(function(user) {
            return that.notify();
        }).then(function() {
            return user;
        });
    },

    getUserInfo : function() {
        return this._http(this.app.options.userInfoApiUrl).then(function(user) {
            if (!user || !user.displayName)
                return;
            return user;
        });
    },

});


Allow method chaining in QueryConverter

Allow method chaining in QueryConverter

--- app/utils/query-converter.js
+++ app/utils/query-converter.js
@@ -11,26 +11,35 @@
 export default function QueryConverter() {
   this.fromId = function(id){
     this.hash = JSON.parse(id);
+    return this;
   };
+
   this.fromHash = function(hash){
     this.hash = hash;
+    return this;
   };
+
   this.fromQueryString = function(qString){
     this.hash = URI(qString).query(true);
+    return this;
   };
+
   this.toId = function(){
     // JS objects maintain insertion ordering! Woah.
     // http://stackoverflow.com/questions/5467129/sort-javascript-object-by-key/31102605#31102605
     var orderedHash = {};
     var unorderedHash = this.hash;
+    console.log(unorderedHash);
     Object.keys(this.hash).sort().forEach(function(key){
       orderedHash[key] = unorderedHash[key];
     });
     return JSON.stringify(orderedHash);
   };
+
   this.toHash = function(){
     return this.hash;
   };
+
   this.toQueryString = function(){
     return URI('').addQuery(this.hash).toString();
   };

<|original_code|>
/* global URI */

/**
 * QueryConverter stores a list of string to string pairs
 * as a hash (Embereño for POJO) and can export that list as a JSON string,
 * a URL query string, or a hash.
 * We will use the JSON string representation as an ID for Ember Data.
 * To ensure a 1-1 mapping from queries to IDs,
 * ID representation of a query must be sorted alphabetically by key.
 */
export default function QueryConverter() {
  this.fromId = function(id){
    this.hash = JSON.parse(id);
  };
  this.fromHash = function(hash){
    this.hash = hash;
  };
  this.fromQueryString = function(qString){
    this.hash = URI(qString).query(true);
  };
  this.toId = function(){
    // JS objects maintain insertion ordering! Woah.
    // http://stackoverflow.com/questions/5467129/sort-javascript-object-by-key/31102605#31102605
    var orderedHash = {};
    var unorderedHash = this.hash;
    Object.keys(this.hash).sort().forEach(function(key){
      orderedHash[key] = unorderedHash[key];
    });
    return JSON.stringify(orderedHash);
  };
  this.toHash = function(){
    return this.hash;
  };
  this.toQueryString = function(){
    return URI('').addQuery(this.hash).toString();
  };
}

<|edits_diff|>
--- app/utils/query-converter.js
+++ app/utils/query-converter.js
@@ -11,23 +11,31 @@
 export default function QueryConverter() {
   this.fromId = function(id){
     this.hash = JSON.parse(id);
+    return this;
   };
+
   this.fromHash = function(hash){
     this.hash = hash;
+    return this;
   };
+
   this.fromQueryString = function(qString){
     this.hash = URI(qString).query(true);
+    return this;
   };
+
   this.toId = function(){
     // JS objects maintain insertion ordering! Woah.
     // http://stackoverflow.com/questions/5467129/sort-javascript-object-by-key/31102605#31102605
     var orderedHash = {};
     var unorderedHash = this.hash;
+    console.log(unorderedHash);
     Object.keys(this.hash).sort().forEach(function(key){
       orderedHash[key] = unorderedHash[key];
     });
     return JSON.stringify(orderedHash);
   };
+
   this.toHash = function(){
     return this.hash;
   };
<|current_version|>
/* global URI */

/**
 * QueryConverter stores a list of string to string pairs
 * as a hash (Embereño for POJO) and can export that list as a JSON string,
 * a URL query string, or a hash.
 * We will use the JSON string representation as an ID for Ember Data.
 * To ensure a 1-1 mapping from queries to IDs,
 * ID representation of a query must be sorted alphabetically by key.
 */
export default function QueryConverter() {
  this.fromId = function(id){
    this.hash = JSON.parse(id);
    return this;
  };

  this.fromHash = function(hash){
    this.hash = hash;
    return this;
  };

  this.fromQueryString = function(qString){
    this.hash = URI(qString).query(true);
    return this;
  };

  this.toId = function(){
    // JS objects maintain insertion ordering! Woah.
    // http://stackoverflow.com/questions/5467129/sort-javascript-object-by-key/31102605#31102605
    var orderedHash = {};
    var unorderedHash = this.hash;
    console.log(unorderedHash);
    Object.keys(this.hash).sort().forEach(function(key){
      orderedHash[key] = unorderedHash[key];
    });
    return JSON.stringify(orderedHash);
  };

  this.toHash = function(){
    return this.hash;
  };
  this.toQueryString = function(){
    return URI('').addQuery(this.hash).toString();
  };
}

<|next_version|>
/* global URI */

/**
 * QueryConverter stores a list of string to string pairs
 * as a hash (Embereño for POJO) and can export that list as a JSON string,
 * a URL query string, or a hash.
 * We will use the JSON string representation as an ID for Ember Data.
 * To ensure a 1-1 mapping from queries to IDs,
 * ID representation of a query must be sorted alphabetically by key.
 */
export default function QueryConverter() {
  this.fromId = function(id){
    this.hash = JSON.parse(id);
    return this;
  };

  this.fromHash = function(hash){
    this.hash = hash;
    return this;
  };

  this.fromQueryString = function(qString){
    this.hash = URI(qString).query(true);
    return this;
  };

  this.toId = function(){
    // JS objects maintain insertion ordering! Woah.
    // http://stackoverflow.com/questions/5467129/sort-javascript-object-by-key/31102605#31102605
    var orderedHash = {};
    var unorderedHash = this.hash;
    console.log(unorderedHash);
    Object.keys(this.hash).sort().forEach(function(key){
      orderedHash[key] = unorderedHash[key];
    });
    return JSON.stringify(orderedHash);
  };

  this.toHash = function(){
    return this.hash;
  };

  this.toQueryString = function(){
    return URI('').addQuery(this.hash).toString();
  };
}


Fix hound issues: [ci full]

Fix hound issues: [ci full]

--- src/deep-todo/tests/e2e/Tests/TaskEditing.spec.js
+++ src/deep-todo/tests/e2e/Tests/TaskEditing.spec.js
@@ -1,6 +1,11 @@
+/* global browser */
+/* global protractor */
+
 'use strict';

 var TaskList = require('../POMs/TasksList.js');
+var config = require('../protractor.config.js');
+

 describe('Check that task name can be updated', function() {

<|original_code|>
'use strict';

var TaskList = require('../POMs/TasksList.js');

describe('Check that task name can be updated', function() {

  beforeAll(function() {
    TaskList.actionsBeforeAll();
  });

  it('Adding new task', function() {
    TaskList.addTask('protractor test task1');

    //wait untill all task will be loaded
    browser.sleep(config.config.jasmineNodeOpts.defaultTimeoutInterval / 10);
  });

  it('Updating the task name and verifying that it is saved', function() {
    TaskList.taskEditing(0, 'updated task name');
  });

  afterAll(function() {
    //Deleting all existing tasks before each spec to avoid conflicts
    TaskList.clearAllTasks();
  });

});

<|edits_diff|>
--- src/deep-todo/tests/e2e/Tests/TaskEditing.spec.js
+++ src/deep-todo/tests/e2e/Tests/TaskEditing.spec.js
@@ -1,3 +1,6 @@
+/* global browser */
+/* global protractor */
+
 'use strict';

 var TaskList = require('../POMs/TasksList.js');
<|current_version|>
/* global browser */
/* global protractor */

'use strict';

var TaskList = require('../POMs/TasksList.js');

describe('Check that task name can be updated', function() {

  beforeAll(function() {
    TaskList.actionsBeforeAll();
  });

  it('Adding new task', function() {
    TaskList.addTask('protractor test task1');

    //wait untill all task will be loaded
    browser.sleep(config.config.jasmineNodeOpts.defaultTimeoutInterval / 10);
  });

  it('Updating the task name and verifying that it is saved', function() {
    TaskList.taskEditing(0, 'updated task name');
  });

  afterAll(function() {
    //Deleting all existing tasks before each spec to avoid conflicts
    TaskList.clearAllTasks();
  });

});

<|next_version|>
/* global browser */
/* global protractor */

'use strict';

var TaskList = require('../POMs/TasksList.js');
var config = require('../protractor.config.js');

describe('Check that task name can be updated', function() {

  beforeAll(function() {
    TaskList.actionsBeforeAll();
  });

  it('Adding new task', function() {
    TaskList.addTask('protractor test task1');

    //wait untill all task will be loaded
    browser.sleep(config.config.jasmineNodeOpts.defaultTimeoutInterval / 10);
  });

  it('Updating the task name and verifying that it is saved', function() {
    TaskList.taskEditing(0, 'updated task name');
  });

  afterAll(function() {
    //Deleting all existing tasks before each spec to avoid conflicts
    TaskList.clearAllTasks();
  });

});


Create root reducer for the application

Create root reducer for the application

--- client/reducers/index.js
+++ client/reducers/index.js
@@ -1,7 +1,9 @@
 import { combineReducers } from 'redux';
 import { routerReducer } from 'react-router-redux';
+import { reducer as formReducer } from 'redux-form';

 const rootReducer = combineReducers({
+    form: formReducer,
     routing: routerReducer
 });

<|original_code|>
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';

const rootReducer = combineReducers({
    routing: routerReducer
});

export default rootReducer;
<|edits_diff|>
--- client/reducers/index.js
+++ client/reducers/index.js
@@ -1,5 +1,6 @@
 import { combineReducers } from 'redux';
 import { routerReducer } from 'react-router-redux';
+import { reducer as formReducer } from 'redux-form';

 const rootReducer = combineReducers({
     routing: routerReducer
<|current_version|>
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({
    routing: routerReducer
});

export default rootReducer;
<|next_version|>
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';

const rootReducer = combineReducers({
    form: formReducer,
    routing: routerReducer
});

export default rootReducer;


Test with data from real localisation

Test with data from real localisation

--- src/javascript/binary/base/__tests__/storage.js
+++ src/javascript/binary/base/__tests__/storage.js
@@ -6,10 +6,13 @@
     var text = new storage.Localizable({
         key1: 'value',
         key2: 'value [_1]',
+        'You_can_view_your_[_1]trading_limits_here_': 'Ihre [_1] Handelslimits sind hier ersichtlich.',
     });
     it('should try to return a string from the localised texts', function() {
         expect(text.localize('key')).to.equal('key');
         expect(text.localize('key1')).to.equal('value');
+        expect(text.localize('You can view your [_1]trading limits here.'))
+            .to.equal('Ihre [_1] Handelslimits sind hier ersichtlich.');
     });

     it('should only template when required', function() {
@@ -17,6 +20,8 @@
         // inject global template function
         global.template = utility.template;
         expect(text.localize('key2', [1])).to.equal('value 1');
+        expect(text.localize('You can view your [_1]trading limits here.', ['something']))
+            .to.equal('Ihre something Handelslimits sind hier ersichtlich.');
         delete global.template;
     });
 });

<|original_code|>
var expect = require('chai').expect;
var storage = require('../storage');
var utility = require('../utility');

describe('text.localize', function() {
    var text = new storage.Localizable({
        key1: 'value',
        key2: 'value [_1]',
    });
    it('should try to return a string from the localised texts', function() {
        expect(text.localize('key')).to.equal('key');
        expect(text.localize('key1')).to.equal('value');
    });

    it('should only template when required', function() {
        expect(text.localize('key2')).to.equal('value [_1]');
        // inject global template function
        global.template = utility.template;
        expect(text.localize('key2', [1])).to.equal('value 1');
        delete global.template;
    });
});

<|edits_diff|>
--- src/javascript/binary/base/__tests__/storage.js
+++ src/javascript/binary/base/__tests__/storage.js
@@ -6,10 +6,13 @@
     var text = new storage.Localizable({
         key1: 'value',
         key2: 'value [_1]',
+        'You_can_view_your_[_1]trading_limits_here_': 'Ihre [_1] Handelslimits sind hier ersichtlich.',
     });
     it('should try to return a string from the localised texts', function() {
         expect(text.localize('key')).to.equal('key');
         expect(text.localize('key1')).to.equal('value');
+        expect(text.localize('You can view your [_1]trading limits here.'))
+            .to.equal('Ihre [_1] Handelslimits sind hier ersichtlich.');
     });

     it('should only template when required', function() {
<|current_version|>
var expect = require('chai').expect;
var storage = require('../storage');
var utility = require('../utility');

describe('text.localize', function() {
    var text = new storage.Localizable({
        key1: 'value',
        key2: 'value [_1]',
        'You_can_view_your_[_1]trading_limits_here_': 'Ihre [_1] Handelslimits sind hier ersichtlich.',
    });
    it('should try to return a string from the localised texts', function() {
        expect(text.localize('key')).to.equal('key');
        expect(text.localize('key1')).to.equal('value');
        expect(text.localize('You can view your [_1]trading limits here.'))
            .to.equal('Ihre [_1] Handelslimits sind hier ersichtlich.');
    });

    it('should only template when required', function() {
        expect(text.localize('key2')).to.equal('value [_1]');
        // inject global template function
        global.template = utility.template;
        expect(text.localize('key2', [1])).to.equal('value 1');
        delete global.template;
    });
});

<|next_version|>
var expect = require('chai').expect;
var storage = require('../storage');
var utility = require('../utility');

describe('text.localize', function() {
    var text = new storage.Localizable({
        key1: 'value',
        key2: 'value [_1]',
        'You_can_view_your_[_1]trading_limits_here_': 'Ihre [_1] Handelslimits sind hier ersichtlich.',
    });
    it('should try to return a string from the localised texts', function() {
        expect(text.localize('key')).to.equal('key');
        expect(text.localize('key1')).to.equal('value');
        expect(text.localize('You can view your [_1]trading limits here.'))
            .to.equal('Ihre [_1] Handelslimits sind hier ersichtlich.');
    });

    it('should only template when required', function() {
        expect(text.localize('key2')).to.equal('value [_1]');
        // inject global template function
        global.template = utility.template;
        expect(text.localize('key2', [1])).to.equal('value 1');
        expect(text.localize('You can view your [_1]trading limits here.', ['something']))
            .to.equal('Ihre something Handelslimits sind hier ersichtlich.');
        delete global.template;
    });
});


Fix issue where errors aren't being propagated.

--- lib/deferredchain.js
+++ lib/deferredchain.js
@@ -7,6 +7,7 @@

   this.await = new Promise(function() {
     self._done = arguments[0];
+    self._error = arguments[1];
   });
   this.started = false;
 };
@@ -17,6 +18,9 @@
     var args = Array.prototype.slice.call(arguments);

     return fn.apply(null, args);
+  });
+  this.chain = this.chain.catch(function(e) {
+    self._error(e);
   });

   return this;

<|original_code|>
function DeferredChain() {
  var self = this;
  this.chain = new Promise(function(accept, reject) {
    self._accept = accept;
    self._reject = reject;
  });

  this.await = new Promise(function() {
    self._done = arguments[0];
  });
  this.started = false;
};

DeferredChain.prototype.then = function(fn) {
  var self = this;
  this.chain = this.chain.then(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });

  return this;
};

DeferredChain.prototype.catch = function(fn) {
  var self = this;
  this.chain = this.chain.catch(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });

  return this;
};

DeferredChain.prototype.start = function() {
  this.started = true;
  this.chain = this.chain.then(this._done);
  this._accept();
  return this.await;
};

module.exports = DeferredChain;

<|edits_diff|>
--- lib/deferredchain.js
+++ lib/deferredchain.js
@@ -7,6 +7,7 @@

   this.await = new Promise(function() {
     self._done = arguments[0];
+    self._error = arguments[1];
   });
   this.started = false;
 };
<|current_version|>
function DeferredChain() {
  var self = this;
  this.chain = new Promise(function(accept, reject) {
    self._accept = accept;
    self._reject = reject;
  });

  this.await = new Promise(function() {
    self._done = arguments[0];
    self._error = arguments[1];
  });
  this.started = false;
};

DeferredChain.prototype.then = function(fn) {
  var self = this;
  this.chain = this.chain.then(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });

  return this;
};

DeferredChain.prototype.catch = function(fn) {
  var self = this;
  this.chain = this.chain.catch(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });

  return this;
};

DeferredChain.prototype.start = function() {
  this.started = true;
  this.chain = this.chain.then(this._done);
  this._accept();
  return this.await;
};

module.exports = DeferredChain;

<|next_version|>
function DeferredChain() {
  var self = this;
  this.chain = new Promise(function(accept, reject) {
    self._accept = accept;
    self._reject = reject;
  });

  this.await = new Promise(function() {
    self._done = arguments[0];
    self._error = arguments[1];
  });
  this.started = false;
};

DeferredChain.prototype.then = function(fn) {
  var self = this;
  this.chain = this.chain.then(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });
  this.chain = this.chain.catch(function(e) {
    self._error(e);
  });

  return this;
};

DeferredChain.prototype.catch = function(fn) {
  var self = this;
  this.chain = this.chain.catch(function() {
    var args = Array.prototype.slice.call(arguments);

    return fn.apply(null, args);
  });

  return this;
};

DeferredChain.prototype.start = function() {
  this.started = true;
  this.chain = this.chain.then(this._done);
  this._accept();
  return this.await;
};

module.exports = DeferredChain;


Add doc comments for file templater

docs: Add doc comments for file templater

--- bin/fileTemplater.js
+++ bin/fileTemplater.js
@@ -15,16 +15,27 @@

 var fileTemplaterApi = {};

+/**
+ * Run file templating
+ */
 fileTemplaterApi.run = function() {
     _config.files.forEach(function(element, index, array) {
         templateFile(element);
     });
 }

+/**
+ * Sets internal config object
+ */
 fileTemplaterApi.setConfig = function(config) {
     _config = extend(_config, config);
 }

+/**
+ * Template a single file.
+ * Get the contents of a file, template it and re-write to the same file
+ * @param  {Object} filePaths File paths data, containing file src and dest
+ */
 function templateFile(filePaths) {
     var compiled;
     var output;

<|original_code|>
"use strict";

var fs = require('fs');
var path = require('path');
var extend = require('extend');
var template = require('lodash/template');

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

var _fileNumber = 1;
var _config = {
    onEachFile: function() {},
    onCompleted: function() {}
};

var fileTemplaterApi = {};

fileTemplaterApi.run = function() {
    _config.files.forEach(function(element, index, array) {
        templateFile(element);
    });
}

fileTemplaterApi.setConfig = function(config) {
    _config = extend(_config, config);
}

function templateFile(filePaths) {
    var compiled;
    var output;

    fs.readFile(filePaths.src, 'utf8', function(err, fileContents) {
        if (err) errorHandler(err);

        compiled = template(fileContents);
        output = compiled(_config.data);

        fs.writeFile(filePaths.dest, output, 'utf8', function(err) {
            if (err) errorHandler(err);

            _config.onEachFile(filePaths.dest);

            if(_fileNumber === _config.files.length) {
                _config.onCompleted();
            }

            _fileNumber++;

        });

    });
}

module.exports = fileTemplaterApi;
<|edits_diff|>
--- bin/fileTemplater.js
+++ bin/fileTemplater.js
@@ -15,12 +15,18 @@

 var fileTemplaterApi = {};

+/**
+ * Run file templating
+ */
 fileTemplaterApi.run = function() {
     _config.files.forEach(function(element, index, array) {
         templateFile(element);
     });
 }

+/**
+ * Sets internal config object
+ */
 fileTemplaterApi.setConfig = function(config) {
     _config = extend(_config, config);
 }
<|current_version|>
"use strict";

var fs = require('fs');
var path = require('path');
var extend = require('extend');
var template = require('lodash/template');

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

var _fileNumber = 1;
var _config = {
    onEachFile: function() {},
    onCompleted: function() {}
};

var fileTemplaterApi = {};

/**
 * Run file templating
 */
fileTemplaterApi.run = function() {
    _config.files.forEach(function(element, index, array) {
        templateFile(element);
    });
}

/**
 * Sets internal config object
 */
fileTemplaterApi.setConfig = function(config) {
    _config = extend(_config, config);
}

function templateFile(filePaths) {
    var compiled;
    var output;

    fs.readFile(filePaths.src, 'utf8', function(err, fileContents) {
        if (err) errorHandler(err);

        compiled = template(fileContents);
        output = compiled(_config.data);

        fs.writeFile(filePaths.dest, output, 'utf8', function(err) {
            if (err) errorHandler(err);

            _config.onEachFile(filePaths.dest);

            if(_fileNumber === _config.files.length) {
                _config.onCompleted();
            }

            _fileNumber++;

        });

    });
}

module.exports = fileTemplaterApi;
<|next_version|>
"use strict";

var fs = require('fs');
var path = require('path');
var extend = require('extend');
var template = require('lodash/template');

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

var _fileNumber = 1;
var _config = {
    onEachFile: function() {},
    onCompleted: function() {}
};

var fileTemplaterApi = {};

/**
 * Run file templating
 */
fileTemplaterApi.run = function() {
    _config.files.forEach(function(element, index, array) {
        templateFile(element);
    });
}

/**
 * Sets internal config object
 */
fileTemplaterApi.setConfig = function(config) {
    _config = extend(_config, config);
}

/**
 * Template a single file.
 * Get the contents of a file, template it and re-write to the same file
 * @param  {Object} filePaths File paths data, containing file src and dest
 */
function templateFile(filePaths) {
    var compiled;
    var output;

    fs.readFile(filePaths.src, 'utf8', function(err, fileContents) {
        if (err) errorHandler(err);

        compiled = template(fileContents);
        output = compiled(_config.data);

        fs.writeFile(filePaths.dest, output, 'utf8', function(err) {
            if (err) errorHandler(err);

            _config.onEachFile(filePaths.dest);

            if(_fileNumber === _config.files.length) {
                _config.onCompleted();
            }

            _fileNumber++;

        });

    });
}

module.exports = fileTemplaterApi;


Add Python server to localhost

Add Python server to localhost

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

 var gulp = require( 'gulp' );
 var g = require( 'gulp-load-plugins' )();
+var exec = require( 'child_process' ).exec;

 var allTestFiles = './tests/**/*.js';

@@ -23,6 +24,10 @@
     });
 });

+gulp.task( 'python', function() {
+  exec( 'python -m SimpleHTTPServer 9001' );
+});
+
 gulp.task( 'default', [ 'assets' ], function() {
   require( './api/app' );
   gulp.watch([ allTestFiles, 'src/ajax.js' ], [ 'test' ]);

<|original_code|>
'use strict';

var gulp = require( 'gulp' );
var g = require( 'gulp-load-plugins' )();

var allTestFiles = './tests/**/*.js';

gulp.task( 'assets', function() {
  gulp.src([
    'node_modules/gulp-mocha/node_modules/mocha/mocha.{js,css}',
    'node_modules/chai/chai.js'
  ])
  .pipe( gulp.dest( 'public' ) );
});

gulp.task( 'test', function( done ) {
  gulp.src([ allTestFiles ])
    .pipe( g.istanbul() )
    .on( 'finish', function() {
      gulp.src([ 'src/ajax.js', allTestFiles ])
      .pipe( g.istanbul.writeReports() )
      .on( 'end', done );
    });
});

gulp.task( 'default', [ 'assets' ], function() {
  require( './api/app' );
  gulp.watch([ allTestFiles, 'src/ajax.js' ], [ 'test' ]);
});
<|edits_diff|>
--- gulpfile.js
+++ gulpfile.js
@@ -2,6 +2,7 @@

 var gulp = require( 'gulp' );
 var g = require( 'gulp-load-plugins' )();
+var exec = require( 'child_process' ).exec;

 var allTestFiles = './tests/**/*.js';

<|current_version|>
'use strict';

var gulp = require( 'gulp' );
var g = require( 'gulp-load-plugins' )();
var exec = require( 'child_process' ).exec;

var allTestFiles = './tests/**/*.js';

gulp.task( 'assets', function() {
  gulp.src([
    'node_modules/gulp-mocha/node_modules/mocha/mocha.{js,css}',
    'node_modules/chai/chai.js'
  ])
  .pipe( gulp.dest( 'public' ) );
});

gulp.task( 'test', function( done ) {
  gulp.src([ allTestFiles ])
    .pipe( g.istanbul() )
    .on( 'finish', function() {
      gulp.src([ 'src/ajax.js', allTestFiles ])
      .pipe( g.istanbul.writeReports() )
      .on( 'end', done );
    });
});

gulp.task( 'default', [ 'assets' ], function() {
  require( './api/app' );
  gulp.watch([ allTestFiles, 'src/ajax.js' ], [ 'test' ]);
});
<|next_version|>
'use strict';

var gulp = require( 'gulp' );
var g = require( 'gulp-load-plugins' )();
var exec = require( 'child_process' ).exec;

var allTestFiles = './tests/**/*.js';

gulp.task( 'assets', function() {
  gulp.src([
    'node_modules/gulp-mocha/node_modules/mocha/mocha.{js,css}',
    'node_modules/chai/chai.js'
  ])
  .pipe( gulp.dest( 'public' ) );
});

gulp.task( 'test', function( done ) {
  gulp.src([ allTestFiles ])
    .pipe( g.istanbul() )
    .on( 'finish', function() {
      gulp.src([ 'src/ajax.js', allTestFiles ])
      .pipe( g.istanbul.writeReports() )
      .on( 'end', done );
    });
});

gulp.task( 'python', function() {
  exec( 'python -m SimpleHTTPServer 9001' );
});

gulp.task( 'default', [ 'assets' ], function() {
  require( './api/app' );
  gulp.watch([ allTestFiles, 'src/ajax.js' ], [ 'test' ]);
});


import React from 'react';

class MainNavigation extends React.Component {
	render() {
		return (
			<div>
			</div>
		);
	}
}

export default MainNavigation;

Add visit site link to navbar

[ADD] Add visit site link to navbar

--- src/client/react/admin/AdminNavbar/MainNavigation.js
+++ src/client/react/admin/AdminNavbar/MainNavigation.js
@@ -1,10 +1,15 @@
 import React from 'react';
+import { Link } from 'react-router-dom';

+const linkStyle = 'pt-button pt-minimal';
+
 class MainNavigation extends React.Component {
+
 	render() {
 		return (

+				Visit site

 		);
 	}

import React from 'react';
import { Link } from 'react-router-dom';

const linkStyle = 'pt-button pt-minimal';

class MainNavigation extends React.Component {

	render() {
		return (
			<div>
			</div>
		);
	}
}

export default MainNavigation;

<|original_code|>
import React from 'react';

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

		);
	}
}

export default MainNavigation;

<|edits_diff|>
--- src/client/react/admin/AdminNavbar/MainNavigation.js
+++ src/client/react/admin/AdminNavbar/MainNavigation.js
@@ -1,7 +1,11 @@
 import React from 'react';
+import { Link } from 'react-router-dom';

+const linkStyle = 'pt-button pt-minimal';
+
 class MainNavigation extends React.Component {
+
 	render() {
 		return (

<|current_version|>
import React from 'react';
import { Link } from 'react-router-dom';

const linkStyle = 'pt-button pt-minimal';

class MainNavigation extends React.Component {

	render() {
		return (

		);
	}
}

export default MainNavigation;

<|next_version|>
import React from 'react';
import { Link } from 'react-router-dom';

const linkStyle = 'pt-button pt-minimal';

class MainNavigation extends React.Component {

	render() {
		return (

				Visit site

		);
	}
}

export default MainNavigation;


Remove useless locales from moment

Remove useless locales from moment

--- next.config.js
+++ next.config.js
@@ -1,8 +1,13 @@
+const webpack = require('webpack')
 const { join } = require('path')
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

 module.exports = {
   webpack: function (config, { dev }) {
+    config.plugins.push(
+      new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /fr/)
+    )
+
     if (!dev) {
       config.plugins.push(new BundleAnalyzerPlugin({
         analyzerMode: 'static',

<|original_code|>
const { join } = require('path')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  webpack: function (config, { dev }) {
    if (!dev) {
      config.plugins.push(new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        reportFilename: join(__dirname, 'reports/bundles.html'),
        defaultSizes: 'gzip'
      }))
    }

    return config
  }
}

<|edits_diff|>
--- next.config.js
+++ next.config.js
@@ -1,3 +1,4 @@
+const webpack = require('webpack')
 const { join } = require('path')
 const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

<|current_version|>
const webpack = require('webpack')
const { join } = require('path')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  webpack: function (config, { dev }) {
    if (!dev) {
      config.plugins.push(new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        reportFilename: join(__dirname, 'reports/bundles.html'),
        defaultSizes: 'gzip'
      }))
    }

    return config
  }
}

<|next_version|>
const webpack = require('webpack')
const { join } = require('path')
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')

module.exports = {
  webpack: function (config, { dev }) {
    config.plugins.push(
      new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /fr/)
    )

    if (!dev) {
      config.plugins.push(new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        reportFilename: join(__dirname, 'reports/bundles.html'),
        defaultSizes: 'gzip'
      }))
    }

    return config
  }
}


Disable globalShortcut spec on Windows CI

--- spec/api-global-shortcut-spec.js
+++ spec/api-global-shortcut-spec.js
@@ -1,7 +1,13 @@
 const {globalShortcut} = require('electron').remote
 const assert = require('assert')

+const isCI = require('electron').remote.getGlobal('isCi')
+
 describe('globalShortcut module', () => {
+  if (isCI && process.platform === 'win32') {
+    return
+  }
+
   beforeEach(() => {
     globalShortcut.unregisterAll()
   })

<|original_code|>
const {globalShortcut} = require('electron').remote
const assert = require('assert')

describe('globalShortcut module', () => {
  beforeEach(() => {
    globalShortcut.unregisterAll()
  })

  it('can register and unregister accelerators', () => {
    const accelerator = 'CommandOrControl+A+B+C'

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregister(accelerator)
    assert.equal(globalShortcut.isRegistered(accelerator), false)

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregisterAll()
    assert.equal(globalShortcut.isRegistered(accelerator), false)
  })
})

<|edits_diff|>
--- spec/api-global-shortcut-spec.js
+++ spec/api-global-shortcut-spec.js
@@ -1,5 +1,7 @@
 const {globalShortcut} = require('electron').remote
 const assert = require('assert')
+
+const isCI = require('electron').remote.getGlobal('isCi')

 describe('globalShortcut module', () => {
   beforeEach(() => {
<|current_version|>
const {globalShortcut} = require('electron').remote
const assert = require('assert')

const isCI = require('electron').remote.getGlobal('isCi')

describe('globalShortcut module', () => {
  beforeEach(() => {
    globalShortcut.unregisterAll()
  })

  it('can register and unregister accelerators', () => {
    const accelerator = 'CommandOrControl+A+B+C'

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregister(accelerator)
    assert.equal(globalShortcut.isRegistered(accelerator), false)

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregisterAll()
    assert.equal(globalShortcut.isRegistered(accelerator), false)
  })
})

<|next_version|>
const {globalShortcut} = require('electron').remote
const assert = require('assert')

const isCI = require('electron').remote.getGlobal('isCi')

describe('globalShortcut module', () => {
  if (isCI && process.platform === 'win32') {
    return
  }

  beforeEach(() => {
    globalShortcut.unregisterAll()
  })

  it('can register and unregister accelerators', () => {
    const accelerator = 'CommandOrControl+A+B+C'

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregister(accelerator)
    assert.equal(globalShortcut.isRegistered(accelerator), false)

    assert.equal(globalShortcut.isRegistered(accelerator), false)
    globalShortcut.register(accelerator, () => {})
    assert.equal(globalShortcut.isRegistered(accelerator), true)
    globalShortcut.unregisterAll()
    assert.equal(globalShortcut.isRegistered(accelerator), false)
  })
})


Add new `variance` state to appearance

Add new `variance` state to appearance

--- app/transforms/appearance-status.js
+++ app/transforms/appearance-status.js
@@ -7,6 +7,7 @@
       7: 'Built',
       10: 'Started',
       20: 'Finished',
+      25: 'Variance',
       30: 'Verified',
     };
     return map[serialized];
@@ -18,6 +19,7 @@
       'Built': 7,
       'Started': 10,
       'Finished': 20,
+      'Variance': 25,
       'Verified': 30,
     };
     return map[deserialized];

<|original_code|>
import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize: function(serialized) {
    var map = {
      0: 'New',
      7: 'Built',
      10: 'Started',
      20: 'Finished',
      30: 'Verified',
    };
    return map[serialized];
  },

  serialize: function(deserialized) {
    var map = {
      'New': 0,
      'Built': 7,
      'Started': 10,
      'Finished': 20,
      'Verified': 30,
    };
    return map[deserialized];
  }
});

<|edits_diff|>
--- app/transforms/appearance-status.js
+++ app/transforms/appearance-status.js
@@ -7,6 +7,7 @@
       7: 'Built',
       10: 'Started',
       20: 'Finished',
+      25: 'Variance',
       30: 'Verified',
     };
     return map[serialized];
<|current_version|>
import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize: function(serialized) {
    var map = {
      0: 'New',
      7: 'Built',
      10: 'Started',
      20: 'Finished',
      25: 'Variance',
      30: 'Verified',
    };
    return map[serialized];
  },

  serialize: function(deserialized) {
    var map = {
      'New': 0,
      'Built': 7,
      'Started': 10,
      'Finished': 20,
      'Verified': 30,
    };
    return map[deserialized];
  }
});

<|next_version|>
import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize: function(serialized) {
    var map = {
      0: 'New',
      7: 'Built',
      10: 'Started',
      20: 'Finished',
      25: 'Variance',
      30: 'Verified',
    };
    return map[serialized];
  },

  serialize: function(deserialized) {
    var map = {
      'New': 0,
      'Built': 7,
      'Started': 10,
      'Finished': 20,
      'Variance': 25,
      'Verified': 30,
    };
    return map[deserialized];
  }
});


Add TODO related to the auto-request hook feature

--- lib/hooks.js
+++ lib/hooks.js
@@ -5,7 +5,11 @@
 var asyncState = require('./async-state')

 module.exports = function (client) {
+  // TODO: This will actual just use the logger of the last client parsed in.
+  // In most use-cases this is a non-issue, but if someone tries to initiate
+  // multiple clients with different loggers, this will get weird
   shimmer({ logger: client.logger.error })
+
   shimmer.massWrap(http.Server.prototype, ['on', 'addListener'], function (fn) {
     return function (event, listener) {
       if (event === 'request' && typeof listener === 'function') return fn.call(this, event, onRequest)

<|original_code|>
'use strict'

var http = require('http')
var shimmer = require('shimmer')
var asyncState = require('./async-state')

module.exports = function (client) {
  shimmer({ logger: client.logger.error })
  shimmer.massWrap(http.Server.prototype, ['on', 'addListener'], function (fn) {
    return function (event, listener) {
      if (event === 'request' && typeof listener === 'function') return fn.call(this, event, onRequest)
      else return fn.apply(this, arguments)

      function onRequest (req, res) {
        asyncState.req = req
        listener.apply(this, arguments)
      }
    }
  })
}

<|edits_diff|>
--- lib/hooks.js
+++ lib/hooks.js
@@ -5,6 +5,9 @@
 var asyncState = require('./async-state')

 module.exports = function (client) {
+  // TODO: This will actual just use the logger of the last client parsed in.
+  // In most use-cases this is a non-issue, but if someone tries to initiate
+  // multiple clients with different loggers, this will get weird
   shimmer({ logger: client.logger.error })
   shimmer.massWrap(http.Server.prototype, ['on', 'addListener'], function (fn) {
     return function (event, listener) {
<|current_version|>
'use strict'

var http = require('http')
var shimmer = require('shimmer')
var asyncState = require('./async-state')

module.exports = function (client) {
  // TODO: This will actual just use the logger of the last client parsed in.
  // In most use-cases this is a non-issue, but if someone tries to initiate
  // multiple clients with different loggers, this will get weird
  shimmer({ logger: client.logger.error })
  shimmer.massWrap(http.Server.prototype, ['on', 'addListener'], function (fn) {
    return function (event, listener) {
      if (event === 'request' && typeof listener === 'function') return fn.call(this, event, onRequest)
      else return fn.apply(this, arguments)

      function onRequest (req, res) {
        asyncState.req = req
        listener.apply(this, arguments)
      }
    }
  })
}

<|next_version|>
'use strict'

var http = require('http')
var shimmer = require('shimmer')
var asyncState = require('./async-state')

module.exports = function (client) {
  // TODO: This will actual just use the logger of the last client parsed in.
  // In most use-cases this is a non-issue, but if someone tries to initiate
  // multiple clients with different loggers, this will get weird
  shimmer({ logger: client.logger.error })

  shimmer.massWrap(http.Server.prototype, ['on', 'addListener'], function (fn) {
    return function (event, listener) {
      if (event === 'request' && typeof listener === 'function') return fn.call(this, event, onRequest)
      else return fn.apply(this, arguments)

      function onRequest (req, res) {
        asyncState.req = req
        listener.apply(this, arguments)
      }
    }
  })
}


Add YUI Doc tags to documentation blocks.

--- lib/mime.js
+++ lib/mime.js
@@ -5,9 +5,16 @@
  */

 /**
+ * @module mime
+ */
+
+/**
  * File extension to MIME type map.
  *
  * Used by `serve.js` when streaming files from disk.
+ *
+ * @property contentTypes
+ * @type object
  */
 this.contentTypes = {
   "css": "text/css",

<|original_code|>
/*!
 * YUI Mocha
 * Copyright 2011 Yahoo! Inc.
 * Licensed under the BSD license.
 */

/**
 * File extension to MIME type map.
 *
 * Used by `serve.js` when streaming files from disk.
 */
this.contentTypes = {
  "css": "text/css",
  "html": "text/html",
  "ico": "image/vnd.microsoft.icon",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "application/javascript",
  "json": "application/json",
  "less": "text/css",
  "png": "image/png",
  "svg": "image/svg+xml",
  "swf": "application/x-shockwave-flash",
  "tiff": "image/tiff",
  "txt": "text/plain",
  "xml": "text/xml"
};

<|edits_diff|>
--- lib/mime.js
+++ lib/mime.js
@@ -2,6 +2,10 @@
  * YUI Mocha
  * Copyright 2011 Yahoo! Inc.
  * Licensed under the BSD license.
+ */
+
+/**
+ * @module mime
  */

 /**
<|current_version|>
/*!
 * YUI Mocha
 * Copyright 2011 Yahoo! Inc.
 * Licensed under the BSD license.
 */

/**
 * @module mime
 */

/**
 * File extension to MIME type map.
 *
 * Used by `serve.js` when streaming files from disk.
 */
this.contentTypes = {
  "css": "text/css",
  "html": "text/html",
  "ico": "image/vnd.microsoft.icon",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "application/javascript",
  "json": "application/json",
  "less": "text/css",
  "png": "image/png",
  "svg": "image/svg+xml",
  "swf": "application/x-shockwave-flash",
  "tiff": "image/tiff",
  "txt": "text/plain",
  "xml": "text/xml"
};

<|next_version|>
/*!
 * YUI Mocha
 * Copyright 2011 Yahoo! Inc.
 * Licensed under the BSD license.
 */

/**
 * @module mime
 */

/**
 * File extension to MIME type map.
 *
 * Used by `serve.js` when streaming files from disk.
 *
 * @property contentTypes
 * @type object
 */
this.contentTypes = {
  "css": "text/css",
  "html": "text/html",
  "ico": "image/vnd.microsoft.icon",
  "jpeg": "image/jpeg",
  "jpg": "image/jpeg",
  "js": "application/javascript",
  "json": "application/json",
  "less": "text/css",
  "png": "image/png",
  "svg": "image/svg+xml",
  "swf": "application/x-shockwave-flash",
  "tiff": "image/tiff",
  "txt": "text/plain",
  "xml": "text/xml"
};


Return the event object when you call on, once or off

--- js/events.js
+++ js/events.js
@@ -9,6 +9,7 @@
           listeners[type] = []
         if (listeners[type].indexOf(cb) < 0)
           listeners[type].push(cb)
+        return this;
       },
       once: function(type, cb)
       {
@@ -17,6 +18,7 @@
           this.off(type, observer)
           cb.apply(this, arguments)
         })
+        return this;
       },
       emit: function(type)
       {
@@ -54,6 +56,7 @@
         {
           listeners[type].splice(index, 1);
         }
+        return this;
       },
     })
   }

<|original_code|>
  function Events()
  {
    var listeners = {}

    $.extend(this, {
      on: function(type, cb)
      {
        if (!$.isArray(listeners[type]))
          listeners[type] = []
        if (listeners[type].indexOf(cb) < 0)
          listeners[type].push(cb)
      },
      once: function(type, cb)
      {
        this.on(type, function observer()
        {
          this.off(type, observer)
          cb.apply(this, arguments)
        })
      },
      emit: function(type)
      {
        var result = []

        if (!$.isArray(listeners[type]))
          listeners[type] = []

        var args = Array.prototype.slice.call(arguments, 1)
        var cbs = listeners[type].slice()
        while (cbs.length > 0)
        {
          result.push(cbs.shift().apply(this, args))
        }

        return result
      },
      call: function(type)
      {
        var result = this.emit.apply(this, arguments)
        if (result.length > 1)
          warn("Too many results, choosing the first one")
        return result[0]
      },
      off: function(type, cb)
      {
        if (cb == undefined)
          throw new Error("You cannot remove all listeners on an event")

        if (!$.isFunction(cb))
          throw new Error("You must pass a listener to Event.off")

        var index = listeners[type].indexOf(cb)
        if (index != undefined && index >= 0)
        {
          listeners[type].splice(index, 1);
        }
      },
    })
  }

<|edits_diff|>
--- js/events.js
+++ js/events.js
@@ -9,6 +9,7 @@
           listeners[type] = []
         if (listeners[type].indexOf(cb) < 0)
           listeners[type].push(cb)
+        return this;
       },
       once: function(type, cb)
       {
@@ -17,6 +18,7 @@
           this.off(type, observer)
           cb.apply(this, arguments)
         })
+        return this;
       },
       emit: function(type)
       {
<|current_version|>
  function Events()
  {
    var listeners = {}

    $.extend(this, {
      on: function(type, cb)
      {
        if (!$.isArray(listeners[type]))
          listeners[type] = []
        if (listeners[type].indexOf(cb) < 0)
          listeners[type].push(cb)
        return this;
      },
      once: function(type, cb)
      {
        this.on(type, function observer()
        {
          this.off(type, observer)
          cb.apply(this, arguments)
        })
        return this;
      },
      emit: function(type)
      {
        var result = []

        if (!$.isArray(listeners[type]))
          listeners[type] = []

        var args = Array.prototype.slice.call(arguments, 1)
        var cbs = listeners[type].slice()
        while (cbs.length > 0)
        {
          result.push(cbs.shift().apply(this, args))
        }

        return result
      },
      call: function(type)
      {
        var result = this.emit.apply(this, arguments)
        if (result.length > 1)
          warn("Too many results, choosing the first one")
        return result[0]
      },
      off: function(type, cb)
      {
        if (cb == undefined)
          throw new Error("You cannot remove all listeners on an event")

        if (!$.isFunction(cb))
          throw new Error("You must pass a listener to Event.off")

        var index = listeners[type].indexOf(cb)
        if (index != undefined && index >= 0)
        {
          listeners[type].splice(index, 1);
        }
      },
    })
  }

<|next_version|>
  function Events()
  {
    var listeners = {}

    $.extend(this, {
      on: function(type, cb)
      {
        if (!$.isArray(listeners[type]))
          listeners[type] = []
        if (listeners[type].indexOf(cb) < 0)
          listeners[type].push(cb)
        return this;
      },
      once: function(type, cb)
      {
        this.on(type, function observer()
        {
          this.off(type, observer)
          cb.apply(this, arguments)
        })
        return this;
      },
      emit: function(type)
      {
        var result = []

        if (!$.isArray(listeners[type]))
          listeners[type] = []

        var args = Array.prototype.slice.call(arguments, 1)
        var cbs = listeners[type].slice()
        while (cbs.length > 0)
        {
          result.push(cbs.shift().apply(this, args))
        }

        return result
      },
      call: function(type)
      {
        var result = this.emit.apply(this, arguments)
        if (result.length > 1)
          warn("Too many results, choosing the first one")
        return result[0]
      },
      off: function(type, cb)
      {
        if (cb == undefined)
          throw new Error("You cannot remove all listeners on an event")

        if (!$.isFunction(cb))
          throw new Error("You must pass a listener to Event.off")

        var index = listeners[type].indexOf(cb)
        if (index != undefined && index >= 0)
        {
          listeners[type].splice(index, 1);
        }
        return this;
      },
    })
  }


Add explicit rule for arrow functions and add support for es6 globals

--- .eslintrc.js
+++ .eslintrc.js
@@ -6,9 +6,15 @@
     "comma-dangle": ["error", "always-multiline"],
     quotes: ["error", "backtick"],
     semi: ["error", "never"],
+    "arrow-body-style": [
+      "error",
+      "as-needed",
+      { requireReturnForObjectLiteral: true },
+    ],
   },
   env: {
     node: true,
+    es6: true,
   },
   parserOptions: {
     ecmaVersion: 2017,

<|original_code|>
module.exports = {
  extends: "eslint:recommended",
  rules: {
    "no-console": 0,
    "object-curly-spacing": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    quotes: ["error", "backtick"],
    semi: ["error", "never"],
  },
  env: {
    node: true,
  },
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module",
  },
}

<|edits_diff|>
--- .eslintrc.js
+++ .eslintrc.js
@@ -6,6 +6,11 @@
     "comma-dangle": ["error", "always-multiline"],
     quotes: ["error", "backtick"],
     semi: ["error", "never"],
+    "arrow-body-style": [
+      "error",
+      "as-needed",
+      { requireReturnForObjectLiteral: true },
+    ],
   },
   env: {
     node: true,
<|current_version|>
module.exports = {
  extends: "eslint:recommended",
  rules: {
    "no-console": 0,
    "object-curly-spacing": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    quotes: ["error", "backtick"],
    semi: ["error", "never"],
    "arrow-body-style": [
      "error",
      "as-needed",
      { requireReturnForObjectLiteral: true },
    ],
  },
  env: {
    node: true,
  },
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module",
  },
}

<|next_version|>
module.exports = {
  extends: "eslint:recommended",
  rules: {
    "no-console": 0,
    "object-curly-spacing": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    quotes: ["error", "backtick"],
    semi: ["error", "never"],
    "arrow-body-style": [
      "error",
      "as-needed",
      { requireReturnForObjectLiteral: true },
    ],
  },
  env: {
    node: true,
    es6: true,
  },
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module",
  },
}


Add timeouts to protractor demo

Add timeouts to protractor demo

--- protractor-demo/conf.js
+++ protractor-demo/conf.js
@@ -8,6 +8,8 @@
     'browserName': 'chrome'
   },

+  allScriptsTimeout: 11000,
+
   // Spec patterns are relative to the location of the spec file. They may
   // include glob patterns.
   specs: ['*.spec.js'],
@@ -15,5 +17,6 @@
   // Options to be passed to Jasmine-node.
   jasmineNodeOpts: {
     showColors: true, // Use colors in the command line report.
+    defaultTimeoutInterval: 30000
   }
 };

<|original_code|>
// An example configuration file.
exports.config = {
  // The address of a running selenium server.
  //seleniumAddress: 'http://localhost:4444/wd/hub',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  specs: ['*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
  }
};
<|edits_diff|>
--- protractor-demo/conf.js
+++ protractor-demo/conf.js
@@ -8,6 +8,8 @@
     'browserName': 'chrome'
   },

+  allScriptsTimeout: 11000,
+
   // Spec patterns are relative to the location of the spec file. They may
   // include glob patterns.
   specs: ['*.spec.js'],
<|current_version|>
// An example configuration file.
exports.config = {
  // The address of a running selenium server.
  //seleniumAddress: 'http://localhost:4444/wd/hub',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  allScriptsTimeout: 11000,

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  specs: ['*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
  }
};
<|next_version|>
// An example configuration file.
exports.config = {
  // The address of a running selenium server.
  //seleniumAddress: 'http://localhost:4444/wd/hub',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  allScriptsTimeout: 11000,

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  specs: ['*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
    defaultTimeoutInterval: 30000
  }
};


Comment added to the JS code

Comment added to the JS code

--- js/chartist2image-with-svg2bitmap.js
+++ js/chartist2image-with-svg2bitmap.js
@@ -1,5 +1,6 @@
 window.onload = function() {

+  // using true as the second parameter we force chartist.js to use plain SVG not <foreignObject>
   createChart('.ct-chart', true);

   document.getElementById('button1').onclick = function () {
@@ -7,6 +8,7 @@
     var chartDivNode = document.getElementById('chart');
     var chartSvgNode = chartDivNode.children[0];

+    // SVG2Bitmap will render the chartist SVG code and create all necessary inline styles
     SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
   };

<|original_code|>
window.onload = function() {

  createChart('.ct-chart', true);

  document.getElementById('button1').onclick = function () {

    var chartDivNode = document.getElementById('chart');
    var chartSvgNode = chartDivNode.children[0];

    SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
  };

  document.getElementById('button2').onclick = function () {

    var dataURL = document.getElementById('canvas').toDataURL();
    document.getElementById('image').src = dataURL;
  };
}

<|edits_diff|>
--- js/chartist2image-with-svg2bitmap.js
+++ js/chartist2image-with-svg2bitmap.js
@@ -1,5 +1,6 @@
 window.onload = function() {

+  // using true as the second parameter we force chartist.js to use plain SVG not <foreignObject>
   createChart('.ct-chart', true);

   document.getElementById('button1').onclick = function () {
<|current_version|>
window.onload = function() {

  // using true as the second parameter we force chartist.js to use plain SVG not <foreignObject>
  createChart('.ct-chart', true);

  document.getElementById('button1').onclick = function () {

    var chartDivNode = document.getElementById('chart');
    var chartSvgNode = chartDivNode.children[0];

    SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
  };

  document.getElementById('button2').onclick = function () {

    var dataURL = document.getElementById('canvas').toDataURL();
    document.getElementById('image').src = dataURL;
  };
}

<|next_version|>
window.onload = function() {

  // using true as the second parameter we force chartist.js to use plain SVG not <foreignObject>
  createChart('.ct-chart', true);

  document.getElementById('button1').onclick = function () {

    var chartDivNode = document.getElementById('chart');
    var chartSvgNode = chartDivNode.children[0];

    // SVG2Bitmap will render the chartist SVG code and create all necessary inline styles
    SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
  };

  document.getElementById('button2').onclick = function () {

    var dataURL = document.getElementById('canvas').toDataURL();
    document.getElementById('image').src = dataURL;
  };
}


Apply the logger as middleware

Apply the logger as middleware

--- frontend/src/core/Store.js
+++ frontend/src/core/Store.js
@@ -1,10 +1,14 @@
 import {createStore, compose, applyMiddleware} from 'redux';
 import {devTools, persistState} from 'redux-devtools';
 import thunkMiddleware from 'redux-thunk';
+import createLogger from 'redux-logger';
 import travelApp from 'reducers/Reducers.js';
+
+const logger = createLogger();

 const enhancedCreateStore = compose(
   applyMiddleware(
+    logger,
     thunkMiddleware),
   devTools(),
   persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))

<|original_code|>
import {createStore, compose, applyMiddleware} from 'redux';
import {devTools, persistState} from 'redux-devtools';
import thunkMiddleware from 'redux-thunk';
import travelApp from 'reducers/Reducers.js';

const enhancedCreateStore = compose(
  applyMiddleware(
    thunkMiddleware),
  devTools(),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);

export default enhancedCreateStore(travelApp);

<|edits_diff|>
--- frontend/src/core/Store.js
+++ frontend/src/core/Store.js
@@ -1,7 +1,10 @@
 import {createStore, compose, applyMiddleware} from 'redux';
 import {devTools, persistState} from 'redux-devtools';
 import thunkMiddleware from 'redux-thunk';
+import createLogger from 'redux-logger';
 import travelApp from 'reducers/Reducers.js';
+
+const logger = createLogger();

 const enhancedCreateStore = compose(
   applyMiddleware(
<|current_version|>
import {createStore, compose, applyMiddleware} from 'redux';
import {devTools, persistState} from 'redux-devtools';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import travelApp from 'reducers/Reducers.js';

const logger = createLogger();

const enhancedCreateStore = compose(
  applyMiddleware(
    thunkMiddleware),
  devTools(),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);

export default enhancedCreateStore(travelApp);

<|next_version|>
import {createStore, compose, applyMiddleware} from 'redux';
import {devTools, persistState} from 'redux-devtools';
import thunkMiddleware from 'redux-thunk';
import createLogger from 'redux-logger';
import travelApp from 'reducers/Reducers.js';

const logger = createLogger();

const enhancedCreateStore = compose(
  applyMiddleware(
    logger,
    thunkMiddleware),
  devTools(),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
)(createStore);

export default enhancedCreateStore(travelApp);


Add to auth and signup component

Add to auth and signup component

--- client/app/components/components.js
+++ client/app/components/components.js
@@ -1,4 +1,6 @@
 import angular from 'angular';
+import Auth from './auth/auth';
+import Signup from './signup/signup';
 import Dogs from './dogs/dogs';
 import DogProfile from './dog-profile/dog-profile';
 import Users from './users/users';
@@ -6,6 +8,8 @@
 import UserPost from './user-post/user-post';

 let componentModule = angular.module('app.components', [
+  Signup,
+  Auth,
   Dogs,
   Users,
   DogProfile,

<|original_code|>
import angular from 'angular';
import Dogs from './dogs/dogs';
import DogProfile from './dog-profile/dog-profile';
import Users from './users/users';
import DogPost from './dog-post/dog-post';
import UserPost from './user-post/user-post';

let componentModule = angular.module('app.components', [
  Dogs,
  Users,
  DogProfile,
  DogPost,
  UserPost
])
  .name;

export default componentModule;

<|edits_diff|>
--- client/app/components/components.js
+++ client/app/components/components.js
@@ -1,4 +1,6 @@
 import angular from 'angular';
+import Auth from './auth/auth';
+import Signup from './signup/signup';
 import Dogs from './dogs/dogs';
 import DogProfile from './dog-profile/dog-profile';
 import Users from './users/users';
<|current_version|>
import angular from 'angular';
import Auth from './auth/auth';
import Signup from './signup/signup';
import Dogs from './dogs/dogs';
import DogProfile from './dog-profile/dog-profile';
import Users from './users/users';
import DogPost from './dog-post/dog-post';
import UserPost from './user-post/user-post';

let componentModule = angular.module('app.components', [
  Dogs,
  Users,
  DogProfile,
  DogPost,
  UserPost
])
  .name;

export default componentModule;

<|next_version|>
import angular from 'angular';
import Auth from './auth/auth';
import Signup from './signup/signup';
import Dogs from './dogs/dogs';
import DogProfile from './dog-profile/dog-profile';
import Users from './users/users';
import DogPost from './dog-post/dog-post';
import UserPost from './user-post/user-post';

let componentModule = angular.module('app.components', [
  Signup,
  Auth,
  Dogs,
  Users,
  DogProfile,
  DogPost,
  UserPost
])
  .name;

export default componentModule;


Set ApplicationInsights batch size to 1

Set ApplicationInsights batch size to 1

Set the batch size for ApplicationInsights to 1 to try and prevent setTimeout() ever being called and causing the lambda function to timeout from hanging.
Relates to #45.

--- src/telemetry.js
+++ src/telemetry.js
@@ -17,7 +17,12 @@

 telemetry.createClient = function () {
   var client = new appInsights.TelemetryClient(telemetry.instrumentationKey);
+
+  // Prevent Lambda function from hanging and timing out.
+  // See https://github.com/martincostello/alexa-london-travel/issues/45.
   client.config.maxBatchIntervalMs = 0;
+  client.config.maxBatchSize = 1;
+
   return client;
 };

<|original_code|>
// Copyright (c) Martin Costello, 2017. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

"use strict";

var appInsights = require("applicationinsights");

const telemetry = {
  appInsights: appInsights,
  trackEvent: function () {
  },
  trackException: function () {
  }
};

telemetry.instrumentationKey = "";

telemetry.createClient = function () {
  var client = new appInsights.TelemetryClient(telemetry.instrumentationKey);
  client.config.maxBatchIntervalMs = 0;
  return client;
};

/**
 * Sets up collection of telemetry.
 * @param {String} [instrumentationKey=null] - The optional instrumentation key to use.
 */
telemetry.setup = function (instrumentationKey) {
  if (instrumentationKey) {

    telemetry.instrumentationKey = instrumentationKey;

    telemetry.appInsights.setup(instrumentationKey).start();

    telemetry.trackEvent = function (name, properties) {
      telemetry.createClient().trackEvent({
        name: name,
        properties: properties
      });
    };

    telemetry.trackException = function (exception, properties) {
      telemetry.createClient().trackException({
        exception: exception,
        properties: properties
      });
    };
  }
};

module.exports = telemetry;

<|edits_diff|>
--- src/telemetry.js
+++ src/telemetry.js
@@ -17,6 +17,9 @@

 telemetry.createClient = function () {
   var client = new appInsights.TelemetryClient(telemetry.instrumentationKey);
+
+  // Prevent Lambda function from hanging and timing out.
+  // See https://github.com/martincostello/alexa-london-travel/issues/45.
   client.config.maxBatchIntervalMs = 0;
   return client;
 };
<|current_version|>
// Copyright (c) Martin Costello, 2017. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

"use strict";

var appInsights = require("applicationinsights");

const telemetry = {
  appInsights: appInsights,
  trackEvent: function () {
  },
  trackException: function () {
  }
};

telemetry.instrumentationKey = "";

telemetry.createClient = function () {
  var client = new appInsights.TelemetryClient(telemetry.instrumentationKey);

  // Prevent Lambda function from hanging and timing out.
  // See https://github.com/martincostello/alexa-london-travel/issues/45.
  client.config.maxBatchIntervalMs = 0;
  return client;
};

/**
 * Sets up collection of telemetry.
 * @param {String} [instrumentationKey=null] - The optional instrumentation key to use.
 */
telemetry.setup = function (instrumentationKey) {
  if (instrumentationKey) {

    telemetry.instrumentationKey = instrumentationKey;

    telemetry.appInsights.setup(instrumentationKey).start();

    telemetry.trackEvent = function (name, properties) {
      telemetry.createClient().trackEvent({
        name: name,
        properties: properties
      });
    };

    telemetry.trackException = function (exception, properties) {
      telemetry.createClient().trackException({
        exception: exception,
        properties: properties
      });
    };
  }
};

module.exports = telemetry;

<|next_version|>
// Copyright (c) Martin Costello, 2017. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

"use strict";

var appInsights = require("applicationinsights");

const telemetry = {
  appInsights: appInsights,
  trackEvent: function () {
  },
  trackException: function () {
  }
};

telemetry.instrumentationKey = "";

telemetry.createClient = function () {
  var client = new appInsights.TelemetryClient(telemetry.instrumentationKey);

  // Prevent Lambda function from hanging and timing out.
  // See https://github.com/martincostello/alexa-london-travel/issues/45.
  client.config.maxBatchIntervalMs = 0;
  client.config.maxBatchSize = 1;

  return client;
};

/**
 * Sets up collection of telemetry.
 * @param {String} [instrumentationKey=null] - The optional instrumentation key to use.
 */
telemetry.setup = function (instrumentationKey) {
  if (instrumentationKey) {

    telemetry.instrumentationKey = instrumentationKey;

    telemetry.appInsights.setup(instrumentationKey).start();

    telemetry.trackEvent = function (name, properties) {
      telemetry.createClient().trackEvent({
        name: name,
        properties: properties
      });
    };

    telemetry.trackException = function (exception, properties) {
      telemetry.createClient().trackException({
        exception: exception,
        properties: properties
      });
    };
  }
};

module.exports = telemetry;


Set password in redux to empty string on successful login

--- ukelonn.web.frontend/src/main/frontend/reducers/passwordReducer.js
+++ ukelonn.web.frontend/src/main/frontend/reducers/passwordReducer.js
@@ -1,6 +1,8 @@
 import { createReducer } from 'redux-starter-kit';
 import {
     UPDATE,
+    LOGIN_RECEIVE,
+    INITIAL_LOGIN_STATE_RECEIVE,
 } from '../actiontypes';

 const passwordReducer = createReducer(null, {
@@ -10,6 +12,8 @@
         }
         return action.payload.password;
     },
+    [LOGIN_RECEIVE]: (state, action) => '',
+    [INITIAL_LOGIN_STATE_RECEIVE]: (state, action) => '',
 });

 export default passwordReducer;

<|original_code|>
import { createReducer } from 'redux-starter-kit';
import {
    UPDATE,
} from '../actiontypes';

const passwordReducer = createReducer(null, {
    [UPDATE]: (state, action) => {
        if (!(action.payload && action.payload.password)) {
            return state;
        }
        return action.payload.password;
    },
});

export default passwordReducer;

<|edits_diff|>
--- ukelonn.web.frontend/src/main/frontend/reducers/passwordReducer.js
+++ ukelonn.web.frontend/src/main/frontend/reducers/passwordReducer.js
@@ -1,6 +1,8 @@
 import { createReducer } from 'redux-starter-kit';
 import {
     UPDATE,
+    LOGIN_RECEIVE,
+    INITIAL_LOGIN_STATE_RECEIVE,
 } from '../actiontypes';

 const passwordReducer = createReducer(null, {
<|current_version|>
import { createReducer } from 'redux-starter-kit';
import {
    UPDATE,
    LOGIN_RECEIVE,
    INITIAL_LOGIN_STATE_RECEIVE,
} from '../actiontypes';

const passwordReducer = createReducer(null, {
    [UPDATE]: (state, action) => {
        if (!(action.payload && action.payload.password)) {
            return state;
        }
        return action.payload.password;
    },
});

export default passwordReducer;

<|next_version|>
import { createReducer } from 'redux-starter-kit';
import {
    UPDATE,
    LOGIN_RECEIVE,
    INITIAL_LOGIN_STATE_RECEIVE,
} from '../actiontypes';

const passwordReducer = createReducer(null, {
    [UPDATE]: (state, action) => {
        if (!(action.payload && action.payload.password)) {
            return state;
        }
        return action.payload.password;
    },
    [LOGIN_RECEIVE]: (state, action) => '',
    [INITIAL_LOGIN_STATE_RECEIVE]: (state, action) => '',
});

export default passwordReducer;


Mark as answered to disable all matrix input types

--- app/assets/javascripts/respondent/question_answered.js
+++ app/assets/javascripts/respondent/question_answered.js
@@ -10,6 +10,7 @@
       $("li.answer-option-"+the_id+" textarea").attr("disabled", true)
       $("select#answers_"+the_id).attr("disabled", true)
       $(matrix_answer_field).find('select').attr("disabled", true)
+      $(matrix_answer_field).find('input').attr("disabled", true)
     }
     else {
       $(text_answer_field).attr("disabled", false)
@@ -19,6 +20,7 @@
       $("li.answer-option-"+the_id+" textarea").attr("disabled", false)
       $("select#answers_"+the_id).attr("disabled", false)
       $(matrix_answer_field).find('select').attr("disabled", false)
+      $(matrix_answer_field).find('input').attr("disabled", false)
       $('.sticky_save_all').click();
     }
   });

<|original_code|>
$(document).ready(function() {
  $(document).on('change', '.question-answered-box', function(){
    the_id = $(this).data('the-id')
    text_answer_field = $(this).closest('.text-answer').find('.text-answer-field')
    matrix_answer_field = $(this).closest('.answer_fields_wrapper').find('.submission-matrix')
    if($(this).prop('checked')) {
      $(text_answer_field).attr("readonly", true)
      $(text_answer_field).addClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", true)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", true)
      $("select#answers_"+the_id).attr("disabled", true)
      $(matrix_answer_field).find('select').attr("disabled", true)
    }
    else {
      $(text_answer_field).attr("disabled", false)
      $(text_answer_field).attr("readonly", false)
      $(text_answer_field).removeClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", false)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", false)
      $("select#answers_"+the_id).attr("disabled", false)
      $(matrix_answer_field).find('select').attr("disabled", false)
      $('.sticky_save_all').click();
    }
  });
});

<|edits_diff|>
--- app/assets/javascripts/respondent/question_answered.js
+++ app/assets/javascripts/respondent/question_answered.js
@@ -10,6 +10,7 @@
       $("li.answer-option-"+the_id+" textarea").attr("disabled", true)
       $("select#answers_"+the_id).attr("disabled", true)
       $(matrix_answer_field).find('select').attr("disabled", true)
+      $(matrix_answer_field).find('input').attr("disabled", true)
     }
     else {
       $(text_answer_field).attr("disabled", false)
<|current_version|>
$(document).ready(function() {
  $(document).on('change', '.question-answered-box', function(){
    the_id = $(this).data('the-id')
    text_answer_field = $(this).closest('.text-answer').find('.text-answer-field')
    matrix_answer_field = $(this).closest('.answer_fields_wrapper').find('.submission-matrix')
    if($(this).prop('checked')) {
      $(text_answer_field).attr("readonly", true)
      $(text_answer_field).addClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", true)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", true)
      $("select#answers_"+the_id).attr("disabled", true)
      $(matrix_answer_field).find('select').attr("disabled", true)
      $(matrix_answer_field).find('input').attr("disabled", true)
    }
    else {
      $(text_answer_field).attr("disabled", false)
      $(text_answer_field).attr("readonly", false)
      $(text_answer_field).removeClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", false)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", false)
      $("select#answers_"+the_id).attr("disabled", false)
      $(matrix_answer_field).find('select').attr("disabled", false)
      $('.sticky_save_all').click();
    }
  });
});

<|next_version|>
$(document).ready(function() {
  $(document).on('change', '.question-answered-box', function(){
    the_id = $(this).data('the-id')
    text_answer_field = $(this).closest('.text-answer').find('.text-answer-field')
    matrix_answer_field = $(this).closest('.answer_fields_wrapper').find('.submission-matrix')
    if($(this).prop('checked')) {
      $(text_answer_field).attr("readonly", true)
      $(text_answer_field).addClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", true)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", true)
      $("select#answers_"+the_id).attr("disabled", true)
      $(matrix_answer_field).find('select').attr("disabled", true)
      $(matrix_answer_field).find('input').attr("disabled", true)
    }
    else {
      $(text_answer_field).attr("disabled", false)
      $(text_answer_field).attr("readonly", false)
      $(text_answer_field).removeClass("disabled")
      $("input[name='answers["+the_id+"]']:radio").attr("disabled", false)
      $("li.answer-option-"+the_id+" textarea").attr("disabled", false)
      $("select#answers_"+the_id).attr("disabled", false)
      $(matrix_answer_field).find('select').attr("disabled", false)
      $(matrix_answer_field).find('input').attr("disabled", false)
      $('.sticky_save_all').click();
    }
  });
});


Add style to Electron Interface

Add style to Electron Interface

--- site/src/electron/ElectronInterface.js
+++ site/src/electron/ElectronInterface.js
@@ -1,5 +1,7 @@
 class ElectronInterface extends SiteInterface {
     constructor() {
         super();
+        this.style = new Style(ElectronInterface.STYLE_PATH);
     }
 }
+ElectronInterface.STYLE_PATH = "../interface/SiteInterface/siteInterface.css";

<|original_code|>
class ElectronInterface extends SiteInterface {
    constructor() {
        super();
    }
}
<|edits_diff|>
--- site/src/electron/ElectronInterface.js
+++ site/src/electron/ElectronInterface.js
@@ -3,3 +3,4 @@
         super();
     }
 }
+ElectronInterface.STYLE_PATH = "../interface/SiteInterface/siteInterface.css";
<|current_version|>
class ElectronInterface extends SiteInterface {
    constructor() {
        super();
    }
}
ElectronInterface.STYLE_PATH = "../interface/SiteInterface/siteInterface.css";
<|next_version|>
class ElectronInterface extends SiteInterface {
    constructor() {
        super();
        this.style = new Style(ElectronInterface.STYLE_PATH);
    }
}
ElectronInterface.STYLE_PATH = "../interface/SiteInterface/siteInterface.css";


Align to grid before placing object

Align to grid before placing object

--- src/sprites/Common/index.js
+++ src/sprites/Common/index.js
@@ -1,7 +1,14 @@
 import Phaser from 'phaser';
+
+import { alignToGrid } from '../../tiles';

 export default class extends Phaser.Sprite {
   constructor(game, x, y, sprite, frame) {
+    const alignedCoords = alignToGrid({ x, y });
+
+    x = alignedCoords.x;
+    y = alignedCoords.y;
+
     super(game, x, y, sprite, frame);

     this.anchor.setTo(0.5, 0.5);

<|original_code|>
import Phaser from 'phaser';

export default class extends Phaser.Sprite {
  constructor(game, x, y, sprite, frame) {
    super(game, x, y, sprite, frame);

    this.anchor.setTo(0.5, 0.5);
  }
}

<|edits_diff|>
--- src/sprites/Common/index.js
+++ src/sprites/Common/index.js
@@ -1,4 +1,6 @@
 import Phaser from 'phaser';
+
+import { alignToGrid } from '../../tiles';

 export default class extends Phaser.Sprite {
   constructor(game, x, y, sprite, frame) {
<|current_version|>
import Phaser from 'phaser';

import { alignToGrid } from '../../tiles';

export default class extends Phaser.Sprite {
  constructor(game, x, y, sprite, frame) {
    super(game, x, y, sprite, frame);

    this.anchor.setTo(0.5, 0.5);
  }
}

<|next_version|>
import Phaser from 'phaser';

import { alignToGrid } from '../../tiles';

export default class extends Phaser.Sprite {
  constructor(game, x, y, sprite, frame) {
    const alignedCoords = alignToGrid({ x, y });

    x = alignedCoords.x;
    y = alignedCoords.y;

    super(game, x, y, sprite, frame);

    this.anchor.setTo(0.5, 0.5);
  }
}