Allow to close a tab after the task has been executed

--- js/ui/task/ChangeFileOwner.js
+++ js/ui/task/ChangeFileOwner.js
@@ -29,6 +29,10 @@
             // Remove wait msg
             msg.hide();

+            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
+                Ext.getCmp('main-panel').remove(this.from.curTab);
+            }
+
             this.from.close();

             // Notify
@@ -41,6 +45,10 @@
             msg.hide();
             PhDOE.winForbidden(o.type);

+            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
+                Ext.getCmp('main-panel').remove(this.from.curTab);
+            }
+
             this.from.close();
         }
     });

<|original_code|>
Ext.namespace('ui', 'ui.task');

// config - {prefix, ftype, fid, fpath, fname, lang, storeRecord}
ui.task.ChangeFileOwner = function(config)
{
    Ext.apply(this, config);

    var msg = Ext.MessageBox.wait(_('Saving data...'));

    XHR({
        scope  : this,
        params : {
            task        : 'setFileOwner',
            fileIdDB    : this.fileIdDB,
            newOwner    : this.newOwner
        },
        success : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);

            // We reload 2 stores to reflect this change
            ui.cmp.WorkTreeGrid.getInstance().getRootNode().reload(function() {
                ui.cmp.PatchesTreeGrid.getInstance().getRootNode().reload();
            });

            // We reload the information Portlet to reflect this change
            ui.cmp.PortletInfo.getInstance().store.reload();

            // Remove wait msg
            msg.hide();

            this.from.close();

            // Notify
            PhDOE.notify('info', _('Owner changed'), _('The owner for this file have been changed successfully !'));
        },
        failure : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);
            // Remove wait msg
            msg.hide();
            PhDOE.winForbidden(o.type);

            this.from.close();
        }
    });
};
<|edits_diff|>
--- js/ui/task/ChangeFileOwner.js
+++ js/ui/task/ChangeFileOwner.js
@@ -29,6 +29,10 @@
             // Remove wait msg
             msg.hide();

+            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
+                Ext.getCmp('main-panel').remove(this.from.curTab);
+            }
+
             this.from.close();

             // Notify
<|current_version|>
Ext.namespace('ui', 'ui.task');

// config - {prefix, ftype, fid, fpath, fname, lang, storeRecord}
ui.task.ChangeFileOwner = function(config)
{
    Ext.apply(this, config);

    var msg = Ext.MessageBox.wait(_('Saving data...'));

    XHR({
        scope  : this,
        params : {
            task        : 'setFileOwner',
            fileIdDB    : this.fileIdDB,
            newOwner    : this.newOwner
        },
        success : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);

            // We reload 2 stores to reflect this change
            ui.cmp.WorkTreeGrid.getInstance().getRootNode().reload(function() {
                ui.cmp.PatchesTreeGrid.getInstance().getRootNode().reload();
            });

            // We reload the information Portlet to reflect this change
            ui.cmp.PortletInfo.getInstance().store.reload();

            // Remove wait msg
            msg.hide();

            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
                Ext.getCmp('main-panel').remove(this.from.curTab);
            }

            this.from.close();

            // Notify
            PhDOE.notify('info', _('Owner changed'), _('The owner for this file have been changed successfully !'));
        },
        failure : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);
            // Remove wait msg
            msg.hide();
            PhDOE.winForbidden(o.type);

            this.from.close();
        }
    });
};
<|next_version|>
Ext.namespace('ui', 'ui.task');

// config - {prefix, ftype, fid, fpath, fname, lang, storeRecord}
ui.task.ChangeFileOwner = function(config)
{
    Ext.apply(this, config);

    var msg = Ext.MessageBox.wait(_('Saving data...'));

    XHR({
        scope  : this,
        params : {
            task        : 'setFileOwner',
            fileIdDB    : this.fileIdDB,
            newOwner    : this.newOwner
        },
        success : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);

            // We reload 2 stores to reflect this change
            ui.cmp.WorkTreeGrid.getInstance().getRootNode().reload(function() {
                ui.cmp.PatchesTreeGrid.getInstance().getRootNode().reload();
            });

            // We reload the information Portlet to reflect this change
            ui.cmp.PortletInfo.getInstance().store.reload();

            // Remove wait msg
            msg.hide();

            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
                Ext.getCmp('main-panel').remove(this.from.curTab);
            }

            this.from.close();

            // Notify
            PhDOE.notify('info', _('Owner changed'), _('The owner for this file have been changed successfully !'));
        },
        failure : function(r)
        {
            var o = Ext.util.JSON.decode(r.responseText);
            // Remove wait msg
            msg.hide();
            PhDOE.winForbidden(o.type);

            if( Ext.isDefined(this.fromType) && this.fromType === 'tab') {
                Ext.getCmp('main-panel').remove(this.from.curTab);
            }

            this.from.close();
        }
    });
};


Add log messages about database seeding progress

--- seeds.js
+++ seeds.js
@@ -2,10 +2,12 @@
 var Feature = require('./feature');

 module.exports = function (callback) {
+  console.log('Seeding the database...')
   // Drop the features collection.
   Feature.remove(function () {
     // Seed the features collection.
     Feature.create(seeds, function () {
+      console.log('Seeding complete.')
       callback();
     });
   });

<|original_code|>
var seeds = require('./features.json');
var Feature = require('./feature');

module.exports = function (callback) {
  // Drop the features collection.
  Feature.remove(function () {
    // Seed the features collection.
    Feature.create(seeds, function () {
      callback();
    });
  });
};

<|edits_diff|>
--- seeds.js
+++ seeds.js
@@ -2,6 +2,7 @@
 var Feature = require('./feature');

 module.exports = function (callback) {
+  console.log('Seeding the database...')
   // Drop the features collection.
   Feature.remove(function () {
     // Seed the features collection.
<|current_version|>
var seeds = require('./features.json');
var Feature = require('./feature');

module.exports = function (callback) {
  console.log('Seeding the database...')
  // Drop the features collection.
  Feature.remove(function () {
    // Seed the features collection.
    Feature.create(seeds, function () {
      callback();
    });
  });
};

<|next_version|>
var seeds = require('./features.json');
var Feature = require('./feature');

module.exports = function (callback) {
  console.log('Seeding the database...')
  // Drop the features collection.
  Feature.remove(function () {
    // Seed the features collection.
    Feature.create(seeds, function () {
      console.log('Seeding complete.')
      callback();
    });
  });
};


Fix issue, node process won't exit automatically when running notify script

--- src/scripts/scanRepliesAndNotify.js
+++ src/scripts/scanRepliesAndNotify.js
@@ -1,6 +1,7 @@
 import lib from './lib';
 import redis from 'src/lib/redisClient';
 import addTime from 'date-fns/add';
+import Client from 'src/database/mongoClient';

 export default async function scanRepliesAndNotify() {
   const timeOffset = JSON.parse(process.env.REVIEW_REPLY_BUFFER) || {};
@@ -16,6 +17,10 @@
   );
   await lib.sendNotification(notificationList);
   await redis.set('lastScannedAt', nowWithOffset);
+
+  // disconnect redis and mongodb
+  await redis.quit();
+  await (await Client.getInstance()).close();
 }

 if (require.main === module) {

<|original_code|>
import lib from './lib';
import redis from 'src/lib/redisClient';
import addTime from 'date-fns/add';

export default async function scanRepliesAndNotify() {
  const timeOffset = JSON.parse(process.env.REVIEW_REPLY_BUFFER) || {};
  const lastScannedAt =
    (await redis.get('lastScannedAt')) ||
    addTime(new Date(), { days: -90 }).toISOString();

  console.log('[notify] lastScannedAt:' + lastScannedAt);
  const nowWithOffset = addTime(new Date(), timeOffset).toISOString();
  const notificationList = await lib.getNotificationList(
    lastScannedAt,
    nowWithOffset
  );
  await lib.sendNotification(notificationList);
  await redis.set('lastScannedAt', nowWithOffset);
}

if (require.main === module) {
  scanRepliesAndNotify();
}

<|edits_diff|>
--- src/scripts/scanRepliesAndNotify.js
+++ src/scripts/scanRepliesAndNotify.js
@@ -1,6 +1,7 @@
 import lib from './lib';
 import redis from 'src/lib/redisClient';
 import addTime from 'date-fns/add';
+import Client from 'src/database/mongoClient';

 export default async function scanRepliesAndNotify() {
   const timeOffset = JSON.parse(process.env.REVIEW_REPLY_BUFFER) || {};
<|current_version|>
import lib from './lib';
import redis from 'src/lib/redisClient';
import addTime from 'date-fns/add';
import Client from 'src/database/mongoClient';

export default async function scanRepliesAndNotify() {
  const timeOffset = JSON.parse(process.env.REVIEW_REPLY_BUFFER) || {};
  const lastScannedAt =
    (await redis.get('lastScannedAt')) ||
    addTime(new Date(), { days: -90 }).toISOString();

  console.log('[notify] lastScannedAt:' + lastScannedAt);
  const nowWithOffset = addTime(new Date(), timeOffset).toISOString();
  const notificationList = await lib.getNotificationList(
    lastScannedAt,
    nowWithOffset
  );
  await lib.sendNotification(notificationList);
  await redis.set('lastScannedAt', nowWithOffset);
}

if (require.main === module) {
  scanRepliesAndNotify();
}

<|next_version|>
import lib from './lib';
import redis from 'src/lib/redisClient';
import addTime from 'date-fns/add';
import Client from 'src/database/mongoClient';

export default async function scanRepliesAndNotify() {
  const timeOffset = JSON.parse(process.env.REVIEW_REPLY_BUFFER) || {};
  const lastScannedAt =
    (await redis.get('lastScannedAt')) ||
    addTime(new Date(), { days: -90 }).toISOString();

  console.log('[notify] lastScannedAt:' + lastScannedAt);
  const nowWithOffset = addTime(new Date(), timeOffset).toISOString();
  const notificationList = await lib.getNotificationList(
    lastScannedAt,
    nowWithOffset
  );
  await lib.sendNotification(notificationList);
  await redis.set('lastScannedAt', nowWithOffset);

  // disconnect redis and mongodb
  await redis.quit();
  await (await Client.getInstance()).close();
}

if (require.main === module) {
  scanRepliesAndNotify();
}


Fix initialization for i18n setting locale

--- app/routes/application.js
+++ app/routes/application.js
@@ -1,8 +1,14 @@
 import Ember from 'ember';

 export default Ember.Route.extend({
+  i18n: Ember.inject.service(),
   model: function() {
       return this.store;
+  },
+  afterModel: function(user) {
+    var i18nLocales = this.get('i18n.locales');
+    var locale = (window.navigator.language || window.navigator.browserLanguage).split('-')[0];
+    this.set('i18n.locale', locale);
   },
   actions: {
     closeModal: function() {

<|original_code|>
import Ember from 'ember';

export default Ember.Route.extend({
  model: function() {
      return this.store;
  },
  actions: {
    closeModal: function() {
      return this.disconnectOutlet({
        outlet: 'modal',
        parentView: 'application'
      });
    },
    openModal: function(modalName) {
      return this.render(modalName, {
        into: 'application',
        outlet: 'modal'
      });
    }
  }
});

<|edits_diff|>
--- app/routes/application.js
+++ app/routes/application.js
@@ -1,6 +1,7 @@
 import Ember from 'ember';

 export default Ember.Route.extend({
+  i18n: Ember.inject.service(),
   model: function() {
       return this.store;
   },
<|current_version|>
import Ember from 'ember';

export default Ember.Route.extend({
  i18n: Ember.inject.service(),
  model: function() {
      return this.store;
  },
  actions: {
    closeModal: function() {
      return this.disconnectOutlet({
        outlet: 'modal',
        parentView: 'application'
      });
    },
    openModal: function(modalName) {
      return this.render(modalName, {
        into: 'application',
        outlet: 'modal'
      });
    }
  }
});

<|next_version|>
import Ember from 'ember';

export default Ember.Route.extend({
  i18n: Ember.inject.service(),
  model: function() {
      return this.store;
  },
  afterModel: function(user) {
    var i18nLocales = this.get('i18n.locales');
    var locale = (window.navigator.language || window.navigator.browserLanguage).split('-')[0];
    this.set('i18n.locale', locale);
  },
  actions: {
    closeModal: function() {
      return this.disconnectOutlet({
        outlet: 'modal',
        parentView: 'application'
      });
    },
    openModal: function(modalName) {
      return this.render(modalName, {
        into: 'application',
        outlet: 'modal'
      });
    }
  }
});


Add route that catches 404's

Add route that catches 404's

--- frontend/src/app/routes.js
+++ frontend/src/app/routes.js
@@ -2,6 +2,7 @@
 import {IndexRedirect, Route} from "react-router";

 import Admin from "app/layouts/Admin";
+import RouteNotFound from "app/components/RouteNotFound";
 import users from "app/users/routes";

@@ -11,6 +12,7 @@
         <Route component={Admin} path="admin">
             <IndexRedirect to="users"/>
             {users}
+            <Route path="*" component={RouteNotFound}/>
         </Route>
     </Route>
 );

<|original_code|>
import React from "react";
import {IndexRedirect, Route} from "react-router";

import Admin from "app/layouts/Admin";
import users from "app/users/routes";

export default (
    <Route path="/">
        <IndexRedirect to="admin/users"/>
        <Route component={Admin} path="admin">
            <IndexRedirect to="users"/>
            {users}
        </Route>
    </Route>
);

<|edits_diff|>
--- frontend/src/app/routes.js
+++ frontend/src/app/routes.js
@@ -2,6 +2,7 @@
 import {IndexRedirect, Route} from "react-router";

 import Admin from "app/layouts/Admin";
+import RouteNotFound from "app/components/RouteNotFound";
 import users from "app/users/routes";

<|current_version|>
import React from "react";
import {IndexRedirect, Route} from "react-router";

import Admin from "app/layouts/Admin";
import RouteNotFound from "app/components/RouteNotFound";
import users from "app/users/routes";

export default (
    <Route path="/">
        <IndexRedirect to="admin/users"/>
        <Route component={Admin} path="admin">
            <IndexRedirect to="users"/>
            {users}
        </Route>
    </Route>
);

<|next_version|>
import React from "react";
import {IndexRedirect, Route} from "react-router";

import Admin from "app/layouts/Admin";
import RouteNotFound from "app/components/RouteNotFound";
import users from "app/users/routes";

export default (
    <Route path="/">
        <IndexRedirect to="admin/users"/>
        <Route component={Admin} path="admin">
            <IndexRedirect to="users"/>
            {users}
            <Route path="*" component={RouteNotFound}/>
        </Route>
    </Route>
);


Check for two RecipeContainers on Profile

--- test/components/Profile.test.js
+++ test/components/Profile.test.js
@@ -5,6 +5,7 @@
 import fakeStore from './fakeStore';

 import Profile from '../../client/components/Profile.js';
+import RecipeContainer from '../../client/components/RecipeContainer.js';

 const fakeProfile = {
   avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
@@ -32,4 +33,8 @@
   it('should display the correct avatar', () => {
     expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
   });
+
+  it('should render two recipe containers', () => {
+    expect(wrapper.find(RecipeContainer)).to.have.length(2);
+  })
 });

<|original_code|>
const expect = require('chai').expect;
const React = require('react');
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import fakeStore from './fakeStore';

import Profile from '../../client/components/Profile.js';

const fakeProfile = {
  avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
  username: 'USERNAME',
};

describe('<Profile />', () => {
  let wrapper;

  beforeEach('render Profile', () => {
    wrapper = mount(
      <Provider store={fakeStore}>
        <Profile />
      </Provider>);
  });

  it('renders without problems', () => {
    expect(wrapper.find(Profile)).to.have.length(1);
  });

  it('should display the correct username', () => {
    expect(wrapper.find('.profile-username').text()).to.equal(fakeStore.getState().profile.username);
  });

  it('should display the correct avatar', () => {
    expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
  });
});

<|edits_diff|>
--- test/components/Profile.test.js
+++ test/components/Profile.test.js
@@ -5,6 +5,7 @@
 import fakeStore from './fakeStore';

 import Profile from '../../client/components/Profile.js';
+import RecipeContainer from '../../client/components/RecipeContainer.js';

 const fakeProfile = {
   avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
<|current_version|>
const expect = require('chai').expect;
const React = require('react');
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import fakeStore from './fakeStore';

import Profile from '../../client/components/Profile.js';
import RecipeContainer from '../../client/components/RecipeContainer.js';

const fakeProfile = {
  avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
  username: 'USERNAME',
};

describe('<Profile />', () => {
  let wrapper;

  beforeEach('render Profile', () => {
    wrapper = mount(
      <Provider store={fakeStore}>
        <Profile />
      </Provider>);
  });

  it('renders without problems', () => {
    expect(wrapper.find(Profile)).to.have.length(1);
  });

  it('should display the correct username', () => {
    expect(wrapper.find('.profile-username').text()).to.equal(fakeStore.getState().profile.username);
  });

  it('should display the correct avatar', () => {
    expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
  });
});

<|next_version|>
const expect = require('chai').expect;
const React = require('react');
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import fakeStore from './fakeStore';

import Profile from '../../client/components/Profile.js';
import RecipeContainer from '../../client/components/RecipeContainer.js';

const fakeProfile = {
  avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
  username: 'USERNAME',
};

describe('<Profile />', () => {
  let wrapper;

  beforeEach('render Profile', () => {
    wrapper = mount(
      <Provider store={fakeStore}>
        <Profile />
      </Provider>);
  });

  it('renders without problems', () => {
    expect(wrapper.find(Profile)).to.have.length(1);
  });

  it('should display the correct username', () => {
    expect(wrapper.find('.profile-username').text()).to.equal(fakeStore.getState().profile.username);
  });

  it('should display the correct avatar', () => {
    expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
  });

  it('should render two recipe containers', () => {
    expect(wrapper.find(RecipeContainer)).to.have.length(2);
  })
});


Use barbe to render dynamic fields.

Use barbe to render dynamic fields.

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

 const typpy = require("typpy")
     , iterateObject = require("iterate-object")
+    , barbe = require("barbe")
     ;

 /**
@@ -39,6 +40,10 @@
             data = { code: code };
         }

+        if (typeof error === "string") {
+            error = barbe(error, ["<", ">"], data);
+        }
+
         // Create the error
         super(error);

<|original_code|>
"use strict";

const typpy = require("typpy")
    , iterateObject = require("iterate-object")
    ;

/**
 * Err
 * Create a custom error object.
 *
 * @name Err
 * @function
 * @param {String|Error|Object} error The error message or an existing `Error`
 * instance or the `data` object where the `message` is the error message.
 * @param {String|Object} code The error code or the data object.
 * @param {Object} data The data object (its fields will be appended to the
 * `Error` object).
 * @return {Error} The custom `Error` instance.
 */
module.exports = class Err extends Error {
    constructor (error, code, data) {

        // Err({ message: "...", code: "...", ... });
        if (typpy(error, Object)) {
            data = error;
            error = data.message;
            delete data.message;
            code = data.code;
        }

        // Err(message, code, data);
        // Err(message, data);
        if (typpy(data, Object)) {
            data.code = code;
        } else if (typpy(code, Object)) {
            data = code;
            code = undefined;
        } else if (!typpy(code, undefined)) {
            data = { code: code };
        }

        // Create the error
        super(error);

        if (data) {
            iterateObject(data, (v, n) => {
                this[n] = v;
            });
        }
    }
};

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

 const typpy = require("typpy")
     , iterateObject = require("iterate-object")
+    , barbe = require("barbe")
     ;

 /**
<|current_version|>
"use strict";

const typpy = require("typpy")
    , iterateObject = require("iterate-object")
    , barbe = require("barbe")
    ;

/**
 * Err
 * Create a custom error object.
 *
 * @name Err
 * @function
 * @param {String|Error|Object} error The error message or an existing `Error`
 * instance or the `data` object where the `message` is the error message.
 * @param {String|Object} code The error code or the data object.
 * @param {Object} data The data object (its fields will be appended to the
 * `Error` object).
 * @return {Error} The custom `Error` instance.
 */
module.exports = class Err extends Error {
    constructor (error, code, data) {

        // Err({ message: "...", code: "...", ... });
        if (typpy(error, Object)) {
            data = error;
            error = data.message;
            delete data.message;
            code = data.code;
        }

        // Err(message, code, data);
        // Err(message, data);
        if (typpy(data, Object)) {
            data.code = code;
        } else if (typpy(code, Object)) {
            data = code;
            code = undefined;
        } else if (!typpy(code, undefined)) {
            data = { code: code };
        }

        // Create the error
        super(error);

        if (data) {
            iterateObject(data, (v, n) => {
                this[n] = v;
            });
        }
    }
};

<|next_version|>
"use strict";

const typpy = require("typpy")
    , iterateObject = require("iterate-object")
    , barbe = require("barbe")
    ;

/**
 * Err
 * Create a custom error object.
 *
 * @name Err
 * @function
 * @param {String|Error|Object} error The error message or an existing `Error`
 * instance or the `data` object where the `message` is the error message.
 * @param {String|Object} code The error code or the data object.
 * @param {Object} data The data object (its fields will be appended to the
 * `Error` object).
 * @return {Error} The custom `Error` instance.
 */
module.exports = class Err extends Error {
    constructor (error, code, data) {

        // Err({ message: "...", code: "...", ... });
        if (typpy(error, Object)) {
            data = error;
            error = data.message;
            delete data.message;
            code = data.code;
        }

        // Err(message, code, data);
        // Err(message, data);
        if (typpy(data, Object)) {
            data.code = code;
        } else if (typpy(code, Object)) {
            data = code;
            code = undefined;
        } else if (!typpy(code, undefined)) {
            data = { code: code };
        }

        if (typeof error === "string") {
            error = barbe(error, ["<", ">"], data);
        }

        // Create the error
        super(error);

        if (data) {
            iterateObject(data, (v, n) => {
                this[n] = v;
            });
        }
    }
};


Disable Parallax3D on navigation page

Disable Parallax3D on navigation page

--- app/main/about/nav-shrink.js
+++ app/main/about/nav-shrink.js
@@ -28,6 +28,8 @@
       const [key, value] = pair;
       this.elem[key].style.fontSize = `calc(${value} * ${this.scaleX})`;
     });
+    // Turn off parallax effect
+    window.parallax.disable();
   }

@@ -37,5 +39,7 @@
     Array.from(Object.keys(this.fontSize)).forEach((n) => {
       this.elem[n].style.fontSize = '';
     });
+    // Re-enable parallax effect
+    window.parallax.enable();
   }
 }

<|original_code|>
import NavigationBase from '../navigation/anim-base';

export default class AboutNavigationAnimation extends NavigationBase {
  constructor() {
    super();
    this.hash = 'about';
    // Add objects to this.elem
    Object.assign(this.elem, {
      wrapper: document.getElementById('about-wrapper'),
      container: document.querySelector('#about-wrapper .container'),
      monogram: document.querySelector('#about-wrapper .monogram'),
      content: document.querySelector('#about-wrapper .content'),
    });

    this.fontSize = {
      content: 'calc(13px + .75vw)',
      monogram: '4vw',
    };
  }

  putInLaptop() {
    super.putInLaptop();
    // Calculate appropriate font size scale
    this.scaleX = this.elem.container.getBoundingClientRect().width / window.innerWidth;
    // Scale font sizes using CSS `calc`
    Object.entries(this.fontSize).forEach((pair) => {
      const [key, value] = pair;
      this.elem[key].style.fontSize = `calc(${value} * ${this.scaleX})`;
    });
  }

  removeFromLaptop() {
    super.removeFromLaptop();
    // Remove adjusted font sizes
    Array.from(Object.keys(this.fontSize)).forEach((n) => {
      this.elem[n].style.fontSize = '';
    });
  }
}

<|edits_diff|>
--- app/main/about/nav-shrink.js
+++ app/main/about/nav-shrink.js
@@ -28,6 +28,8 @@
       const [key, value] = pair;
       this.elem[key].style.fontSize = `calc(${value} * ${this.scaleX})`;
     });
+    // Turn off parallax effect
+    window.parallax.disable();
   }

<|current_version|>
import NavigationBase from '../navigation/anim-base';

export default class AboutNavigationAnimation extends NavigationBase {
  constructor() {
    super();
    this.hash = 'about';
    // Add objects to this.elem
    Object.assign(this.elem, {
      wrapper: document.getElementById('about-wrapper'),
      container: document.querySelector('#about-wrapper .container'),
      monogram: document.querySelector('#about-wrapper .monogram'),
      content: document.querySelector('#about-wrapper .content'),
    });

    this.fontSize = {
      content: 'calc(13px + .75vw)',
      monogram: '4vw',
    };
  }

  putInLaptop() {
    super.putInLaptop();
    // Calculate appropriate font size scale
    this.scaleX = this.elem.container.getBoundingClientRect().width / window.innerWidth;
    // Scale font sizes using CSS `calc`
    Object.entries(this.fontSize).forEach((pair) => {
      const [key, value] = pair;
      this.elem[key].style.fontSize = `calc(${value} * ${this.scaleX})`;
    });
    // Turn off parallax effect
    window.parallax.disable();
  }

  removeFromLaptop() {
    super.removeFromLaptop();
    // Remove adjusted font sizes
    Array.from(Object.keys(this.fontSize)).forEach((n) => {
      this.elem[n].style.fontSize = '';
    });
  }
}

<|next_version|>
import NavigationBase from '../navigation/anim-base';

export default class AboutNavigationAnimation extends NavigationBase {
  constructor() {
    super();
    this.hash = 'about';
    // Add objects to this.elem
    Object.assign(this.elem, {
      wrapper: document.getElementById('about-wrapper'),
      container: document.querySelector('#about-wrapper .container'),
      monogram: document.querySelector('#about-wrapper .monogram'),
      content: document.querySelector('#about-wrapper .content'),
    });

    this.fontSize = {
      content: 'calc(13px + .75vw)',
      monogram: '4vw',
    };
  }

  putInLaptop() {
    super.putInLaptop();
    // Calculate appropriate font size scale
    this.scaleX = this.elem.container.getBoundingClientRect().width / window.innerWidth;
    // Scale font sizes using CSS `calc`
    Object.entries(this.fontSize).forEach((pair) => {
      const [key, value] = pair;
      this.elem[key].style.fontSize = `calc(${value} * ${this.scaleX})`;
    });
    // Turn off parallax effect
    window.parallax.disable();
  }

  removeFromLaptop() {
    super.removeFromLaptop();
    // Remove adjusted font sizes
    Array.from(Object.keys(this.fontSize)).forEach((n) => {
      this.elem[n].style.fontSize = '';
    });
    // Re-enable parallax effect
    window.parallax.enable();
  }
}


Remove yes/no answer check after submitted once

--- app/assets/javascripts/answers.js
+++ app/assets/javascripts/answers.js
@@ -28,10 +28,12 @@

   $('#respond-yes').click(function(e) {
     provide_feedback("yes", "Great! Congrats! Try another question.");
+    $('#response').addClass('hidden');
   });

   $('#respond-no').click(function(e) {
     provide_feedback("no", "No worries. You'll get it next time. Onwards!");
+    $('#response').addClass('hidden');
   });

 });

<|original_code|>
//hide and show answers
$(document).ready(function(e){

    function provide_feedback(is_correct, notice_text) {
      $.ajax({
        url: window.location.pathname + "/feedback",
        type: "POST",
        data: { correct: is_correct }
      })
        .done(function( data ) {
          if ( console && console.log ) {
            console.log( "Sample of data:", data.slice( 0, 100 ) );
          }
          $('#alert_text').text(notice_text);
          $('.alert').slideDown();
      });
    };

  //if you wish to keep both the divs hidden by default then dont forget to hide //them
  $("#answers").hide();
  $("#response").hide();

  $("#submit_answer").click(function(){
       $("#answers").fadeIn();
       $("#submit_answer").hide("slow");
       $("#response").fadeIn();
  });

  $('#respond-yes').click(function(e) {
    provide_feedback("yes", "Great! Congrats! Try another question.");
  });

  $('#respond-no').click(function(e) {
    provide_feedback("no", "No worries. You'll get it next time. Onwards!");
  });

});

<|edits_diff|>
--- app/assets/javascripts/answers.js
+++ app/assets/javascripts/answers.js
@@ -28,6 +28,7 @@

   $('#respond-yes').click(function(e) {
     provide_feedback("yes", "Great! Congrats! Try another question.");
+    $('#response').addClass('hidden');
   });

   $('#respond-no').click(function(e) {
<|current_version|>
//hide and show answers
$(document).ready(function(e){

    function provide_feedback(is_correct, notice_text) {
      $.ajax({
        url: window.location.pathname + "/feedback",
        type: "POST",
        data: { correct: is_correct }
      })
        .done(function( data ) {
          if ( console && console.log ) {
            console.log( "Sample of data:", data.slice( 0, 100 ) );
          }
          $('#alert_text').text(notice_text);
          $('.alert').slideDown();
      });
    };

  //if you wish to keep both the divs hidden by default then dont forget to hide //them
  $("#answers").hide();
  $("#response").hide();

  $("#submit_answer").click(function(){
       $("#answers").fadeIn();
       $("#submit_answer").hide("slow");
       $("#response").fadeIn();
  });

  $('#respond-yes').click(function(e) {
    provide_feedback("yes", "Great! Congrats! Try another question.");
    $('#response').addClass('hidden');
  });

  $('#respond-no').click(function(e) {
    provide_feedback("no", "No worries. You'll get it next time. Onwards!");
  });

});

<|next_version|>
//hide and show answers
$(document).ready(function(e){

    function provide_feedback(is_correct, notice_text) {
      $.ajax({
        url: window.location.pathname + "/feedback",
        type: "POST",
        data: { correct: is_correct }
      })
        .done(function( data ) {
          if ( console && console.log ) {
            console.log( "Sample of data:", data.slice( 0, 100 ) );
          }
          $('#alert_text').text(notice_text);
          $('.alert').slideDown();
      });
    };

  //if you wish to keep both the divs hidden by default then dont forget to hide //them
  $("#answers").hide();
  $("#response").hide();

  $("#submit_answer").click(function(){
       $("#answers").fadeIn();
       $("#submit_answer").hide("slow");
       $("#response").fadeIn();
  });

  $('#respond-yes').click(function(e) {
    provide_feedback("yes", "Great! Congrats! Try another question.");
    $('#response').addClass('hidden');
  });

  $('#respond-no').click(function(e) {
    provide_feedback("no", "No worries. You'll get it next time. Onwards!");
    $('#response').addClass('hidden');
  });

});


Add space removing for form

Add space removing for form

--- js/script.js
+++ js/script.js
@@ -1,6 +1,8 @@
 function login() {
   var firstName = document.getElementById("firstName").value;
+  firstName = firstName.replace(/\s+/g, '');
   var lastName = document.getElementById("lastName").value
+  lastName = lastName.replace(/\s+/g, '');

   var xhr = new XMLHttpRequest();
   xhr.open("POST", '/server', true);

<|original_code|>
function login() {
  var firstName = document.getElementById("firstName").value;
  var lastName = document.getElementById("lastName").value

  var xhr = new XMLHttpRequest();
  xhr.open("POST", '/server', true);

  xhr.onreadystatechange = function() {
      if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
          // Request finished. Do processing here.
      }
  }

  saveName(firstName, lastName);
  document.location.href = 'index.html';
}

function saveName(firstName, lastName) {
 var name = {
   First: firstName,
   Last: lastName
 };

 name = JSON.stringify(name);
 name = btoa(name);
 localStorage.setItem('_name', name);
}

<|edits_diff|>
--- js/script.js
+++ js/script.js
@@ -1,5 +1,6 @@
 function login() {
   var firstName = document.getElementById("firstName").value;
+  firstName = firstName.replace(/\s+/g, '');
   var lastName = document.getElementById("lastName").value

   var xhr = new XMLHttpRequest();
<|current_version|>
function login() {
  var firstName = document.getElementById("firstName").value;
  firstName = firstName.replace(/\s+/g, '');
  var lastName = document.getElementById("lastName").value

  var xhr = new XMLHttpRequest();
  xhr.open("POST", '/server', true);

  xhr.onreadystatechange = function() {
      if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
          // Request finished. Do processing here.
      }
  }

  saveName(firstName, lastName);
  document.location.href = 'index.html';
}

function saveName(firstName, lastName) {
 var name = {
   First: firstName,
   Last: lastName
 };

 name = JSON.stringify(name);
 name = btoa(name);
 localStorage.setItem('_name', name);
}

<|next_version|>
function login() {
  var firstName = document.getElementById("firstName").value;
  firstName = firstName.replace(/\s+/g, '');
  var lastName = document.getElementById("lastName").value
  lastName = lastName.replace(/\s+/g, '');

  var xhr = new XMLHttpRequest();
  xhr.open("POST", '/server', true);

  xhr.onreadystatechange = function() {
      if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
          // Request finished. Do processing here.
      }
  }

  saveName(firstName, lastName);
  document.location.href = 'index.html';
}

function saveName(firstName, lastName) {
 var name = {
   First: firstName,
   Last: lastName
 };

 name = JSON.stringify(name);
 name = btoa(name);
 localStorage.setItem('_name', name);
}


Make the Amazon:S3:CopyObject example nicer

--- examples/amazon/s3/copy-object.js
+++ examples/amazon/s3/copy-object.js
@@ -14,11 +14,16 @@
     'region' : amazon.US_EAST_1
 });

+fmt.line();
+fmt.title('s3.CopyObject');
+
 fmt.field('Region', s3.region() );
 fmt.field('EndPoint', s3.host() );
 fmt.field('AccessKeyId', s3.accessKeyId() );
 fmt.field('SecretAccessKey', s3.secretAccessKey().substr(0, 3) + '...' );
 fmt.field('AwsAccountId', s3.awsAccountId() );
+
+fmt.line();

 var options = {
     BucketName : 'pie-18',
@@ -31,4 +36,5 @@
     fmt.msg("copying one object to another - expecting success");
     fmt.dump(err, 'Error');
     fmt.dump(data, 'Data');
+    fmt.line();
 });

<|original_code|>
var fmt = require('fmt');
var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var S3 = awssum.load('amazon/s3').S3;

var env             = process.env;
var accessKeyId     = env.ACCESS_KEY_ID;
var secretAccessKey = env.SECRET_ACCESS_KEY;
var awsAccountId    = env.AWS_ACCOUNT_ID;

var s3 = new S3({
    'accessKeyId' : accessKeyId,
    'secretAccessKey' : secretAccessKey,
    'region' : amazon.US_EAST_1
});

fmt.field('Region', s3.region() );
fmt.field('EndPoint', s3.host() );
fmt.field('AccessKeyId', s3.accessKeyId() );
fmt.field('SecretAccessKey', s3.secretAccessKey().substr(0, 3) + '...' );
fmt.field('AwsAccountId', s3.awsAccountId() );

var options = {
    BucketName : 'pie-18',
    ObjectName : 'copy-of-test-object.txt',
    SourceBucket : 'pie-18',
    SourceObject : 'test-object.txt',
};

s3.CopyObject(options, function(err, data) {
    fmt.msg("copying one object to another - expecting success");
    fmt.dump(err, 'Error');
    fmt.dump(data, 'Data');
});

<|edits_diff|>
--- examples/amazon/s3/copy-object.js
+++ examples/amazon/s3/copy-object.js
@@ -14,11 +14,16 @@
     'region' : amazon.US_EAST_1
 });

+fmt.line();
+fmt.title('s3.CopyObject');
+
 fmt.field('Region', s3.region() );
 fmt.field('EndPoint', s3.host() );
 fmt.field('AccessKeyId', s3.accessKeyId() );
 fmt.field('SecretAccessKey', s3.secretAccessKey().substr(0, 3) + '...' );
 fmt.field('AwsAccountId', s3.awsAccountId() );
+
+fmt.line();

 var options = {
     BucketName : 'pie-18',
<|current_version|>
var fmt = require('fmt');
var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var S3 = awssum.load('amazon/s3').S3;

var env             = process.env;
var accessKeyId     = env.ACCESS_KEY_ID;
var secretAccessKey = env.SECRET_ACCESS_KEY;
var awsAccountId    = env.AWS_ACCOUNT_ID;

var s3 = new S3({
    'accessKeyId' : accessKeyId,
    'secretAccessKey' : secretAccessKey,
    'region' : amazon.US_EAST_1
});

fmt.line();
fmt.title('s3.CopyObject');

fmt.field('Region', s3.region() );
fmt.field('EndPoint', s3.host() );
fmt.field('AccessKeyId', s3.accessKeyId() );
fmt.field('SecretAccessKey', s3.secretAccessKey().substr(0, 3) + '...' );
fmt.field('AwsAccountId', s3.awsAccountId() );

fmt.line();

var options = {
    BucketName : 'pie-18',
    ObjectName : 'copy-of-test-object.txt',
    SourceBucket : 'pie-18',
    SourceObject : 'test-object.txt',
};

s3.CopyObject(options, function(err, data) {
    fmt.msg("copying one object to another - expecting success");
    fmt.dump(err, 'Error');
    fmt.dump(data, 'Data');
});

<|next_version|>
var fmt = require('fmt');
var awssum = require('awssum');
var amazon = awssum.load('amazon/amazon');
var S3 = awssum.load('amazon/s3').S3;

var env             = process.env;
var accessKeyId     = env.ACCESS_KEY_ID;
var secretAccessKey = env.SECRET_ACCESS_KEY;
var awsAccountId    = env.AWS_ACCOUNT_ID;

var s3 = new S3({
    'accessKeyId' : accessKeyId,
    'secretAccessKey' : secretAccessKey,
    'region' : amazon.US_EAST_1
});

fmt.line();
fmt.title('s3.CopyObject');

fmt.field('Region', s3.region() );
fmt.field('EndPoint', s3.host() );
fmt.field('AccessKeyId', s3.accessKeyId() );
fmt.field('SecretAccessKey', s3.secretAccessKey().substr(0, 3) + '...' );
fmt.field('AwsAccountId', s3.awsAccountId() );

fmt.line();

var options = {
    BucketName : 'pie-18',
    ObjectName : 'copy-of-test-object.txt',
    SourceBucket : 'pie-18',
    SourceObject : 'test-object.txt',
};

s3.CopyObject(options, function(err, data) {
    fmt.msg("copying one object to another - expecting success");
    fmt.dump(err, 'Error');
    fmt.dump(data, 'Data');
    fmt.line();
});


Add Account.secret field to mongodb

Add Account.secret field to mongodb

--- nodejs/lib/models/account.js
+++ nodejs/lib/models/account.js
@@ -6,11 +6,21 @@
 	'display_name'    : String
 	,'name'           : String
 	,'owner_ids'      : [ObjectId]
+	,'secret'         : {type: String, 'default': generateSecret}
 });

 // number defines index sort order (1=asc)
 Account.index({name: 1});

+Account.static({
+	generateSecret: generateSecret
+});
+
 // Model name, Schema, collection name
 mongoose.model('Account', Account, 'accounts');
 module.exports = mongoose.model('Account');
+
+
+function generateSecret(){
+	return wompt.util.randomString(20);
+}

<|original_code|>
var wompt = require("../includes"),
mongoose = wompt.mongoose,
ObjectId = mongoose.Schema.ObjectId;

var Account = new mongoose.Schema({
	'display_name'    : String
	,'name'           : String
	,'owner_ids'      : [ObjectId]
});

// number defines index sort order (1=asc)
Account.index({name: 1});

// Model name, Schema, collection name
mongoose.model('Account', Account, 'accounts');
module.exports = mongoose.model('Account');

<|edits_diff|>
--- nodejs/lib/models/account.js
+++ nodejs/lib/models/account.js
@@ -6,11 +6,16 @@
 	'display_name'    : String
 	,'name'           : String
 	,'owner_ids'      : [ObjectId]
+	,'secret'         : {type: String, 'default': generateSecret}
 });

 // number defines index sort order (1=asc)
 Account.index({name: 1});

+Account.static({
+	generateSecret: generateSecret
+});
+
 // Model name, Schema, collection name
 mongoose.model('Account', Account, 'accounts');
 module.exports = mongoose.model('Account');
<|current_version|>
var wompt = require("../includes"),
mongoose = wompt.mongoose,
ObjectId = mongoose.Schema.ObjectId;

var Account = new mongoose.Schema({
	'display_name'    : String
	,'name'           : String
	,'owner_ids'      : [ObjectId]
	,'secret'         : {type: String, 'default': generateSecret}
});

// number defines index sort order (1=asc)
Account.index({name: 1});

Account.static({
	generateSecret: generateSecret
});

// Model name, Schema, collection name
mongoose.model('Account', Account, 'accounts');
module.exports = mongoose.model('Account');

<|next_version|>
var wompt = require("../includes"),
mongoose = wompt.mongoose,
ObjectId = mongoose.Schema.ObjectId;

var Account = new mongoose.Schema({
	'display_name'    : String
	,'name'           : String
	,'owner_ids'      : [ObjectId]
	,'secret'         : {type: String, 'default': generateSecret}
});

// number defines index sort order (1=asc)
Account.index({name: 1});

Account.static({
	generateSecret: generateSecret
});

// Model name, Schema, collection name
mongoose.model('Account', Account, 'accounts');
module.exports = mongoose.model('Account');

function generateSecret(){
	return wompt.util.randomString(20);
}


import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>
                <div>
                    <Header />
                    <News />
                </div>
            </MuiThemeProvider>
        )
    }

};

export default App;

import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import Sponsor from '../Sponsor';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>
                <div>
                    <Header />
                    <News />
                    <Sponsor />
                </div>
            </MuiThemeProvider>
        )
    }

};

export default App;

Add Sponsor component to home page

Add Sponsor component to home page

--- src/components/App/index.js
+++ src/components/App/index.js
@@ -5,6 +5,7 @@
 import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
 import Header from '../Header';
 import News from '../News';
+import Sponsor from '../Sponsor';
 import styles from './index.css';

 class App extends React.Component {
@@ -15,6 +16,7 @@
                 <div>
                     <Header />
                     <News />
+                    <Sponsor />
                 </div>
             </MuiThemeProvider>
         )

import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import Sponsor from '../Sponsor';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>
                <div>
                    <Header />
                    <News />
                </div>
            </MuiThemeProvider>
        )
    }

};

export default App;

<|original_code|>
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>

                    <News />

            </MuiThemeProvider>
        )
    }

};

export default App;

<|edits_diff|>
--- src/components/App/index.js
+++ src/components/App/index.js
@@ -5,6 +5,7 @@
 import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
 import Header from '../Header';
 import News from '../News';
+import Sponsor from '../Sponsor';
 import styles from './index.css';

 class App extends React.Component {
<|current_version|>
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import Sponsor from '../Sponsor';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>

                    <News />

            </MuiThemeProvider>
        )
    }

};

export default App;

<|next_version|>
import React from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import Theme from '../../../config/theme';
import FloatingActionButton from 'material-ui/FloatingActionButton';
import UpIcon from 'material-ui/svg-icons/navigation/arrow-upward';
import Header from '../Header';
import News from '../News';
import Sponsor from '../Sponsor';
import styles from './index.css';

class App extends React.Component {

    render () {
        return (
            <MuiThemeProvider muiTheme={Theme}>

                    <News />
                    <Sponsor />

            </MuiThemeProvider>
        )
    }

};

export default App;


$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
      $("button.upvote").closest(".response").append("<p>" + response + "</p>")
    }).fail( function (response) {
        console.log("Failed. Here is the response:")
        console.log(response);
    })
  })
})

Add ajax to upvote a response.

Add ajax to upvote a response.

--- app/assets/javascripts/responses.js
+++ app/assets/javascripts/responses.js
@@ -8,7 +8,9 @@
       data: { id: commentId },
       dataType: 'JSON'
     }).done( function (response) {
+      $("button.upvote").closest(".response").append("<p>" + response + "</p>")
     }).fail( function (response) {
+        console.log("Failed. Here is the response:")
         console.log(response);
     })
   })

$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
      $("button.upvote").closest(".response").append("<p>" + response + "</p>")
    }).fail( function (response) {
        console.log(response);
    })
  })
})

<|original_code|>
$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
    }).fail( function (response) {
        console.log(response);
    })
  })
})

<|edits_diff|>
--- app/assets/javascripts/responses.js
+++ app/assets/javascripts/responses.js
@@ -8,6 +8,7 @@
       data: { id: commentId },
       dataType: 'JSON'
     }).done( function (response) {
+      $("button.upvote").closest(".response").append("
" + response + "
")
     }).fail( function (response) {
         console.log(response);
     })
<|current_version|>
$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
      $("button.upvote").closest(".response").append("
" + response + "
")
    }).fail( function (response) {
        console.log(response);
    })
  })
})

<|next_version|>
$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
      $("button.upvote").closest(".response").append("
" + response + "
")
    }).fail( function (response) {
        console.log("Failed. Here is the response:")
        console.log(response);
    })
  })
})


Add Mesh collision filter property.

Add Mesh collision filter property.

--- src/js/objects/mesh.js
+++ src/js/objects/mesh.js
@@ -2,12 +2,15 @@

 var _ = require( '../utils' );
 var Object3D = require( '../object3d' );
+var Filter = require( '../math/filter' );

 function Mesh( geometry, material ) {
   Object3D.call( this );

   this.geometry = geometry;
   this.material = material;
+
+  this.filter = new Filter();
 }

 _.extends( Mesh, Object3D );

<|original_code|>
'use strict';

var _ = require( '../utils' );
var Object3D = require( '../object3d' );

function Mesh( geometry, material ) {
  Object3D.call( this );

  this.geometry = geometry;
  this.material = material;
}

_.extends( Mesh, Object3D );

module.exports = Mesh;

<|edits_diff|>
--- src/js/objects/mesh.js
+++ src/js/objects/mesh.js
@@ -2,6 +2,7 @@

 var _ = require( '../utils' );
 var Object3D = require( '../object3d' );
+var Filter = require( '../math/filter' );

 function Mesh( geometry, material ) {
   Object3D.call( this );
<|current_version|>
'use strict';

var _ = require( '../utils' );
var Object3D = require( '../object3d' );
var Filter = require( '../math/filter' );

function Mesh( geometry, material ) {
  Object3D.call( this );

  this.geometry = geometry;
  this.material = material;
}

_.extends( Mesh, Object3D );

module.exports = Mesh;

<|next_version|>
'use strict';

var _ = require( '../utils' );
var Object3D = require( '../object3d' );
var Filter = require( '../math/filter' );

function Mesh( geometry, material ) {
  Object3D.call( this );

  this.geometry = geometry;
  this.material = material;

  this.filter = new Filter();
}

_.extends( Mesh, Object3D );

module.exports = Mesh;


Add comments to slideshow controller.

Add comments to slideshow controller.

--- client/app/scripts/controllers/carousel.js
+++ client/app/scripts/controllers/carousel.js
@@ -7,11 +7,20 @@
       $scope.homepageInterval = 5000;
       var slides = $scope.slides = [];

+      /**
+      * Gets all published "features" from api
+      *
+      */
       Feature.getPublished().then(function(response) {
         $scope.features = response;
         startSlider();
       });

+      /**
+      * helper method which starts slider
+      * by adding each slide to the slides array
+      *
+      */
       function startSlider() {
         $scope.features.forEach(function(feature) {
           $scope.addSlide(feature);

<|original_code|>
angular
  .module('app')
  .controller('CarouselDemoCtrl', [
    '$scope',
    'featureService',
    function($scope, Feature) {
      $scope.homepageInterval = 5000;
      var slides = $scope.slides = [];

      Feature.getPublished().then(function(response) {
        $scope.features = response;
        startSlider();
      });

      function startSlider() {
        $scope.features.forEach(function(feature) {
          $scope.addSlide(feature);
        });
      }

      $scope.addSlide = function(feature) {
        var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
        slides.push({
          image: feature.image,
          message: feature.message,
          action: feature.action,
          actionUrl: feature.actionUrl
        });
      };
    }]);

<|edits_diff|>
--- client/app/scripts/controllers/carousel.js
+++ client/app/scripts/controllers/carousel.js
@@ -7,6 +7,10 @@
       $scope.homepageInterval = 5000;
       var slides = $scope.slides = [];

+      /**
+      * Gets all published "features" from api
+      *
+      */
       Feature.getPublished().then(function(response) {
         $scope.features = response;
         startSlider();
<|current_version|>
angular
  .module('app')
  .controller('CarouselDemoCtrl', [
    '$scope',
    'featureService',
    function($scope, Feature) {
      $scope.homepageInterval = 5000;
      var slides = $scope.slides = [];

      /**
      * Gets all published "features" from api
      *
      */
      Feature.getPublished().then(function(response) {
        $scope.features = response;
        startSlider();
      });

      function startSlider() {
        $scope.features.forEach(function(feature) {
          $scope.addSlide(feature);
        });
      }

      $scope.addSlide = function(feature) {
        var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
        slides.push({
          image: feature.image,
          message: feature.message,
          action: feature.action,
          actionUrl: feature.actionUrl
        });
      };
    }]);

<|next_version|>
angular
  .module('app')
  .controller('CarouselDemoCtrl', [
    '$scope',
    'featureService',
    function($scope, Feature) {
      $scope.homepageInterval = 5000;
      var slides = $scope.slides = [];

      /**
      * Gets all published "features" from api
      *
      */
      Feature.getPublished().then(function(response) {
        $scope.features = response;
        startSlider();
      });

      /**
      * helper method which starts slider
      * by adding each slide to the slides array
      *
      */
      function startSlider() {
        $scope.features.forEach(function(feature) {
          $scope.addSlide(feature);
        });
      }

      $scope.addSlide = function(feature) {
        var newWidth = 200 + ((slides.length + (25 * slides.length)) % 150);
        slides.push({
          image: feature.image,
          message: feature.message,
          action: feature.action,
          actionUrl: feature.actionUrl
        });
      };
    }]);


Load .env file at webpack build.

Load .env file at webpack build.

--- webpack.config.js
+++ webpack.config.js
@@ -1,4 +1,5 @@
 const nodeExternals = require('webpack-node-externals');
+const Dotenv = require('dotenv-webpack');

 module.exports = {
   entry: [
@@ -21,4 +22,7 @@
     ],
   },
   externals: [nodeExternals()],
+  plugins: [
+    new Dotenv()
+  ],
 };

<|original_code|>
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: [
    'babel-polyfill',
    './index.js',
  ],
  target: 'node',
  output: {
    libraryTarget: 'commonjs',
    path: '.webpack',
    filename: 'index.js',
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
      },
    ],
  },
  externals: [nodeExternals()],
};

<|edits_diff|>
--- webpack.config.js
+++ webpack.config.js
@@ -1,4 +1,5 @@
 const nodeExternals = require('webpack-node-externals');
+const Dotenv = require('dotenv-webpack');

 module.exports = {
   entry: [
<|current_version|>
const nodeExternals = require('webpack-node-externals');
const Dotenv = require('dotenv-webpack');

module.exports = {
  entry: [
    'babel-polyfill',
    './index.js',
  ],
  target: 'node',
  output: {
    libraryTarget: 'commonjs',
    path: '.webpack',
    filename: 'index.js',
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
      },
    ],
  },
  externals: [nodeExternals()],
};

<|next_version|>
const nodeExternals = require('webpack-node-externals');
const Dotenv = require('dotenv-webpack');

module.exports = {
  entry: [
    'babel-polyfill',
    './index.js',
  ],
  target: 'node',
  output: {
    libraryTarget: 'commonjs',
    path: '.webpack',
    filename: 'index.js',
  },
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
      },
    ],
  },
  externals: [nodeExternals()],
  plugins: [
    new Dotenv()
  ],
};


Add API endpoint to get current user info

--- server/config/routes.js
+++ server/config/routes.js
@@ -1,5 +1,6 @@
 'use strict';

+const passport = require('passport');
 const main = require('../app/controllers/main');
 const api = require('../app/controllers/api');
 const auth = require('../app/controllers/auth');
@@ -11,6 +12,9 @@
 module.exports = function applyRoutes(app) {
   app.get('/', main.index);
   app.post('/auth/token', auth.token);
+  app.get('/me', passport.authenticate('jwt'), function(req, res) {
+    res.send(req.user);
+  });
   app.get('/:type(orders|accounts|portions|vendors)', api);
   app.get('/:type(orders|accounts|portions|vendors)/:id', api);
   app.post('/:type(orders|accounts|portions|vendors)', api);

<|original_code|>
'use strict';

const main = require('../app/controllers/main');
const api = require('../app/controllers/api');
const auth = require('../app/controllers/auth');

/**
 * Expose routes
 */

module.exports = function applyRoutes(app) {
  app.get('/', main.index);
  app.post('/auth/token', auth.token);
  app.get('/:type(orders|accounts|portions|vendors)', api);
  app.get('/:type(orders|accounts|portions|vendors)/:id', api);
  app.post('/:type(orders|accounts|portions|vendors)', api);
};

<|edits_diff|>
--- server/config/routes.js
+++ server/config/routes.js
@@ -1,5 +1,6 @@
 'use strict';

+const passport = require('passport');
 const main = require('../app/controllers/main');
 const api = require('../app/controllers/api');
 const auth = require('../app/controllers/auth');
<|current_version|>
'use strict';

const passport = require('passport');
const main = require('../app/controllers/main');
const api = require('../app/controllers/api');
const auth = require('../app/controllers/auth');

/**
 * Expose routes
 */

module.exports = function applyRoutes(app) {
  app.get('/', main.index);
  app.post('/auth/token', auth.token);
  app.get('/:type(orders|accounts|portions|vendors)', api);
  app.get('/:type(orders|accounts|portions|vendors)/:id', api);
  app.post('/:type(orders|accounts|portions|vendors)', api);
};

<|next_version|>
'use strict';

const passport = require('passport');
const main = require('../app/controllers/main');
const api = require('../app/controllers/api');
const auth = require('../app/controllers/auth');

/**
 * Expose routes
 */

module.exports = function applyRoutes(app) {
  app.get('/', main.index);
  app.post('/auth/token', auth.token);
  app.get('/me', passport.authenticate('jwt'), function(req, res) {
    res.send(req.user);
  });
  app.get('/:type(orders|accounts|portions|vendors)', api);
  app.get('/:type(orders|accounts|portions|vendors)/:id', api);
  app.post('/:type(orders|accounts|portions|vendors)', api);
};


Load first project if only one project

Load first project if only one project

--- portal/js/router.js
+++ portal/js/router.js
@@ -14,6 +14,11 @@
   model: function () {
     return this.store.find('project');
   },
+  afterModel: function(projects, transition) {
+    if (projects.get('length') === 1) {
+      this.transitionTo('project', projects.objectAt(0));
+    }
+  },
   renderTemplate: function() {
     this.render('projects', {
       outlet: 'off-canvas'
@@ -25,6 +30,7 @@
   model: function(params) {
     return this.store.find('project', params.project_id);
   },
+
   renderTemplate: function() {
     this.render('investigations', {
       outlet: 'main'

<|original_code|>
App.Router.map(function () {
  this.resource('projects', {path: '/'}, function(){
    this.resource('project', {path: '/project/:project_id'}, function(){
      this.resource('investigation', {path: 'investigations/:investigation_id'});
    });
  });
});

App.Router.reopen({
  rootURL: '/portal'
})

App.ProjectsRoute = Ember.Route.extend({
  model: function () {
    return this.store.find('project');
  },
  renderTemplate: function() {
    this.render('projects', {
      outlet: 'off-canvas'
    });
  }
});

App.ProjectRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('project', params.project_id);
  },
  renderTemplate: function() {
    this.render('investigations', {
      outlet: 'main'
    });

    this.render({
      outlet: 'title'
    })
  }
});

<|edits_diff|>
--- portal/js/router.js
+++ portal/js/router.js
@@ -13,6 +13,11 @@
 App.ProjectsRoute = Ember.Route.extend({
   model: function () {
     return this.store.find('project');
+  },
+  afterModel: function(projects, transition) {
+    if (projects.get('length') === 1) {
+      this.transitionTo('project', projects.objectAt(0));
+    }
   },
   renderTemplate: function() {
     this.render('projects', {
<|current_version|>
App.Router.map(function () {
  this.resource('projects', {path: '/'}, function(){
    this.resource('project', {path: '/project/:project_id'}, function(){
      this.resource('investigation', {path: 'investigations/:investigation_id'});
    });
  });
});

App.Router.reopen({
  rootURL: '/portal'
})

App.ProjectsRoute = Ember.Route.extend({
  model: function () {
    return this.store.find('project');
  },
  afterModel: function(projects, transition) {
    if (projects.get('length') === 1) {
      this.transitionTo('project', projects.objectAt(0));
    }
  },
  renderTemplate: function() {
    this.render('projects', {
      outlet: 'off-canvas'
    });
  }
});

App.ProjectRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('project', params.project_id);
  },
  renderTemplate: function() {
    this.render('investigations', {
      outlet: 'main'
    });

    this.render({
      outlet: 'title'
    })
  }
});

<|next_version|>
App.Router.map(function () {
  this.resource('projects', {path: '/'}, function(){
    this.resource('project', {path: '/project/:project_id'}, function(){
      this.resource('investigation', {path: 'investigations/:investigation_id'});
    });
  });
});

App.Router.reopen({
  rootURL: '/portal'
})

App.ProjectsRoute = Ember.Route.extend({
  model: function () {
    return this.store.find('project');
  },
  afterModel: function(projects, transition) {
    if (projects.get('length') === 1) {
      this.transitionTo('project', projects.objectAt(0));
    }
  },
  renderTemplate: function() {
    this.render('projects', {
      outlet: 'off-canvas'
    });
  }
});

App.ProjectRoute = Ember.Route.extend({
  model: function(params) {
    return this.store.find('project', params.project_id);
  },

  renderTemplate: function() {
    this.render('investigations', {
      outlet: 'main'
    });

    this.render({
      outlet: 'title'
    })
  }
});


Create the user on form submission

Create the user on form submission

--- assets/js/main.js
+++ assets/js/main.js
@@ -1,5 +1,12 @@
 $(document).ready(function () {
+  var currentUser = {};
+
   $('form').on('submit', function () {
+    var userName = $('input#user-name').val();
+    io.socket.post('/user', { name: userName }, function (user, jwres) {
+      currentUser = user;
+    });
+
     return false;
   });

<|original_code|>
$(document).ready(function () {
  $('form').on('submit', function () {
    return false;
  });

  $('#login-modal').modal({
    backdrop: 'static',
    keyboard: false,
  });
});

<|edits_diff|>
--- assets/js/main.js
+++ assets/js/main.js
@@ -1,4 +1,6 @@
 $(document).ready(function () {
+  var currentUser = {};
+
   $('form').on('submit', function () {
     return false;
   });
<|current_version|>
$(document).ready(function () {
  var currentUser = {};

  $('form').on('submit', function () {
    return false;
  });

  $('#login-modal').modal({
    backdrop: 'static',
    keyboard: false,
  });
});

<|next_version|>
$(document).ready(function () {
  var currentUser = {};

  $('form').on('submit', function () {
    var userName = $('input#user-name').val();
    io.socket.post('/user', { name: userName }, function (user, jwres) {
      currentUser = user;
    });

    return false;
  });

  $('#login-modal').modal({
    backdrop: 'static',
    keyboard: false,
  });
});


Reduce the amount of console "spam", by ignoring `info`/`warn` calls, when running the unit-tests in Node.js/Travis

Compared to running the unit-tests in "regular" browsers, where any console output won't get mixed up with test output, in Node.js/Travis the test output looks quite noisy.
By ignoring `info`/`warn` calls, when running unit-tests in Node.js/Travis, the test output is a lot smaller not to mention that any *actual* failures are more easily spotted.

--- test/unit/clitests_helper.js
+++ test/unit/clitests_helper.js
@@ -13,6 +13,7 @@
  * limitations under the License.
  */

+import { setVerbosityLevel, VerbosityLevel } from '../../src/shared/util';
 import isNodeJS from '../../src/shared/is_node';
 import { PDFNodeStream } from '../../src/display/node_stream';
 import { setPDFNetworkStreamFactory } from '../../src/display/api';
@@ -23,6 +24,10 @@
                   'Node.js environments.');
 }

+// Reduce the amount of console "spam", by ignoring `info`/`warn` calls,
+// when running the unit-tests in Node.js/Travis.
+setVerbosityLevel(VerbosityLevel.ERRORS);
+
 // Set the network stream factory for the unit-tests.
 setPDFNetworkStreamFactory(function(params) {
   return new PDFNodeStream(params);

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

import isNodeJS from '../../src/shared/is_node';
import { PDFNodeStream } from '../../src/display/node_stream';
import { setPDFNetworkStreamFactory } from '../../src/display/api';

// Ensure that this script only runs in Node.js environments.
if (!isNodeJS()) {
  throw new Error('The `gulp unittestcli` command can only be used in ' +
                  'Node.js environments.');
}

// Set the network stream factory for the unit-tests.
setPDFNetworkStreamFactory(function(params) {
  return new PDFNodeStream(params);
});

<|edits_diff|>
--- test/unit/clitests_helper.js
+++ test/unit/clitests_helper.js
@@ -13,6 +13,7 @@
  * limitations under the License.
  */

+import { setVerbosityLevel, VerbosityLevel } from '../../src/shared/util';
 import isNodeJS from '../../src/shared/is_node';
 import { PDFNodeStream } from '../../src/display/node_stream';
 import { setPDFNetworkStreamFactory } from '../../src/display/api';
<|current_version|>
/* Copyright 2018 Mozilla Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { setVerbosityLevel, VerbosityLevel } from '../../src/shared/util';
import isNodeJS from '../../src/shared/is_node';
import { PDFNodeStream } from '../../src/display/node_stream';
import { setPDFNetworkStreamFactory } from '../../src/display/api';

// Ensure that this script only runs in Node.js environments.
if (!isNodeJS()) {
  throw new Error('The `gulp unittestcli` command can only be used in ' +
                  'Node.js environments.');
}

// Set the network stream factory for the unit-tests.
setPDFNetworkStreamFactory(function(params) {
  return new PDFNodeStream(params);
});

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

import { setVerbosityLevel, VerbosityLevel } from '../../src/shared/util';
import isNodeJS from '../../src/shared/is_node';
import { PDFNodeStream } from '../../src/display/node_stream';
import { setPDFNetworkStreamFactory } from '../../src/display/api';

// Ensure that this script only runs in Node.js environments.
if (!isNodeJS()) {
  throw new Error('The `gulp unittestcli` command can only be used in ' +
                  'Node.js environments.');
}

// Reduce the amount of console "spam", by ignoring `info`/`warn` calls,
// when running the unit-tests in Node.js/Travis.
setVerbosityLevel(VerbosityLevel.ERRORS);

// Set the network stream factory for the unit-tests.
setPDFNetworkStreamFactory(function(params) {
  return new PDFNodeStream(params);
});


Gather some information about field selectors

--- views/widgets/MappingView/index.js
+++ views/widgets/MappingView/index.js
@@ -1,10 +1,16 @@
 import Backbone from 'backbone';
 import myTemplate from './index.jade';
+import candela from '../../../../../src';

 let MappingView = Backbone.View.extend({
   initialize: function () {
   },
   render: function () {
+    const spec = candela.components.Scatter.options;
+    const fields = spec.filter((opt) => opt.selector && opt.selector[0] === 'field');
+
+    console.log(fields);
+
     this.$el.html(myTemplate());
   }
 });

<|original_code|>
import Backbone from 'backbone';
import myTemplate from './index.jade';

let MappingView = Backbone.View.extend({
  initialize: function () {
  },
  render: function () {
    this.$el.html(myTemplate());
  }
});

export default MappingView;

<|edits_diff|>
--- views/widgets/MappingView/index.js
+++ views/widgets/MappingView/index.js
@@ -1,5 +1,6 @@
 import Backbone from 'backbone';
 import myTemplate from './index.jade';
+import candela from '../../../../../src';

 let MappingView = Backbone.View.extend({
   initialize: function () {
<|current_version|>
import Backbone from 'backbone';
import myTemplate from './index.jade';
import candela from '../../../../../src';

let MappingView = Backbone.View.extend({
  initialize: function () {
  },
  render: function () {
    this.$el.html(myTemplate());
  }
});

export default MappingView;

<|next_version|>
import Backbone from 'backbone';
import myTemplate from './index.jade';
import candela from '../../../../../src';

let MappingView = Backbone.View.extend({
  initialize: function () {
  },
  render: function () {
    const spec = candela.components.Scatter.options;
    const fields = spec.filter((opt) => opt.selector && opt.selector[0] === 'field');

    console.log(fields);

    this.$el.html(myTemplate());
  }
});

export default MappingView;


Add code comments for clarity

Add code comments for clarity

--- main.js
+++ main.js
@@ -7,10 +7,12 @@
     mortgage: "Mortgage amount",
   },
   methods: {
+    // Format the number for currency
     currencyFormat: function(num) {
       // As seen at https://blog.tompawlak.org/number-currency-formatting-javascript.
       return "$" + num.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
     },
+    // Calculate the profit from the sale
     calculateProfit: function(num) {
       var price = document.getElementById('price').value;
       var fee = document.getElementById('fee').value / 100;

<|original_code|>
var vm = new Vue({
  el: '#homeselling',
  data: {
    heading: "What's My Profit?",
    homeprice: "Home Price",
    realtorfee: "Realtor fee (in percent)",
    mortgage: "Mortgage amount",
  },
  methods: {
    currencyFormat: function(num) {
      // As seen at https://blog.tompawlak.org/number-currency-formatting-javascript.
      return "$" + num.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
    },
    calculateProfit: function(num) {
      var price = document.getElementById('price').value;
      var fee = document.getElementById('fee').value / 100;
      var mortgage = document.getElementById('mortgage').value;

      var takehome = (price - (price * fee));
      var profit = takehome - mortgage;
      document.getElementById('takehome').innerHTML = '
Your takehome money after the Realtor fee will be ' + vm.currencyFormat(takehome) + '.
';
      document.getElementById('result').innerHTML = '
Your profit after paying off your mortgage will be ' + vm.currencyFormat(profit) + '.
';
      return false;
    }
  }
});

<|edits_diff|>
--- main.js
+++ main.js
@@ -7,6 +7,7 @@
     mortgage: "Mortgage amount",
   },
   methods: {
+    // Format the number for currency
     currencyFormat: function(num) {
       // As seen at https://blog.tompawlak.org/number-currency-formatting-javascript.
       return "$" + num.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
<|current_version|>
var vm = new Vue({
  el: '#homeselling',
  data: {
    heading: "What's My Profit?",
    homeprice: "Home Price",
    realtorfee: "Realtor fee (in percent)",
    mortgage: "Mortgage amount",
  },
  methods: {
    // Format the number for currency
    currencyFormat: function(num) {
      // As seen at https://blog.tompawlak.org/number-currency-formatting-javascript.
      return "$" + num.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
    },
    calculateProfit: function(num) {
      var price = document.getElementById('price').value;
      var fee = document.getElementById('fee').value / 100;
      var mortgage = document.getElementById('mortgage').value;

      var takehome = (price - (price * fee));
      var profit = takehome - mortgage;
      document.getElementById('takehome').innerHTML = '
Your takehome money after the Realtor fee will be ' + vm.currencyFormat(takehome) + '.
';
      document.getElementById('result').innerHTML = '
Your profit after paying off your mortgage will be ' + vm.currencyFormat(profit) + '.
';
      return false;
    }
  }
});

<|next_version|>
var vm = new Vue({
  el: '#homeselling',
  data: {
    heading: "What's My Profit?",
    homeprice: "Home Price",
    realtorfee: "Realtor fee (in percent)",
    mortgage: "Mortgage amount",
  },
  methods: {
    // Format the number for currency
    currencyFormat: function(num) {
      // As seen at https://blog.tompawlak.org/number-currency-formatting-javascript.
      return "$" + num.toFixed(2).replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,")
    },
    // Calculate the profit from the sale
    calculateProfit: function(num) {
      var price = document.getElementById('price').value;
      var fee = document.getElementById('fee').value / 100;
      var mortgage = document.getElementById('mortgage').value;

      var takehome = (price - (price * fee));
      var profit = takehome - mortgage;
      document.getElementById('takehome').innerHTML = '
Your takehome money after the Realtor fee will be ' + vm.currencyFormat(takehome) + '.
';
      document.getElementById('result').innerHTML = '
Your profit after paying off your mortgage will be ' + vm.currencyFormat(profit) + '.
';
      return false;
    }
  }
});


Add the use of PatientReducer in redux store

--- src/reducers/index.js
+++ src/reducers/index.js
@@ -5,6 +5,7 @@
 import { ModulesReducer } from './ModulesReducer';
 import { UserReducer } from './UserReducer';
 import { PrescriptionReducer } from './PrescriptionReducer';
+import { PatientReducer } from './PatientReducer';

 export default combineReducers({
   user: UserReducer,
@@ -13,4 +14,5 @@
   pages: PagesReducer,
   modules: ModulesReducer,
   prescription: PrescriptionReducer,
+  patient: PatientReducer,
 });

<|original_code|>
import { combineReducers } from 'redux';
import NavigationReducer from './NavigationReducer';
import SyncReducer from './SyncReducer';
import { PagesReducer } from './PagesReducer';
import { ModulesReducer } from './ModulesReducer';
import { UserReducer } from './UserReducer';
import { PrescriptionReducer } from './PrescriptionReducer';

export default combineReducers({
  user: UserReducer,
  nav: NavigationReducer,
  sync: SyncReducer,
  pages: PagesReducer,
  modules: ModulesReducer,
  prescription: PrescriptionReducer,
});

<|edits_diff|>
--- src/reducers/index.js
+++ src/reducers/index.js
@@ -5,6 +5,7 @@
 import { ModulesReducer } from './ModulesReducer';
 import { UserReducer } from './UserReducer';
 import { PrescriptionReducer } from './PrescriptionReducer';
+import { PatientReducer } from './PatientReducer';

 export default combineReducers({
   user: UserReducer,
<|current_version|>
import { combineReducers } from 'redux';
import NavigationReducer from './NavigationReducer';
import SyncReducer from './SyncReducer';
import { PagesReducer } from './PagesReducer';
import { ModulesReducer } from './ModulesReducer';
import { UserReducer } from './UserReducer';
import { PrescriptionReducer } from './PrescriptionReducer';
import { PatientReducer } from './PatientReducer';

export default combineReducers({
  user: UserReducer,
  nav: NavigationReducer,
  sync: SyncReducer,
  pages: PagesReducer,
  modules: ModulesReducer,
  prescription: PrescriptionReducer,
});

<|next_version|>
import { combineReducers } from 'redux';
import NavigationReducer from './NavigationReducer';
import SyncReducer from './SyncReducer';
import { PagesReducer } from './PagesReducer';
import { ModulesReducer } from './ModulesReducer';
import { UserReducer } from './UserReducer';
import { PrescriptionReducer } from './PrescriptionReducer';
import { PatientReducer } from './PatientReducer';

export default combineReducers({
  user: UserReducer,
  nav: NavigationReducer,
  sync: SyncReducer,
  pages: PagesReducer,
  modules: ModulesReducer,
  prescription: PrescriptionReducer,
  patient: PatientReducer,
});


Check for authorization header before split

--- src/auth/middleware.js
+++ src/auth/middleware.js
@@ -4,8 +4,14 @@
 import { AuthenticationError } from '../components/errors';

 export function isTokenAuthenticated(req, res, next) {
+    const authString = req.get('Authorization');
+    if (!authString) {
+        // No auth header provided
+        return next(new AuthenticationError());
+    }
     const [scheme, token] = req.get('Authorization').split(' ');
     if (scheme !== 'Token') {
+        // Only token authentication is accepted
         return next(new AuthenticationError());
     }

<|original_code|>
import expressJwt from 'express-jwt';
import db from '../models';
import config from '../config';
import { AuthenticationError } from '../components/errors';

export function isTokenAuthenticated(req, res, next) {
    const [scheme, token] = req.get('Authorization').split(' ');
    if (scheme !== 'Token') {
        return next(new AuthenticationError());
    }

    db.APIToken.findOne({
        where: { token }
    })
    .then(apiToken => {
        if (!apiToken) {
            return next(new AuthenticationError());
        }
        req.apiToken = apiToken;
        return next();
    })
    .catch(next);
}

export const isAuthenticated = expressJwt({ secret: config.jwtSecret });

<|edits_diff|>
--- src/auth/middleware.js
+++ src/auth/middleware.js
@@ -4,6 +4,11 @@
 import { AuthenticationError } from '../components/errors';

 export function isTokenAuthenticated(req, res, next) {
+    const authString = req.get('Authorization');
+    if (!authString) {
+        // No auth header provided
+        return next(new AuthenticationError());
+    }
     const [scheme, token] = req.get('Authorization').split(' ');
     if (scheme !== 'Token') {
         return next(new AuthenticationError());
<|current_version|>
import expressJwt from 'express-jwt';
import db from '../models';
import config from '../config';
import { AuthenticationError } from '../components/errors';

export function isTokenAuthenticated(req, res, next) {
    const authString = req.get('Authorization');
    if (!authString) {
        // No auth header provided
        return next(new AuthenticationError());
    }
    const [scheme, token] = req.get('Authorization').split(' ');
    if (scheme !== 'Token') {
        return next(new AuthenticationError());
    }

    db.APIToken.findOne({
        where: { token }
    })
    .then(apiToken => {
        if (!apiToken) {
            return next(new AuthenticationError());
        }
        req.apiToken = apiToken;
        return next();
    })
    .catch(next);
}

export const isAuthenticated = expressJwt({ secret: config.jwtSecret });

<|next_version|>
import expressJwt from 'express-jwt';
import db from '../models';
import config from '../config';
import { AuthenticationError } from '../components/errors';

export function isTokenAuthenticated(req, res, next) {
    const authString = req.get('Authorization');
    if (!authString) {
        // No auth header provided
        return next(new AuthenticationError());
    }
    const [scheme, token] = req.get('Authorization').split(' ');
    if (scheme !== 'Token') {
        // Only token authentication is accepted
        return next(new AuthenticationError());
    }

    db.APIToken.findOne({
        where: { token }
    })
    .then(apiToken => {
        if (!apiToken) {
            return next(new AuthenticationError());
        }
        req.apiToken = apiToken;
        return next();
    })
    .catch(next);
}

export const isAuthenticated = expressJwt({ secret: config.jwtSecret });


Add additional matchers to test to assert text output

--- tests/acceptance/application-test.js
+++ tests/acceptance/application-test.js
@@ -8,6 +8,7 @@

   andThen(function() {
     assert.equal(find('.enabled_foo').length, 1);
+    assert.equal(find('.enabled_foo').text(), 'ENABLED_FOO!! \\o/');
   });
 });

@@ -24,6 +25,7 @@

   andThen(function() {
     assert.equal(find('.disabled_bar').length, 1);
+    assert.equal(find('.disabled_bar').text(), 'DISABLED_BAR!! \\o/');
   });
 });

<|original_code|>
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | application');

test('enabled flags are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_foo').length, 1);
  });
});

test('disabled flags are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_bar').length, 0);
  });
});

test('disabled else blocks are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_bar').length, 1);
  });
});

test('enabled else blocks are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_foo').length, 0);
  });
});

<|edits_diff|>
--- tests/acceptance/application-test.js
+++ tests/acceptance/application-test.js
@@ -8,6 +8,7 @@

   andThen(function() {
     assert.equal(find('.enabled_foo').length, 1);
+    assert.equal(find('.enabled_foo').text(), 'ENABLED_FOO!! \\o/');
   });
 });

<|current_version|>
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | application');

test('enabled flags are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_foo').length, 1);
    assert.equal(find('.enabled_foo').text(), 'ENABLED_FOO!! \\o/');
  });
});

test('disabled flags are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_bar').length, 0);
  });
});

test('disabled else blocks are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_bar').length, 1);
  });
});

test('enabled else blocks are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_foo').length, 0);
  });
});

<|next_version|>
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | application');

test('enabled flags are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_foo').length, 1);
    assert.equal(find('.enabled_foo').text(), 'ENABLED_FOO!! \\o/');
  });
});

test('disabled flags are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.enabled_bar').length, 0);
  });
});

test('disabled else blocks are shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_bar').length, 1);
    assert.equal(find('.disabled_bar').text(), 'DISABLED_BAR!! \\o/');
  });
});

test('enabled else blocks are not shown', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal(find('.disabled_foo').length, 0);
  });
});


Apply Buble to build locale

Apply Buble to build locale

--- scripts/build-locale.js
+++ scripts/build-locale.js
@@ -3,6 +3,7 @@
 import {rollup} from 'rollup'
 import uglify from 'rollup-plugin-uglify'
 import chalk from 'chalk'
+import buble from 'rollup-plugin-buble'

 async function build () {
   console.log(chalk.cyan('Building individual translations.'))
@@ -11,6 +12,7 @@
     const inputOptions = {
       input: path.join(__dirname, '..', 'src', 'locale', 'translations', file),
       plugins: [
+        buble(),
         uglify()
       ]
     }
@@ -29,6 +31,7 @@
   const bundle = await rollup({
     input: path.join(__dirname, '..', 'src', 'locale', 'index.js'),
     plugins: [
+      buble(),
       uglify()
     ]
   })

<|original_code|>
import fs from 'fs'
import path from 'path'
import {rollup} from 'rollup'
import uglify from 'rollup-plugin-uglify'
import chalk from 'chalk'

async function build () {
  console.log(chalk.cyan('Building individual translations.'))
  const files = fs.readdirSync('./src/locale/translations')
  files.forEach(async function (file) {
    const inputOptions = {
      input: path.join(__dirname, '..', 'src', 'locale', 'translations', file),
      plugins: [
        uglify()
      ]
    }
    const bundle = await rollup(inputOptions)
    const outputOptions = {
      file: path.join(__dirname, '..', 'dist', 'locale', 'translations', file),
      format: 'es'
    }
    await bundle.write(outputOptions)
  })
  await console.log(chalk.green('Individual translations built.'))
}

async function buildAll () {
  console.log(chalk.cyan('Building translation importer.'))
  const bundle = await rollup({
    input: path.join(__dirname, '..', 'src', 'locale', 'index.js'),
    plugins: [
      uglify()
    ]
  })
  await bundle.write({
    file: path.join(__dirname, '..', 'dist', 'locale', 'index.js'),
    format: 'es'
  })
  await console.log(chalk.green('All translations built.'))
}

build()
buildAll()

<|edits_diff|>
--- scripts/build-locale.js
+++ scripts/build-locale.js
@@ -3,6 +3,7 @@
 import {rollup} from 'rollup'
 import uglify from 'rollup-plugin-uglify'
 import chalk from 'chalk'
+import buble from 'rollup-plugin-buble'

 async function build () {
   console.log(chalk.cyan('Building individual translations.'))
@@ -11,6 +12,7 @@
     const inputOptions = {
       input: path.join(__dirname, '..', 'src', 'locale', 'translations', file),
       plugins: [
+        buble(),
         uglify()
       ]
     }
<|current_version|>
import fs from 'fs'
import path from 'path'
import {rollup} from 'rollup'
import uglify from 'rollup-plugin-uglify'
import chalk from 'chalk'
import buble from 'rollup-plugin-buble'

async function build () {
  console.log(chalk.cyan('Building individual translations.'))
  const files = fs.readdirSync('./src/locale/translations')
  files.forEach(async function (file) {
    const inputOptions = {
      input: path.join(__dirname, '..', 'src', 'locale', 'translations', file),
      plugins: [
        buble(),
        uglify()
      ]
    }
    const bundle = await rollup(inputOptions)
    const outputOptions = {
      file: path.join(__dirname, '..', 'dist', 'locale', 'translations', file),
      format: 'es'
    }
    await bundle.write(outputOptions)
  })
  await console.log(chalk.green('Individual translations built.'))
}

async function buildAll () {
  console.log(chalk.cyan('Building translation importer.'))
  const bundle = await rollup({
    input: path.join(__dirname, '..', 'src', 'locale', 'index.js'),
    plugins: [
      uglify()
    ]
  })
  await bundle.write({
    file: path.join(__dirname, '..', 'dist', 'locale', 'index.js'),
    format: 'es'
  })
  await console.log(chalk.green('All translations built.'))
}

build()
buildAll()

<|next_version|>
import fs from 'fs'
import path from 'path'
import {rollup} from 'rollup'
import uglify from 'rollup-plugin-uglify'
import chalk from 'chalk'
import buble from 'rollup-plugin-buble'

async function build () {
  console.log(chalk.cyan('Building individual translations.'))
  const files = fs.readdirSync('./src/locale/translations')
  files.forEach(async function (file) {
    const inputOptions = {
      input: path.join(__dirname, '..', 'src', 'locale', 'translations', file),
      plugins: [
        buble(),
        uglify()
      ]
    }
    const bundle = await rollup(inputOptions)
    const outputOptions = {
      file: path.join(__dirname, '..', 'dist', 'locale', 'translations', file),
      format: 'es'
    }
    await bundle.write(outputOptions)
  })
  await console.log(chalk.green('Individual translations built.'))
}

async function buildAll () {
  console.log(chalk.cyan('Building translation importer.'))
  const bundle = await rollup({
    input: path.join(__dirname, '..', 'src', 'locale', 'index.js'),
    plugins: [
      buble(),
      uglify()
    ]
  })
  await bundle.write({
    file: path.join(__dirname, '..', 'dist', 'locale', 'index.js'),
    format: 'es'
  })
  await console.log(chalk.green('All translations built.'))
}

build()
buildAll()


Revert "Remove unnecessary router reopening"

This reverts commit 46040476a75b4470acff131f39a1391f039af422.

--- tests/helpers/start-app.js
+++ tests/helpers/start-app.js
@@ -1,4 +1,5 @@
 import Application from 'appkit/app';
+import Router from 'appkit/router';

 function startApp(attrs) {
   var App;
@@ -9,6 +10,10 @@
     LOG_ACTIVE_GENERATION:false,
     LOG_VIEW_LOOKUPS: false
   }, attrs); // but you can override;
+
+  Router.reopen({
+    location: 'none'
+  });

   Ember.run(function(){
     App = Application.create(attributes);

<|original_code|>
import Application from 'appkit/app';

function startApp(attrs) {
  var App;

  var attributes = Ember.merge({
    // useful Test defaults
    rootElement: '#ember-testing',
    LOG_ACTIVE_GENERATION:false,
    LOG_VIEW_LOOKUPS: false
  }, attrs); // but you can override;

  Ember.run(function(){
    App = Application.create(attributes);
    App.setupForTesting();
    App.injectTestHelpers();
  });

  App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"

  return App;
}

export default startApp;

<|edits_diff|>
--- tests/helpers/start-app.js
+++ tests/helpers/start-app.js
@@ -1,4 +1,5 @@
 import Application from 'appkit/app';
+import Router from 'appkit/router';

 function startApp(attrs) {
   var App;
<|current_version|>
import Application from 'appkit/app';
import Router from 'appkit/router';

function startApp(attrs) {
  var App;

  var attributes = Ember.merge({
    // useful Test defaults
    rootElement: '#ember-testing',
    LOG_ACTIVE_GENERATION:false,
    LOG_VIEW_LOOKUPS: false
  }, attrs); // but you can override;

  Ember.run(function(){
    App = Application.create(attributes);
    App.setupForTesting();
    App.injectTestHelpers();
  });

  App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"

  return App;
}

export default startApp;

<|next_version|>
import Application from 'appkit/app';
import Router from 'appkit/router';

function startApp(attrs) {
  var App;

  var attributes = Ember.merge({
    // useful Test defaults
    rootElement: '#ember-testing',
    LOG_ACTIVE_GENERATION:false,
    LOG_VIEW_LOOKUPS: false
  }, attrs); // but you can override;

  Router.reopen({
    location: 'none'
  });

  Ember.run(function(){
    App = Application.create(attributes);
    App.setupForTesting();
    App.injectTestHelpers();
  });

  App.reset(); // this shouldn't be needed, i want to be able to "start an app at a specific URL"

  return App;
}

export default startApp;


Add Octocat icon to Header

Add Octocat icon to Header

--- src/features/header/header-main/navigation/index.js
+++ src/features/header/header-main/navigation/index.js
@@ -3,6 +3,7 @@

 import { Ul, Li, Nav } from "./styled-components";
 import { LinkedInIcon } from "../../../../elements/linkedin-icon";
+import { OctocatIcon } from "../../../../elements/octocat-icon";
 import { Highlight } from "../../../../elements/highlight";
 import { Chevron } from "../../../../elements/chevron";
 import theme from "../../../../global/style/mainTheme";
@@ -18,7 +19,12 @@
         </Highlight>

<Highlight {...props}>Contact</Highlight>

+
+

+

<LinkedInIcon />

+
<OctocatIcon />

+

 );

<|original_code|>
//@flow
import React from "react";

import { Ul, Li, Nav } from "./styled-components";
import { LinkedInIcon } from "../../../../elements/linkedin-icon";
import { Highlight } from "../../../../elements/highlight";
import { Chevron } from "../../../../elements/chevron";
import theme from "../../../../global/style/mainTheme";

export const MainNav = (props: {}) => (

<Highlight {...props} url="/">Projects</Highlight>

<Highlight {...props}>About</Highlight>

        <Highlight highlightColor="transparent" {...props}>
          <Chevron {...props}>Download</Chevron>
        </Highlight>

<Highlight {...props}>Contact</Highlight>

<LinkedInIcon />

);

<|edits_diff|>
--- src/features/header/header-main/navigation/index.js
+++ src/features/header/header-main/navigation/index.js
@@ -3,6 +3,7 @@

 import { Ul, Li, Nav } from "./styled-components";
 import { LinkedInIcon } from "../../../../elements/linkedin-icon";
+import { OctocatIcon } from "../../../../elements/octocat-icon";
 import { Highlight } from "../../../../elements/highlight";
 import { Chevron } from "../../../../elements/chevron";
 import theme from "../../../../global/style/mainTheme";
@@ -18,7 +19,11 @@
         </Highlight>

<Highlight {...props}>Contact</Highlight>

+
+

+

<LinkedInIcon />

+
<OctocatIcon />

 );
<|current_version|>
//@flow
import React from "react";

import { Ul, Li, Nav } from "./styled-components";
import { LinkedInIcon } from "../../../../elements/linkedin-icon";
import { OctocatIcon } from "../../../../elements/octocat-icon";
import { Highlight } from "../../../../elements/highlight";
import { Chevron } from "../../../../elements/chevron";
import theme from "../../../../global/style/mainTheme";

export const MainNav = (props: {}) => (

<Highlight {...props} url="/">Projects</Highlight>

<Highlight {...props}>About</Highlight>

        <Highlight highlightColor="transparent" {...props}>
          <Chevron {...props}>Download</Chevron>
        </Highlight>

<Highlight {...props}>Contact</Highlight>

<LinkedInIcon />

<OctocatIcon />

);

<|next_version|>
//@flow
import React from "react";

import { Ul, Li, Nav } from "./styled-components";
import { LinkedInIcon } from "../../../../elements/linkedin-icon";
import { OctocatIcon } from "../../../../elements/octocat-icon";
import { Highlight } from "../../../../elements/highlight";
import { Chevron } from "../../../../elements/chevron";
import theme from "../../../../global/style/mainTheme";

export const MainNav = (props: {}) => (

<Highlight {...props} url="/">Projects</Highlight>

<Highlight {...props}>About</Highlight>

        <Highlight highlightColor="transparent" {...props}>
          <Chevron {...props}>Download</Chevron>
        </Highlight>

<Highlight {...props}>Contact</Highlight>

<LinkedInIcon />

<OctocatIcon />

);