Update storage on history filter change

Update storage on history filter change

--- zucchini-ui-frontend-react/src/store.js
+++ zucchini-ui-frontend-react/src/store.js
@@ -7,6 +7,7 @@
 import reducer from './reducer';
 import featureFiltersStorage from './filters/featureFiltersStorage';
 import statsDashboardFiltersStorage from './filters/statsDashboardFiltersStorage';
+import historyFiltersStorage from './filters/historyFiltersStorage';
 import { default as createStorageMiddleware } from './browserStorage/createMiddleware';

@@ -15,6 +16,7 @@
 const middlewares = [
   createStorageMiddleware(featureFiltersStorage, state => state.featureFilters),
   createStorageMiddleware(statsDashboardFiltersStorage, state => state.statsDashboardFilters),
+  createStorageMiddleware(historyFiltersStorage, state => state.historyFilters),
   routerMiddleware(browserHistory),
   thunkMiddleware,
   promiseMiddleware(),

<|original_code|>
import { createStore, applyMiddleware, compose } from 'redux';
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux';
import { browserHistory } from 'react-router';
import promiseMiddleware from 'redux-promise-middleware';
import thunkMiddleware from 'redux-thunk';

import reducer from './reducer';
import featureFiltersStorage from './filters/featureFiltersStorage';
import statsDashboardFiltersStorage from './filters/statsDashboardFiltersStorage';
import { default as createStorageMiddleware } from './browserStorage/createMiddleware';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const middlewares = [
  createStorageMiddleware(featureFiltersStorage, state => state.featureFilters),
  createStorageMiddleware(statsDashboardFiltersStorage, state => state.statsDashboardFilters),
  routerMiddleware(browserHistory),
  thunkMiddleware,
  promiseMiddleware(),
];

const initialState = {};

const store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(...middlewares)));

const history = syncHistoryWithStore(browserHistory, store);

export default store;
export { history };

<|edits_diff|>
--- zucchini-ui-frontend-react/src/store.js
+++ zucchini-ui-frontend-react/src/store.js
@@ -7,6 +7,7 @@
 import reducer from './reducer';
 import featureFiltersStorage from './filters/featureFiltersStorage';
 import statsDashboardFiltersStorage from './filters/statsDashboardFiltersStorage';
+import historyFiltersStorage from './filters/historyFiltersStorage';
 import { default as createStorageMiddleware } from './browserStorage/createMiddleware';

<|current_version|>
import { createStore, applyMiddleware, compose } from 'redux';
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux';
import { browserHistory } from 'react-router';
import promiseMiddleware from 'redux-promise-middleware';
import thunkMiddleware from 'redux-thunk';

import reducer from './reducer';
import featureFiltersStorage from './filters/featureFiltersStorage';
import statsDashboardFiltersStorage from './filters/statsDashboardFiltersStorage';
import historyFiltersStorage from './filters/historyFiltersStorage';
import { default as createStorageMiddleware } from './browserStorage/createMiddleware';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const middlewares = [
  createStorageMiddleware(featureFiltersStorage, state => state.featureFilters),
  createStorageMiddleware(statsDashboardFiltersStorage, state => state.statsDashboardFilters),
  routerMiddleware(browserHistory),
  thunkMiddleware,
  promiseMiddleware(),
];

const initialState = {};

const store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(...middlewares)));

const history = syncHistoryWithStore(browserHistory, store);

export default store;
export { history };

<|next_version|>
import { createStore, applyMiddleware, compose } from 'redux';
import { syncHistoryWithStore, routerMiddleware } from 'react-router-redux';
import { browserHistory } from 'react-router';
import promiseMiddleware from 'redux-promise-middleware';
import thunkMiddleware from 'redux-thunk';

import reducer from './reducer';
import featureFiltersStorage from './filters/featureFiltersStorage';
import statsDashboardFiltersStorage from './filters/statsDashboardFiltersStorage';
import historyFiltersStorage from './filters/historyFiltersStorage';
import { default as createStorageMiddleware } from './browserStorage/createMiddleware';

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const middlewares = [
  createStorageMiddleware(featureFiltersStorage, state => state.featureFilters),
  createStorageMiddleware(statsDashboardFiltersStorage, state => state.statsDashboardFilters),
  createStorageMiddleware(historyFiltersStorage, state => state.historyFilters),
  routerMiddleware(browserHistory),
  thunkMiddleware,
  promiseMiddleware(),
];

const initialState = {};

const store = createStore(reducer, initialState, composeEnhancers(applyMiddleware(...middlewares)));

const history = syncHistoryWithStore(browserHistory, store);

export default store;
export { history };


Add Spanish to list of available languages

--- chrome/src/js/utils/Languages/index.js
+++ chrome/src/js/utils/Languages/index.js
@@ -2,12 +2,14 @@

 import cs from './lang/cs';
 import en from './lang/en';
+import es from './lang/es';
 import nl from './lang/nl';
 import sk from './lang/sk';

 const ALL = [
   cs,
   en,
+  es,
   nl,
   sk
 ];

<|original_code|>
import Settings from 'utils/Settings';

import cs from './lang/cs';
import en from './lang/en';
import nl from './lang/nl';
import sk from './lang/sk';

const ALL = [
  cs,
  en,
  nl,
  sk
];

function getAvailable() {
  return ALL.slice();
}

function getSelected() {
  return Settings.get().then(({ language }) => language);
}

function find(languageCode) {
  const majorLanguageCode = languageCode.split(/-_/).shift().toLowerCase();

  return ALL.find(({ code }) => code === majorLanguageCode);
}

function detect(document) {
  const siteLanguageCode = document.documentElement.getAttribute('lang');
  const navigatorLanguageCode = navigator.language;
  const detectedlanguage = find(siteLanguageCode) || find(navigatorLanguageCode);

  return detectedlanguage || null;
}

export default {
  detect,
  find,
  getAvailable,
  getSelected
};

<|edits_diff|>
--- chrome/src/js/utils/Languages/index.js
+++ chrome/src/js/utils/Languages/index.js
@@ -2,6 +2,7 @@

 import cs from './lang/cs';
 import en from './lang/en';
+import es from './lang/es';
 import nl from './lang/nl';
 import sk from './lang/sk';

<|current_version|>
import Settings from 'utils/Settings';

import cs from './lang/cs';
import en from './lang/en';
import es from './lang/es';
import nl from './lang/nl';
import sk from './lang/sk';

const ALL = [
  cs,
  en,
  nl,
  sk
];

function getAvailable() {
  return ALL.slice();
}

function getSelected() {
  return Settings.get().then(({ language }) => language);
}

function find(languageCode) {
  const majorLanguageCode = languageCode.split(/-_/).shift().toLowerCase();

  return ALL.find(({ code }) => code === majorLanguageCode);
}

function detect(document) {
  const siteLanguageCode = document.documentElement.getAttribute('lang');
  const navigatorLanguageCode = navigator.language;
  const detectedlanguage = find(siteLanguageCode) || find(navigatorLanguageCode);

  return detectedlanguage || null;
}

export default {
  detect,
  find,
  getAvailable,
  getSelected
};

<|next_version|>
import Settings from 'utils/Settings';

import cs from './lang/cs';
import en from './lang/en';
import es from './lang/es';
import nl from './lang/nl';
import sk from './lang/sk';

const ALL = [
  cs,
  en,
  es,
  nl,
  sk
];

function getAvailable() {
  return ALL.slice();
}

function getSelected() {
  return Settings.get().then(({ language }) => language);
}

function find(languageCode) {
  const majorLanguageCode = languageCode.split(/-_/).shift().toLowerCase();

  return ALL.find(({ code }) => code === majorLanguageCode);
}

function detect(document) {
  const siteLanguageCode = document.documentElement.getAttribute('lang');
  const navigatorLanguageCode = navigator.language;
  const detectedlanguage = find(siteLanguageCode) || find(navigatorLanguageCode);

  return detectedlanguage || null;
}

export default {
  detect,
  find,
  getAvailable,
  getSelected
};


Disable the assigned list when changing to the next status

--- Resources/public/js/updateAssignedList.js
+++ Resources/public/js/updateAssignedList.js
@@ -13,6 +13,7 @@
             status = currentStateId;
         }

+        $assigned.attr('disabled','disabled');
         $.ajax({
             url: Routing.generate('integrated_workflow_assigned', {
                 'workflow':workflowId,
@@ -36,6 +37,8 @@

                     $tmp.appendTo($assigned);
                 });
+
+                $assigned.removeAttr('disabled');
             }
         });
     };

<|original_code|>
$(function() {

    var $nextStatus = $('.next-status-choice');
    var $assigned = $('.assigned-choice');

    var workflowId = $('.workflow-hidden').val();
    var currentStateId = $('.current-state').data('value');

    var UpdateAssignedList = function() {
        var status = $('input:checked', $nextStatus).val();

        if (status == undefined) {
            status = currentStateId;
        }

        $.ajax({
            url: Routing.generate('integrated_workflow_assigned', {
                'workflow':workflowId,
                'state':status,
                '_format':'json'
            }),
            dataType: 'json',
            success: function(response) {
                var selected = $('option:selected', $assigned).val();

                var $firstOption = $('option:first', $assigned);
                var $option = $firstOption.clone();
                $firstOption.siblings().remove();

                $.each(response.users, function(id, name) {
                    var $tmp = $option.clone().val(id).text(name);

                    if (id==selected) {
                        $tmp.attr('selected','selected');
                    }

                    $tmp.appendTo($assigned);
                });
            }
        });
    };

    $('input', $nextStatus).change(UpdateAssignedList);
    UpdateAssignedList();

});
<|edits_diff|>
--- Resources/public/js/updateAssignedList.js
+++ Resources/public/js/updateAssignedList.js
@@ -13,6 +13,7 @@
             status = currentStateId;
         }

+        $assigned.attr('disabled','disabled');
         $.ajax({
             url: Routing.generate('integrated_workflow_assigned', {
                 'workflow':workflowId,
<|current_version|>
$(function() {

    var $nextStatus = $('.next-status-choice');
    var $assigned = $('.assigned-choice');

    var workflowId = $('.workflow-hidden').val();
    var currentStateId = $('.current-state').data('value');

    var UpdateAssignedList = function() {
        var status = $('input:checked', $nextStatus).val();

        if (status == undefined) {
            status = currentStateId;
        }

        $assigned.attr('disabled','disabled');
        $.ajax({
            url: Routing.generate('integrated_workflow_assigned', {
                'workflow':workflowId,
                'state':status,
                '_format':'json'
            }),
            dataType: 'json',
            success: function(response) {
                var selected = $('option:selected', $assigned).val();

                var $firstOption = $('option:first', $assigned);
                var $option = $firstOption.clone();
                $firstOption.siblings().remove();

                $.each(response.users, function(id, name) {
                    var $tmp = $option.clone().val(id).text(name);

                    if (id==selected) {
                        $tmp.attr('selected','selected');
                    }

                    $tmp.appendTo($assigned);
                });
            }
        });
    };

    $('input', $nextStatus).change(UpdateAssignedList);
    UpdateAssignedList();

});
<|next_version|>
$(function() {

    var $nextStatus = $('.next-status-choice');
    var $assigned = $('.assigned-choice');

    var workflowId = $('.workflow-hidden').val();
    var currentStateId = $('.current-state').data('value');

    var UpdateAssignedList = function() {
        var status = $('input:checked', $nextStatus).val();

        if (status == undefined) {
            status = currentStateId;
        }

        $assigned.attr('disabled','disabled');
        $.ajax({
            url: Routing.generate('integrated_workflow_assigned', {
                'workflow':workflowId,
                'state':status,
                '_format':'json'
            }),
            dataType: 'json',
            success: function(response) {
                var selected = $('option:selected', $assigned).val();

                var $firstOption = $('option:first', $assigned);
                var $option = $firstOption.clone();
                $firstOption.siblings().remove();

                $.each(response.users, function(id, name) {
                    var $tmp = $option.clone().val(id).text(name);

                    if (id==selected) {
                        $tmp.attr('selected','selected');
                    }

                    $tmp.appendTo($assigned);
                });

                $assigned.removeAttr('disabled');
            }
        });
    };

    $('input', $nextStatus).change(UpdateAssignedList);
    UpdateAssignedList();

});


Revert "Remove new action plan button"

Revert "Remove new action plan button"

This reverts commit 76dd907effe40f7c1d4bb323b14a06eba8beb78b.

--- app/frontend/action_plans/action_plans_sidebar.component.js
+++ app/frontend/action_plans/action_plans_sidebar.component.js
@@ -1,8 +1,10 @@
 import ActionPlansFilters  from './action_plans_filters.component';
+import NewActionPlanButton from './new_action_plan_button.component';

 export default function () {
   return (

+      <NewActionPlanButton />

{I18n.t('proposals.index.filter.title')}

<|original_code|>
import ActionPlansFilters  from './action_plans_filters.component';

export default function () {
  return (

{I18n.t('proposals.index.filter.title')}

          <ActionPlansFilters />

  )
}

<|edits_diff|>
--- app/frontend/action_plans/action_plans_sidebar.component.js
+++ app/frontend/action_plans/action_plans_sidebar.component.js
@@ -1,4 +1,5 @@
 import ActionPlansFilters  from './action_plans_filters.component';
+import NewActionPlanButton from './new_action_plan_button.component';

 export default function () {
   return (
<|current_version|>
import ActionPlansFilters  from './action_plans_filters.component';
import NewActionPlanButton from './new_action_plan_button.component';

export default function () {
  return (

{I18n.t('proposals.index.filter.title')}

          <ActionPlansFilters />

  )
}

<|next_version|>
import ActionPlansFilters  from './action_plans_filters.component';
import NewActionPlanButton from './new_action_plan_button.component';

export default function () {
  return (

      <NewActionPlanButton />

{I18n.t('proposals.index.filter.title')}

          <ActionPlansFilters />

  )
}


Reset search results on new search

Reset search results on new search

--- app/menu/menu-controller.js
+++ app/menu/menu-controller.js
@@ -30,6 +30,8 @@
         }

         $scope.search = function() {
+            $scope.resetSearch();
+
             SearchService.Search($scope.search_expression, {'services': ['UserService', 'NewsService'], 'length': '2', 'offset': '0'}).then(function(response) {
                 if (response.success === true && response.data.length > 0) {
                     angular.forEach(response.data, function(res, id) {
@@ -40,5 +42,9 @@
                 }
             });
         }
+
+        $scope.resetSearch = function() {
+            $scope.results = [];
+        }
     }
 })();

<|original_code|>
(function () {
    'use strict';

    angular
        .module('app')
        .controller('MenuController', MenuController);

    MenuController.$inject = ['$scope', 'UserService', '$rootScope', 'SearchService', 'TranslateService'];
    function MenuController($scope, UserService, $rootScope, SearchService, TranslateService) {
        initController();

        function initController() {
            $scope.search_expression = null;
            $scope.results = [];
            $scope.displaySearchResults = false;
            $scope.languages = [];

            TranslateService.GetLanguages().then(function(response) {
                if (response.success) {
                    $scope.languages = response.data;
                }
            });
        }

        $scope.setSearchResults = function(value) {
            if (value === false) {
                $scope.results = [];
            }
            $scope.displaySearchResults = value;
        }

        $scope.search = function() {
            SearchService.Search($scope.search_expression, {'services': ['UserService', 'NewsService'], 'length': '2', 'offset': '0'}).then(function(response) {
                if (response.success === true && response.data.length > 0) {
                    angular.forEach(response.data, function(res, id) {
                        if (res.success === true) {
                            $scope.results.push(res.data);
                        }
                    });
                }
            });
        }
    }
})();
<|edits_diff|>
--- app/menu/menu-controller.js
+++ app/menu/menu-controller.js
@@ -30,6 +30,8 @@
         }

         $scope.search = function() {
+            $scope.resetSearch();
+
             SearchService.Search($scope.search_expression, {'services': ['UserService', 'NewsService'], 'length': '2', 'offset': '0'}).then(function(response) {
                 if (response.success === true && response.data.length > 0) {
                     angular.forEach(response.data, function(res, id) {
<|current_version|>
(function () {
    'use strict';

    angular
        .module('app')
        .controller('MenuController', MenuController);

    MenuController.$inject = ['$scope', 'UserService', '$rootScope', 'SearchService', 'TranslateService'];
    function MenuController($scope, UserService, $rootScope, SearchService, TranslateService) {
        initController();

        function initController() {
            $scope.search_expression = null;
            $scope.results = [];
            $scope.displaySearchResults = false;
            $scope.languages = [];

            TranslateService.GetLanguages().then(function(response) {
                if (response.success) {
                    $scope.languages = response.data;
                }
            });
        }

        $scope.setSearchResults = function(value) {
            if (value === false) {
                $scope.results = [];
            }
            $scope.displaySearchResults = value;
        }

        $scope.search = function() {
            $scope.resetSearch();

            SearchService.Search($scope.search_expression, {'services': ['UserService', 'NewsService'], 'length': '2', 'offset': '0'}).then(function(response) {
                if (response.success === true && response.data.length > 0) {
                    angular.forEach(response.data, function(res, id) {
                        if (res.success === true) {
                            $scope.results.push(res.data);
                        }
                    });
                }
            });
        }
    }
})();
<|next_version|>
(function () {
    'use strict';

    angular
        .module('app')
        .controller('MenuController', MenuController);

    MenuController.$inject = ['$scope', 'UserService', '$rootScope', 'SearchService', 'TranslateService'];
    function MenuController($scope, UserService, $rootScope, SearchService, TranslateService) {
        initController();

        function initController() {
            $scope.search_expression = null;
            $scope.results = [];
            $scope.displaySearchResults = false;
            $scope.languages = [];

            TranslateService.GetLanguages().then(function(response) {
                if (response.success) {
                    $scope.languages = response.data;
                }
            });
        }

        $scope.setSearchResults = function(value) {
            if (value === false) {
                $scope.results = [];
            }
            $scope.displaySearchResults = value;
        }

        $scope.search = function() {
            $scope.resetSearch();

            SearchService.Search($scope.search_expression, {'services': ['UserService', 'NewsService'], 'length': '2', 'offset': '0'}).then(function(response) {
                if (response.success === true && response.data.length > 0) {
                    angular.forEach(response.data, function(res, id) {
                        if (res.success === true) {
                            $scope.results.push(res.data);
                        }
                    });
                }
            });
        }

        $scope.resetSearch = function() {
            $scope.results = [];
        }
    }
})();


Add Lunar scene to menu

Add Lunar scene to menu

--- client/react/components/PickYourPoo.js
+++ client/react/components/PickYourPoo.js
@@ -1,10 +1,12 @@
 import React from 'react';
 import DinoScene from '../../aframe/components/DinoScene';
 import WarScene from '../../aframe/components/WarScene';
+import MoonScene from '../../aframe/components/MoonScene';

 const pooScenes = {
   war: WarScene,
   dino: DinoScene,
+  moon: MoonScene,
 }

 class PickYourPoo extends React.Component {
@@ -31,6 +33,7 @@

 this.loadPoo('war')}>World War Two

 this.loadPoo('dino')}>Prehistoric Poo

+
 this.loadPoo('moon')}>Lunar Poo

       );

<|original_code|>
import React from 'react';
import DinoScene from '../../aframe/components/DinoScene';
import WarScene from '../../aframe/components/WarScene';

const pooScenes = {
  war: WarScene,
  dino: DinoScene,
}

class PickYourPoo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  loadPoo(poo) {
    this.setState({ scene: pooScenes[poo] });
  }

  render () {
    if (this.state.scene) {
      return <this.state.scene />;
    } else {
      return (

PoopVR

Pick your Poo!

 this.loadPoo('war')}>World War Two

 this.loadPoo('dino')}>Prehistoric Poo

      );
    }
  }
};

module.exports = PickYourPoo;

<|edits_diff|>
--- client/react/components/PickYourPoo.js
+++ client/react/components/PickYourPoo.js
@@ -1,10 +1,12 @@
 import React from 'react';
 import DinoScene from '../../aframe/components/DinoScene';
 import WarScene from '../../aframe/components/WarScene';
+import MoonScene from '../../aframe/components/MoonScene';

 const pooScenes = {
   war: WarScene,
   dino: DinoScene,
+  moon: MoonScene,
 }

 class PickYourPoo extends React.Component {
<|current_version|>
import React from 'react';
import DinoScene from '../../aframe/components/DinoScene';
import WarScene from '../../aframe/components/WarScene';
import MoonScene from '../../aframe/components/MoonScene';

const pooScenes = {
  war: WarScene,
  dino: DinoScene,
  moon: MoonScene,
}

class PickYourPoo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  loadPoo(poo) {
    this.setState({ scene: pooScenes[poo] });
  }

  render () {
    if (this.state.scene) {
      return <this.state.scene />;
    } else {
      return (

PoopVR

Pick your Poo!

 this.loadPoo('war')}>World War Two

 this.loadPoo('dino')}>Prehistoric Poo

      );
    }
  }
};

module.exports = PickYourPoo;

<|next_version|>
import React from 'react';
import DinoScene from '../../aframe/components/DinoScene';
import WarScene from '../../aframe/components/WarScene';
import MoonScene from '../../aframe/components/MoonScene';

const pooScenes = {
  war: WarScene,
  dino: DinoScene,
  moon: MoonScene,
}

class PickYourPoo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  loadPoo(poo) {
    this.setState({ scene: pooScenes[poo] });
  }

  render () {
    if (this.state.scene) {
      return <this.state.scene />;
    } else {
      return (

PoopVR

Pick your Poo!

 this.loadPoo('war')}>World War Two

 this.loadPoo('dino')}>Prehistoric Poo

 this.loadPoo('moon')}>Lunar Poo

      );
    }
  }
};

module.exports = PickYourPoo;


Add unit tests for date formats

Add unit tests for date formats

--- test/helpers.spec.js
+++ test/helpers.spec.js
@@ -14,14 +14,26 @@
             expect(helpers.formatMMMMYYYY).to.be.a('function');
         });

+        it('should format dates with "MMMMYYYY"', () => {
+            expect(helpers.formatMMMMYYYY('2015-07-01').string).to.equal('July 2015');
+        });
+
         it('should expose a "MMMDDYYYY" format', () => {
             expect(helpers.formatMMMDDYYYY).to.exist;
             expect(helpers.formatMMMDDYYYY).to.be.a('function');
+        });
+
+        it('should format dates with "MMMDDYYYY"', () => {
+            expect(helpers.formatMMMDDYYYY('2015-07-01').string).to.equal('Jul 01, 2015');
         });

         it('should expose a "YYYY" format', () => {
             expect(helpers.formatYYYY).to.exist;
             expect(helpers.formatYYYY).to.be.a('function');
         });
+
+        it('should format dates with "YYYY"', () => {
+            expect(helpers.formatYYYY('2015-07-01').string).to.equal('2015');
+        });
     });
 });

<|original_code|>
import { describe, it } from 'mocha';
import { expect } from 'chai';
import helpers from '../lib/helpers';

describe('Helpers', () => {
    it('should be an object', () => {
        expect(helpers).to.exist;
        expect(helpers).to.be.an('object');
    });

    describe('format', () => {
        it('should expose a "MMMMYYYY" format', () => {
            expect(helpers.formatMMMMYYYY).to.exist;
            expect(helpers.formatMMMMYYYY).to.be.a('function');
        });

        it('should expose a "MMMDDYYYY" format', () => {
            expect(helpers.formatMMMDDYYYY).to.exist;
            expect(helpers.formatMMMDDYYYY).to.be.a('function');
        });

        it('should expose a "YYYY" format', () => {
            expect(helpers.formatYYYY).to.exist;
            expect(helpers.formatYYYY).to.be.a('function');
        });
    });
});

<|edits_diff|>
--- test/helpers.spec.js
+++ test/helpers.spec.js
@@ -14,9 +14,17 @@
             expect(helpers.formatMMMMYYYY).to.be.a('function');
         });

+        it('should format dates with "MMMMYYYY"', () => {
+            expect(helpers.formatMMMMYYYY('2015-07-01').string).to.equal('July 2015');
+        });
+
         it('should expose a "MMMDDYYYY" format', () => {
             expect(helpers.formatMMMDDYYYY).to.exist;
             expect(helpers.formatMMMDDYYYY).to.be.a('function');
+        });
+
+        it('should format dates with "MMMDDYYYY"', () => {
+            expect(helpers.formatMMMDDYYYY('2015-07-01').string).to.equal('Jul 01, 2015');
         });

         it('should expose a "YYYY" format', () => {
<|current_version|>
import { describe, it } from 'mocha';
import { expect } from 'chai';
import helpers from '../lib/helpers';

describe('Helpers', () => {
    it('should be an object', () => {
        expect(helpers).to.exist;
        expect(helpers).to.be.an('object');
    });

    describe('format', () => {
        it('should expose a "MMMMYYYY" format', () => {
            expect(helpers.formatMMMMYYYY).to.exist;
            expect(helpers.formatMMMMYYYY).to.be.a('function');
        });

        it('should format dates with "MMMMYYYY"', () => {
            expect(helpers.formatMMMMYYYY('2015-07-01').string).to.equal('July 2015');
        });

        it('should expose a "MMMDDYYYY" format', () => {
            expect(helpers.formatMMMDDYYYY).to.exist;
            expect(helpers.formatMMMDDYYYY).to.be.a('function');
        });

        it('should format dates with "MMMDDYYYY"', () => {
            expect(helpers.formatMMMDDYYYY('2015-07-01').string).to.equal('Jul 01, 2015');
        });

        it('should expose a "YYYY" format', () => {
            expect(helpers.formatYYYY).to.exist;
            expect(helpers.formatYYYY).to.be.a('function');
        });
    });
});

<|next_version|>
import { describe, it } from 'mocha';
import { expect } from 'chai';
import helpers from '../lib/helpers';

describe('Helpers', () => {
    it('should be an object', () => {
        expect(helpers).to.exist;
        expect(helpers).to.be.an('object');
    });

    describe('format', () => {
        it('should expose a "MMMMYYYY" format', () => {
            expect(helpers.formatMMMMYYYY).to.exist;
            expect(helpers.formatMMMMYYYY).to.be.a('function');
        });

        it('should format dates with "MMMMYYYY"', () => {
            expect(helpers.formatMMMMYYYY('2015-07-01').string).to.equal('July 2015');
        });

        it('should expose a "MMMDDYYYY" format', () => {
            expect(helpers.formatMMMDDYYYY).to.exist;
            expect(helpers.formatMMMDDYYYY).to.be.a('function');
        });

        it('should format dates with "MMMDDYYYY"', () => {
            expect(helpers.formatMMMDDYYYY('2015-07-01').string).to.equal('Jul 01, 2015');
        });

        it('should expose a "YYYY" format', () => {
            expect(helpers.formatYYYY).to.exist;
            expect(helpers.formatYYYY).to.be.a('function');
        });

        it('should format dates with "YYYY"', () => {
            expect(helpers.formatYYYY('2015-07-01').string).to.equal('2015');
        });
    });
});


Add comments to main file

Add comments to main file

--- server.js
+++ server.js
@@ -6,12 +6,16 @@
 var app = express();
 var http = require('http').Server(app);

+// Configure DB connection and models
 require('./server/config/mongoose')();

+// Configure app (common middlewares)
 require('./server/config/express')(app);

+// Configure passport authentication methods
 require('./server/config/passport')();

+// Configure routes
 require('./server/config/routes')(app);

 // Log uncaught errors

<|original_code|>
/// <reference path="typings/node/node.d.ts"/>
// Load environment variables
require('dotenv').load();

var express = require('express');
var app = express();
var http = require('http').Server(app);

require('./server/config/mongoose')();

require('./server/config/express')(app);

require('./server/config/passport')();

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

// Log uncaught errors
process.on('uncaughtException', function(err) {
  console.log('UNCAUGHT EXCEPTION : ' + err.stack);
});

// Start app
http.listen(process.env.PORT);
console.log('Application started and listening to ' + process.env.PORT + '...');

<|edits_diff|>
--- server.js
+++ server.js
@@ -6,10 +6,13 @@
 var app = express();
 var http = require('http').Server(app);

+// Configure DB connection and models
 require('./server/config/mongoose')();

+// Configure app (common middlewares)
 require('./server/config/express')(app);

+// Configure passport authentication methods
 require('./server/config/passport')();

 require('./server/config/routes')(app);
<|current_version|>
/// <reference path="typings/node/node.d.ts"/>
// Load environment variables
require('dotenv').load();

var express = require('express');
var app = express();
var http = require('http').Server(app);

// Configure DB connection and models
require('./server/config/mongoose')();

// Configure app (common middlewares)
require('./server/config/express')(app);

// Configure passport authentication methods
require('./server/config/passport')();

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

// Log uncaught errors
process.on('uncaughtException', function(err) {
  console.log('UNCAUGHT EXCEPTION : ' + err.stack);
});

// Start app
http.listen(process.env.PORT);
console.log('Application started and listening to ' + process.env.PORT + '...');

<|next_version|>
/// <reference path="typings/node/node.d.ts"/>
// Load environment variables
require('dotenv').load();

var express = require('express');
var app = express();
var http = require('http').Server(app);

// Configure DB connection and models
require('./server/config/mongoose')();

// Configure app (common middlewares)
require('./server/config/express')(app);

// Configure passport authentication methods
require('./server/config/passport')();

// Configure routes
require('./server/config/routes')(app);

// Log uncaught errors
process.on('uncaughtException', function(err) {
  console.log('UNCAUGHT EXCEPTION : ' + err.stack);
});

// Start app
http.listen(process.env.PORT);
console.log('Application started and listening to ' + process.env.PORT + '...');


Hide the ''load more'' button while loading.

--- app/scripts/masonry.init.js
+++ app/scripts/masonry.init.js
@@ -32,6 +32,7 @@
           // show elems now they're ready
           $newElems.animate({ opacity: 1 });
           $container.masonry( 'appended', $newElems, true );
+          $('#more').show();
         });
       }
     );
@@ -39,6 +40,7 @@
     $(window).unbind('.infscr');

     $("#more").click(function(){
+        $('#more').hide();
         var $container = $('#masonry-container');
         $container.infinitescroll('retrieve');
         return false;

<|original_code|>
'use strict';

// Initiate masonry & infinite scroll on relevant pages
$(function() {

    var $container = $('#masonry-container');

    $container.imagesLoaded(function(){
      $container.masonry({
        itemSelector: '.box',
      });
    });

    $container.infinitescroll({
      navSelector  : '#page-nav',    // selector for the paged navigation
      nextSelector : '#page-nav a',  // selector for the NEXT link (to page 2)
      itemSelector : '.box',     // selector for all items you'll retrieve
      loading: {
          finishedMsg: 'Ikke flere resultater...',
          img: '/images/loading.gif',
          msgText: 'Henter flere resultater...',
          speed: 0,
        },
        animate:false
      },
      // trigger Masonry as a callback
      function( newElements ) {
        // hide new items while they are loading
        var $newElems = $( newElements ).css({ opacity: 0 });
        // ensure that images load before adding to masonry layout
        $newElems.imagesLoaded(function(){
          // show elems now they're ready
          $newElems.animate({ opacity: 1 });
          $container.masonry( 'appended', $newElems, true );
        });
      }
    );

    $(window).unbind('.infscr');

    $("#more").click(function(){
        var $container = $('#masonry-container');
        $container.infinitescroll('retrieve');
        return false;
    });

});

<|edits_diff|>
--- app/scripts/masonry.init.js
+++ app/scripts/masonry.init.js
@@ -32,6 +32,7 @@
           // show elems now they're ready
           $newElems.animate({ opacity: 1 });
           $container.masonry( 'appended', $newElems, true );
+          $('#more').show();
         });
       }
     );
<|current_version|>
'use strict';

// Initiate masonry & infinite scroll on relevant pages
$(function() {

    var $container = $('#masonry-container');

    $container.imagesLoaded(function(){
      $container.masonry({
        itemSelector: '.box',
      });
    });

    $container.infinitescroll({
      navSelector  : '#page-nav',    // selector for the paged navigation
      nextSelector : '#page-nav a',  // selector for the NEXT link (to page 2)
      itemSelector : '.box',     // selector for all items you'll retrieve
      loading: {
          finishedMsg: 'Ikke flere resultater...',
          img: '/images/loading.gif',
          msgText: 'Henter flere resultater...',
          speed: 0,
        },
        animate:false
      },
      // trigger Masonry as a callback
      function( newElements ) {
        // hide new items while they are loading
        var $newElems = $( newElements ).css({ opacity: 0 });
        // ensure that images load before adding to masonry layout
        $newElems.imagesLoaded(function(){
          // show elems now they're ready
          $newElems.animate({ opacity: 1 });
          $container.masonry( 'appended', $newElems, true );
          $('#more').show();
        });
      }
    );

    $(window).unbind('.infscr');

    $("#more").click(function(){
        var $container = $('#masonry-container');
        $container.infinitescroll('retrieve');
        return false;
    });

});

<|next_version|>
'use strict';

// Initiate masonry & infinite scroll on relevant pages
$(function() {

    var $container = $('#masonry-container');

    $container.imagesLoaded(function(){
      $container.masonry({
        itemSelector: '.box',
      });
    });

    $container.infinitescroll({
      navSelector  : '#page-nav',    // selector for the paged navigation
      nextSelector : '#page-nav a',  // selector for the NEXT link (to page 2)
      itemSelector : '.box',     // selector for all items you'll retrieve
      loading: {
          finishedMsg: 'Ikke flere resultater...',
          img: '/images/loading.gif',
          msgText: 'Henter flere resultater...',
          speed: 0,
        },
        animate:false
      },
      // trigger Masonry as a callback
      function( newElements ) {
        // hide new items while they are loading
        var $newElems = $( newElements ).css({ opacity: 0 });
        // ensure that images load before adding to masonry layout
        $newElems.imagesLoaded(function(){
          // show elems now they're ready
          $newElems.animate({ opacity: 1 });
          $container.masonry( 'appended', $newElems, true );
          $('#more').show();
        });
      }
    );

    $(window).unbind('.infscr');

    $("#more").click(function(){
        $('#more').hide();
        var $container = $('#masonry-container');
        $container.infinitescroll('retrieve');
        return false;
    });

});


Make sure template paths are resolved

Make sure template paths are resolved

--- runtime/lib/loader.js
+++ runtime/lib/loader.js
@@ -2,6 +2,7 @@
 var fs = require('fs');
 var Module = require('module').Module;
 var raptorTemplatesCompiler = require('../../compiler');
+var cwd = process.cwd();

 function loadSource(templatePath, compiledSrc) {
     var templateModulePath = templatePath + '.js';
@@ -19,6 +20,8 @@
 }

 module.exports = function load(templatePath) {
+    templatePath = nodePath.resolve(cwd, templatePath);
+
     var targetFile = templatePath + '.js';
     var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
     var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);

<|original_code|>
var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var raptorTemplatesCompiler = require('../../compiler');

function loadSource(templatePath, compiledSrc) {
    var templateModulePath = templatePath + '.js';

    var templateModule = new Module(templateModulePath, module);
    templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
    templateModule.filename = templateModulePath;

    templateModule._compile(
        compiledSrc,
        templateModulePath);

    return templateModule.exports;
}

module.exports = function load(templatePath) {
    var targetFile = templatePath + '.js';
    var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
    var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);
    if (isUpToDate) {
        return require(targetFile);
    }

	var templateSrc = fs.readFileSync(templatePath, {encoding: 'utf8'});
	var compiledSrc = compiler.compile(templateSrc);

    // console.log('Compiled code for "' + templatePath + '":\n' + compiledSrc);

    fs.writeFileSync(targetFile, compiledSrc, {encoding: 'utf8'});

    return require(targetFile);
};

module.exports.loadSource = loadSource;
<|edits_diff|>
--- runtime/lib/loader.js
+++ runtime/lib/loader.js
@@ -2,6 +2,7 @@
 var fs = require('fs');
 var Module = require('module').Module;
 var raptorTemplatesCompiler = require('../../compiler');
+var cwd = process.cwd();

 function loadSource(templatePath, compiledSrc) {
     var templateModulePath = templatePath + '.js';
<|current_version|>
var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var raptorTemplatesCompiler = require('../../compiler');
var cwd = process.cwd();

function loadSource(templatePath, compiledSrc) {
    var templateModulePath = templatePath + '.js';

    var templateModule = new Module(templateModulePath, module);
    templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
    templateModule.filename = templateModulePath;

    templateModule._compile(
        compiledSrc,
        templateModulePath);

    return templateModule.exports;
}

module.exports = function load(templatePath) {
    var targetFile = templatePath + '.js';
    var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
    var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);
    if (isUpToDate) {
        return require(targetFile);
    }

	var templateSrc = fs.readFileSync(templatePath, {encoding: 'utf8'});
	var compiledSrc = compiler.compile(templateSrc);

    // console.log('Compiled code for "' + templatePath + '":\n' + compiledSrc);

    fs.writeFileSync(targetFile, compiledSrc, {encoding: 'utf8'});

    return require(targetFile);
};

module.exports.loadSource = loadSource;
<|next_version|>
var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var raptorTemplatesCompiler = require('../../compiler');
var cwd = process.cwd();

function loadSource(templatePath, compiledSrc) {
    var templateModulePath = templatePath + '.js';

    var templateModule = new Module(templateModulePath, module);
    templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
    templateModule.filename = templateModulePath;

    templateModule._compile(
        compiledSrc,
        templateModulePath);

    return templateModule.exports;
}

module.exports = function load(templatePath) {
    templatePath = nodePath.resolve(cwd, templatePath);

    var targetFile = templatePath + '.js';
    var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
    var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);
    if (isUpToDate) {
        return require(targetFile);
    }

	var templateSrc = fs.readFileSync(templatePath, {encoding: 'utf8'});
	var compiledSrc = compiler.compile(templateSrc);

    // console.log('Compiled code for "' + templatePath + '":\n' + compiledSrc);

    fs.writeFileSync(targetFile, compiledSrc, {encoding: 'utf8'});

    return require(targetFile);
};

module.exports.loadSource = loadSource;


Add more prefer event listeners to observe compose window creating/deleting

--- content/messengercompose-overlay.js
+++ content/messengercompose-overlay.js
@@ -8,9 +8,13 @@
     init: function() {
       window.removeEventListener('load', this, false);
       window.addEventListener('unload', this, false);
+      document.documentElement.addEventListener('compose-window-init', this, false);
+      document.documentElement.addEventListener('compose-window-close', this, false);
     },
     destroy: function() {
       window.removeEventListener('unload', this, false);
+      document.documentElement.removeEventListener('compose-window-init', this, false);
+      document.documentElement.removeEventListener('compose-window-close', this, false);
     },

     handleEvent: function(aEvent) {

<|original_code|>
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

(function (aGlobal) {

  var tbBug766495 = {
    init: function() {
      window.removeEventListener('load', this, false);
      window.addEventListener('unload', this, false);
    },
    destroy: function() {
      window.removeEventListener('unload', this, false);
    },

    handleEvent: function(aEvent) {
      switch (aEvent.type) {
      case 'load':
        this.init();
        return;

      case 'unload':
        this.destroy();
        return;
      }
    }
  };
  window.addEventListener('load', tbBug766495, false);
  aGlobal.tbBug766495 = tbBug766495;
})(this);

<|edits_diff|>
--- content/messengercompose-overlay.js
+++ content/messengercompose-overlay.js
@@ -8,6 +8,8 @@
     init: function() {
       window.removeEventListener('load', this, false);
       window.addEventListener('unload', this, false);
+      document.documentElement.addEventListener('compose-window-init', this, false);
+      document.documentElement.addEventListener('compose-window-close', this, false);
     },
     destroy: function() {
       window.removeEventListener('unload', this, false);
<|current_version|>
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

(function (aGlobal) {

  var tbBug766495 = {
    init: function() {
      window.removeEventListener('load', this, false);
      window.addEventListener('unload', this, false);
      document.documentElement.addEventListener('compose-window-init', this, false);
      document.documentElement.addEventListener('compose-window-close', this, false);
    },
    destroy: function() {
      window.removeEventListener('unload', this, false);
    },

    handleEvent: function(aEvent) {
      switch (aEvent.type) {
      case 'load':
        this.init();
        return;

      case 'unload':
        this.destroy();
        return;
      }
    }
  };
  window.addEventListener('load', tbBug766495, false);
  aGlobal.tbBug766495 = tbBug766495;
})(this);

<|next_version|>
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

(function (aGlobal) {

  var tbBug766495 = {
    init: function() {
      window.removeEventListener('load', this, false);
      window.addEventListener('unload', this, false);
      document.documentElement.addEventListener('compose-window-init', this, false);
      document.documentElement.addEventListener('compose-window-close', this, false);
    },
    destroy: function() {
      window.removeEventListener('unload', this, false);
      document.documentElement.removeEventListener('compose-window-init', this, false);
      document.documentElement.removeEventListener('compose-window-close', this, false);
    },

    handleEvent: function(aEvent) {
      switch (aEvent.type) {
      case 'load':
        this.init();
        return;

      case 'unload':
        this.destroy();
        return;
      }
    }
  };
  window.addEventListener('load', tbBug766495, false);
  aGlobal.tbBug766495 = tbBug766495;
})(this);


Add "parent" field to track topic ids

Add "parent" field to track topic ids

--- models/nntp/Article.js
+++ models/nntp/Article.js
@@ -12,6 +12,7 @@

   let Article = new Schema({
     source:  Schema.ObjectId,
+    parent:  Schema.ObjectId,
     group:   Schema.ObjectId,
     index:   Number
   }, {
@@ -24,6 +25,9 @@

   // find an article by message_id (ARTICLE command)
   Article.index({ source: 1 });
+
+  // mass-removal of messages
+  Article.index({ parent: 1 });

   // get range of articles inside a group
   Article.index({ group: 1, index: 1 });

<|original_code|>
// NNTP article
//

'use strict';

const Mongoose = require('mongoose');
const Schema   = Mongoose.Schema;

module.exports = function (N, collectionName) {

  let Article = new Schema({
    source:  Schema.ObjectId,
    group:   Schema.ObjectId,
    index:   Number
  }, {
    versionKey: false
  });

  // Indexes
  //////////////////////////////////////////////////////////////////////////////

  // find an article by message_id (ARTICLE command)
  Article.index({ source: 1 });

  // get range of articles inside a group
  Article.index({ group: 1, index: 1 });

  N.wire.on('init:models', function emit_init_Article() {
    return N.wire.emit('init:models.' + collectionName, Article);
  });

  N.wire.on('init:models.' + collectionName, function init_model_Article(schema) {
    N.models[collectionName] = Mongoose.model(collectionName, schema);
  });
};

<|edits_diff|>
--- models/nntp/Article.js
+++ models/nntp/Article.js
@@ -12,6 +12,7 @@

   let Article = new Schema({
     source:  Schema.ObjectId,
+    parent:  Schema.ObjectId,
     group:   Schema.ObjectId,
     index:   Number
   }, {
<|current_version|>
// NNTP article
//

'use strict';

const Mongoose = require('mongoose');
const Schema   = Mongoose.Schema;

module.exports = function (N, collectionName) {

  let Article = new Schema({
    source:  Schema.ObjectId,
    parent:  Schema.ObjectId,
    group:   Schema.ObjectId,
    index:   Number
  }, {
    versionKey: false
  });

  // Indexes
  //////////////////////////////////////////////////////////////////////////////

  // find an article by message_id (ARTICLE command)
  Article.index({ source: 1 });

  // get range of articles inside a group
  Article.index({ group: 1, index: 1 });

  N.wire.on('init:models', function emit_init_Article() {
    return N.wire.emit('init:models.' + collectionName, Article);
  });

  N.wire.on('init:models.' + collectionName, function init_model_Article(schema) {
    N.models[collectionName] = Mongoose.model(collectionName, schema);
  });
};

<|next_version|>
// NNTP article
//

'use strict';

const Mongoose = require('mongoose');
const Schema   = Mongoose.Schema;

module.exports = function (N, collectionName) {

  let Article = new Schema({
    source:  Schema.ObjectId,
    parent:  Schema.ObjectId,
    group:   Schema.ObjectId,
    index:   Number
  }, {
    versionKey: false
  });

  // Indexes
  //////////////////////////////////////////////////////////////////////////////

  // find an article by message_id (ARTICLE command)
  Article.index({ source: 1 });

  // mass-removal of messages
  Article.index({ parent: 1 });

  // get range of articles inside a group
  Article.index({ group: 1, index: 1 });

  N.wire.on('init:models', function emit_init_Article() {
    return N.wire.emit('init:models.' + collectionName, Article);
  });

  N.wire.on('init:models.' + collectionName, function init_model_Article(schema) {
    N.models[collectionName] = Mongoose.model(collectionName, schema);
  });
};


Add a couple more logs for Travis debugging

--- src/models/GitHubAuth.js
+++ src/models/GitHubAuth.js
@@ -11,6 +11,7 @@
   }

   static setToken(token) {
+    console.log('setToken', token)
     if (this.isAuthenticated()) {
       this.deleteToken()
     }
@@ -22,6 +23,7 @@
   }

   static getToken() {
+    console.log('getToken', keytar.getPassword(SERVICE, ACCOUNT))
     return keytar.getPassword(SERVICE, ACCOUNT)
   }
 }

<|original_code|>
'use strict'

import keytar from 'keytar'

const SERVICE = 'gh-notifications-snoozer'
const ACCOUNT = process.env.NODE_ENV === 'test' ? 'github-test' : 'github'

class GitHubAuth {
  static isAuthenticated() {
    return this.getToken() !== null
  }

  static setToken(token) {
    if (this.isAuthenticated()) {
      this.deleteToken()
    }
    keytar.addPassword(SERVICE, ACCOUNT, token)
  }

  static deleteToken() {
    keytar.deletePassword(SERVICE, ACCOUNT)
  }

  static getToken() {
    return keytar.getPassword(SERVICE, ACCOUNT)
  }
}

module.exports = GitHubAuth

<|edits_diff|>
--- src/models/GitHubAuth.js
+++ src/models/GitHubAuth.js
@@ -11,6 +11,7 @@
   }

   static setToken(token) {
+    console.log('setToken', token)
     if (this.isAuthenticated()) {
       this.deleteToken()
     }
<|current_version|>
'use strict'

import keytar from 'keytar'

const SERVICE = 'gh-notifications-snoozer'
const ACCOUNT = process.env.NODE_ENV === 'test' ? 'github-test' : 'github'

class GitHubAuth {
  static isAuthenticated() {
    return this.getToken() !== null
  }

  static setToken(token) {
    console.log('setToken', token)
    if (this.isAuthenticated()) {
      this.deleteToken()
    }
    keytar.addPassword(SERVICE, ACCOUNT, token)
  }

  static deleteToken() {
    keytar.deletePassword(SERVICE, ACCOUNT)
  }

  static getToken() {
    return keytar.getPassword(SERVICE, ACCOUNT)
  }
}

module.exports = GitHubAuth

<|next_version|>
'use strict'

import keytar from 'keytar'

const SERVICE = 'gh-notifications-snoozer'
const ACCOUNT = process.env.NODE_ENV === 'test' ? 'github-test' : 'github'

class GitHubAuth {
  static isAuthenticated() {
    return this.getToken() !== null
  }

  static setToken(token) {
    console.log('setToken', token)
    if (this.isAuthenticated()) {
      this.deleteToken()
    }
    keytar.addPassword(SERVICE, ACCOUNT, token)
  }

  static deleteToken() {
    keytar.deletePassword(SERVICE, ACCOUNT)
  }

  static getToken() {
    console.log('getToken', keytar.getPassword(SERVICE, ACCOUNT))
    return keytar.getPassword(SERVICE, ACCOUNT)
  }
}

module.exports = GitHubAuth


Add name to remote config.

Add name to remote config.

--- src/scenario/driver.js
+++ src/scenario/driver.js
@@ -1,3 +1,4 @@
+var _ = require('lodash');
 var wd = require('wd');
 var TestCase = require('./testCase');
 var Driver = require('../driver');
@@ -14,6 +15,7 @@
         this.doRun(browser, remote, desired);
     },
     createBrowser: function (remote, desired, done) {
+        desired = _.defaults({name: this.name}, desired);
         var browser = new Driver(remote, desired, done);
         return browser;
     },

<|original_code|>
var wd = require('wd');
var TestCase = require('./testCase');
var Driver = require('../driver');

var WDTestCase = TestCase.extend({
    constructor: function () {
        TestCase.apply(this, arguments);
    },
    // timeout for raw wd methods (ms)
    // raw methods are the _ ones.
    timeout: 10000,
    run: function (remote, desired, done) {
        var browser = this.createBrowser(remote, desired, done);
        this.doRun(browser, remote, desired);
    },
    createBrowser: function (remote, desired, done) {
        var browser = new Driver(remote, desired, done);
        return browser;
    },
    doRun: function (browser, remote, desired) {
        console.log('please define steps');
    }
});

module.exports = WDTestCase;

<|edits_diff|>
--- src/scenario/driver.js
+++ src/scenario/driver.js
@@ -1,3 +1,4 @@
+var _ = require('lodash');
 var wd = require('wd');
 var TestCase = require('./testCase');
 var Driver = require('../driver');
<|current_version|>
var _ = require('lodash');
var wd = require('wd');
var TestCase = require('./testCase');
var Driver = require('../driver');

var WDTestCase = TestCase.extend({
    constructor: function () {
        TestCase.apply(this, arguments);
    },
    // timeout for raw wd methods (ms)
    // raw methods are the _ ones.
    timeout: 10000,
    run: function (remote, desired, done) {
        var browser = this.createBrowser(remote, desired, done);
        this.doRun(browser, remote, desired);
    },
    createBrowser: function (remote, desired, done) {
        var browser = new Driver(remote, desired, done);
        return browser;
    },
    doRun: function (browser, remote, desired) {
        console.log('please define steps');
    }
});

module.exports = WDTestCase;

<|next_version|>
var _ = require('lodash');
var wd = require('wd');
var TestCase = require('./testCase');
var Driver = require('../driver');

var WDTestCase = TestCase.extend({
    constructor: function () {
        TestCase.apply(this, arguments);
    },
    // timeout for raw wd methods (ms)
    // raw methods are the _ ones.
    timeout: 10000,
    run: function (remote, desired, done) {
        var browser = this.createBrowser(remote, desired, done);
        this.doRun(browser, remote, desired);
    },
    createBrowser: function (remote, desired, done) {
        desired = _.defaults({name: this.name}, desired);
        var browser = new Driver(remote, desired, done);
        return browser;
    },
    doRun: function (browser, remote, desired) {
        console.log('please define steps');
    }
});

module.exports = WDTestCase;


Fix bug in FirebaseUI for when Firebase is an AMD module

--- addon/components/firebase-ui-auth.js
+++ addon/components/firebase-ui-auth.js
@@ -4,6 +4,7 @@
 import inject from 'ember-service/inject';

 import FirebaseUi from 'firebaseui';
+import firebase from 'firebase';

 import layout from '../templates/components/firebase-ui-auth';

@@ -47,6 +48,9 @@
     this._super(...arguments);

     scheduleOnce('afterRender', () => {
+      // Workaround for when the firebase asset is an AMD module
+      window.firebase = firebase;
+
       let auth = this.get('firebaseApp').auth();
       let ui = new FirebaseUi.auth.AuthUI(auth);

<|original_code|>
/** @module emberfire-utils */
import { scheduleOnce } from 'ember-runloop';
import Component from 'ember-component';
import inject from 'ember-service/inject';

import FirebaseUi from 'firebaseui';

import layout from '../templates/components/firebase-ui-auth';

/**
 * `<firebase-ui-auth>`
 *
 * API Reference:
 *   * `@uiConfig` - Object
 *
 * @class FirebaseUiAuth
 * @namespace Component
 * @extends Ember.Component
 */
export default Component.extend({
  layout,

  /**
   * @type Ember.Service
   * @readOnly
   */
  firebaseApp: inject(),

  /**
   * @type {string}
   * @readonly
   */
  elementId: 'firebaseui-auth-container',

  /**
   * @type {FirebaseUi}
   * @default
   */
  ui: null,

  /**
   * Component hook.
   *
   * - Renders the FirebaseUI auth widget
   */
  didInsertElement() {
    this._super(...arguments);

    scheduleOnce('afterRender', () => {
      let auth = this.get('firebaseApp').auth();
      let ui = new FirebaseUi.auth.AuthUI(auth);

      ui.start('#firebaseui-auth-container', this.getAttr('uiConfig'));
      this.set('ui', ui);
    });
  },

  /**
   * Component hook.
   *
   * - Dispose the FirebaseUI auth widget
   */
  willDestroyElement() {
    this._super(...arguments);

    this.get('ui').reset();
  },
});

<|edits_diff|>
--- addon/components/firebase-ui-auth.js
+++ addon/components/firebase-ui-auth.js
@@ -4,6 +4,7 @@
 import inject from 'ember-service/inject';

 import FirebaseUi from 'firebaseui';
+import firebase from 'firebase';

 import layout from '../templates/components/firebase-ui-auth';

<|current_version|>
/** @module emberfire-utils */
import { scheduleOnce } from 'ember-runloop';
import Component from 'ember-component';
import inject from 'ember-service/inject';

import FirebaseUi from 'firebaseui';
import firebase from 'firebase';

import layout from '../templates/components/firebase-ui-auth';

/**
 * `<firebase-ui-auth>`
 *
 * API Reference:
 *   * `@uiConfig` - Object
 *
 * @class FirebaseUiAuth
 * @namespace Component
 * @extends Ember.Component
 */
export default Component.extend({
  layout,

  /**
   * @type Ember.Service
   * @readOnly
   */
  firebaseApp: inject(),

  /**
   * @type {string}
   * @readonly
   */
  elementId: 'firebaseui-auth-container',

  /**
   * @type {FirebaseUi}
   * @default
   */
  ui: null,

  /**
   * Component hook.
   *
   * - Renders the FirebaseUI auth widget
   */
  didInsertElement() {
    this._super(...arguments);

    scheduleOnce('afterRender', () => {
      let auth = this.get('firebaseApp').auth();
      let ui = new FirebaseUi.auth.AuthUI(auth);

      ui.start('#firebaseui-auth-container', this.getAttr('uiConfig'));
      this.set('ui', ui);
    });
  },

  /**
   * Component hook.
   *
   * - Dispose the FirebaseUI auth widget
   */
  willDestroyElement() {
    this._super(...arguments);

    this.get('ui').reset();
  },
});

<|next_version|>
/** @module emberfire-utils */
import { scheduleOnce } from 'ember-runloop';
import Component from 'ember-component';
import inject from 'ember-service/inject';

import FirebaseUi from 'firebaseui';
import firebase from 'firebase';

import layout from '../templates/components/firebase-ui-auth';

/**
 * `<firebase-ui-auth>`
 *
 * API Reference:
 *   * `@uiConfig` - Object
 *
 * @class FirebaseUiAuth
 * @namespace Component
 * @extends Ember.Component
 */
export default Component.extend({
  layout,

  /**
   * @type Ember.Service
   * @readOnly
   */
  firebaseApp: inject(),

  /**
   * @type {string}
   * @readonly
   */
  elementId: 'firebaseui-auth-container',

  /**
   * @type {FirebaseUi}
   * @default
   */
  ui: null,

  /**
   * Component hook.
   *
   * - Renders the FirebaseUI auth widget
   */
  didInsertElement() {
    this._super(...arguments);

    scheduleOnce('afterRender', () => {
      // Workaround for when the firebase asset is an AMD module
      window.firebase = firebase;

      let auth = this.get('firebaseApp').auth();
      let ui = new FirebaseUi.auth.AuthUI(auth);

      ui.start('#firebaseui-auth-container', this.getAttr('uiConfig'));
      this.set('ui', ui);
    });
  },

  /**
   * Component hook.
   *
   * - Dispose the FirebaseUI auth widget
   */
  willDestroyElement() {
    this._super(...arguments);

    this.get('ui').reset();
  },
});


Add additional test for lPartial

Add additional test for lPartial

--- test/eigensheep/l_partial_test.js
+++ test/eigensheep/l_partial_test.js
@@ -3,9 +3,17 @@

   var lPartial = require('eigensheep/l_partial')['default'];
   var multiply = function(a, b) { return a * b; };
+  var greet = function(salutation, title, firstName, lastName) {
+    return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+  };

   test("creates a partially-applied version of an existing function", function() {
     var double = lPartial(multiply, 2);
     equal(double(5), 10);
   });
+
+  test("creates a partially-left-applied version of an existing function", function() {
+    var greetSir = lPartial(greet, 'Hello', 'Sir');
+    equal(greetSir('Bob', 'Robertson'), 'Hello, Sir Bob Robertson!');
+  });
 })();

<|original_code|>
(function() {
  module("R.lPartial");

  var lPartial = require('eigensheep/l_partial')['default'];
  var multiply = function(a, b) { return a * b; };

  test("creates a partially-applied version of an existing function", function() {
    var double = lPartial(multiply, 2);
    equal(double(5), 10);
  });
})();

<|edits_diff|>
--- test/eigensheep/l_partial_test.js
+++ test/eigensheep/l_partial_test.js
@@ -3,6 +3,9 @@

   var lPartial = require('eigensheep/l_partial')['default'];
   var multiply = function(a, b) { return a * b; };
+  var greet = function(salutation, title, firstName, lastName) {
+    return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
+  };

   test("creates a partially-applied version of an existing function", function() {
     var double = lPartial(multiply, 2);
<|current_version|>
(function() {
  module("R.lPartial");

  var lPartial = require('eigensheep/l_partial')['default'];
  var multiply = function(a, b) { return a * b; };
  var greet = function(salutation, title, firstName, lastName) {
    return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
  };

  test("creates a partially-applied version of an existing function", function() {
    var double = lPartial(multiply, 2);
    equal(double(5), 10);
  });
})();

<|next_version|>
(function() {
  module("R.lPartial");

  var lPartial = require('eigensheep/l_partial')['default'];
  var multiply = function(a, b) { return a * b; };
  var greet = function(salutation, title, firstName, lastName) {
    return salutation + ', ' + title + ' ' + firstName + ' ' + lastName + '!';
  };

  test("creates a partially-applied version of an existing function", function() {
    var double = lPartial(multiply, 2);
    equal(double(5), 10);
  });

  test("creates a partially-left-applied version of an existing function", function() {
    var greetSir = lPartial(greet, 'Hello', 'Sir');
    equal(greetSir('Bob', 'Robertson'), 'Hello, Sir Bob Robertson!');
  });
})();


Allow ENV "PORT" to override listen port

--- config/webpack.config.devserver.js
+++ config/webpack.config.devserver.js
@@ -1,5 +1,9 @@
 const path = require('path');
 const webpack = require('webpack');
+
+// Listen port
+const PORT = process.env.PORT || 8080;
+

 // Load base config
 const baseConfig = require('./webpack.config.base');
@@ -10,6 +14,9 @@
 config.devtool = 'cheap-source-map';

 config.devServer = {
+    hot: true,
+    host: "0.0.0.0",
+    port: PORT,
     contentBase: path.resolve(__dirname, '../src'),
     watchContentBase: true
 };

<|original_code|>
const path = require('path');
const webpack = require('webpack');

// Load base config
const baseConfig = require('./webpack.config.base');

// Create the config
const config = Object.create(baseConfig);

config.devtool = 'cheap-source-map';

config.devServer = {
    contentBase: path.resolve(__dirname, '../src'),
    watchContentBase: true
};

module.exports = config;

<|edits_diff|>
--- config/webpack.config.devserver.js
+++ config/webpack.config.devserver.js
@@ -1,5 +1,9 @@
 const path = require('path');
 const webpack = require('webpack');
+
+// Listen port
+const PORT = process.env.PORT || 8080;
+

 // Load base config
 const baseConfig = require('./webpack.config.base');
<|current_version|>
const path = require('path');
const webpack = require('webpack');

// Listen port
const PORT = process.env.PORT || 8080;

// Load base config
const baseConfig = require('./webpack.config.base');

// Create the config
const config = Object.create(baseConfig);

config.devtool = 'cheap-source-map';

config.devServer = {
    contentBase: path.resolve(__dirname, '../src'),
    watchContentBase: true
};

module.exports = config;

<|next_version|>
const path = require('path');
const webpack = require('webpack');

// Listen port
const PORT = process.env.PORT || 8080;

// Load base config
const baseConfig = require('./webpack.config.base');

// Create the config
const config = Object.create(baseConfig);

config.devtool = 'cheap-source-map';

config.devServer = {
    hot: true,
    host: "0.0.0.0",
    port: PORT,
    contentBase: path.resolve(__dirname, '../src'),
    watchContentBase: true
};

module.exports = config;


Update app factory to return a Koa application.

--- src/index.js
+++ src/index.js
@@ -1,6 +1,7 @@
 /**
  * External imports
  */
+import koa from 'koa';
 import libdebug from 'debug';

 // create debug logger
@@ -8,4 +9,6 @@

 export default function create(options = {}) {
   debug('options %j', options);
+
+  return koa();
 }

<|original_code|>
/**
 * External imports
 */
import libdebug from 'debug';

// create debug logger
const debug = libdebug('lgho:root');

export default function create(options = {}) {
  debug('options %j', options);
}

<|edits_diff|>
--- src/index.js
+++ src/index.js
@@ -1,6 +1,7 @@
 /**
  * External imports
  */
+import koa from 'koa';
 import libdebug from 'debug';

 // create debug logger
<|current_version|>
/**
 * External imports
 */
import koa from 'koa';
import libdebug from 'debug';

// create debug logger
const debug = libdebug('lgho:root');

export default function create(options = {}) {
  debug('options %j', options);
}

<|next_version|>
/**
 * External imports
 */
import koa from 'koa';
import libdebug from 'debug';

// create debug logger
const debug = libdebug('lgho:root');

export default function create(options = {}) {
  debug('options %j', options);

  return koa();
}


Fix marked compatibility on API Doc

Fix marked compatibility on API Doc

--- js/apidoc.js
+++ js/apidoc.js
@@ -4,6 +4,7 @@
 import '../less/udata/swagger.less';

 import $ from 'expose?$!expose?jQuery!jquery';
+import commonmark from 'helpers/commonmark';
 import hljs from 'highlight.js';
 import log from 'logger';

@@ -19,6 +20,10 @@

 import 'script!swaggerui/swagger-ui.min';
 SwaggerUi = window.SwaggerUi;
+
+// Marked compatibility for SwaggerUI
+window.marked = commonmark;
+marked.setOptions = function() {};

 $(function() {
     hljs.initHighlightingOnLoad();

<|original_code|>
/**
 * Display a SwaggerUI documentation
 */
import '../less/udata/swagger.less';

import $ from 'expose?$!expose?jQuery!jquery';
import hljs from 'highlight.js';
import log from 'logger';

// Required jQuery plugins
import 'jquery.browser';
import 'swaggerui/lib/jquery.slideto.min';
import 'swaggerui/lib/jquery.wiggle.min';
import 'script!swaggerui/lib/jquery.ba-bbq.min';

import 'expose?Handlebars!handlebars';
import 'script!swaggerui/lib/underscore-min';
import 'script!swaggerui/lib/backbone-min';

import 'script!swaggerui/swagger-ui.min';
SwaggerUi = window.SwaggerUi;

$(function() {
    hljs.initHighlightingOnLoad();
    $('pre code').each(function(i, e) {
        hljs.highlightBlock(e);
    });

    const swaggerUi = new SwaggerUi({
        url: $('meta[name="swagger-specs"]').attr('content'),
        dom_id: 'swagger-ui-container',
        supportedSubmitMethods: ['get'],
        onComplete: function(swaggerApi, swaggerUi) {
            log.debug('Loaded SwaggerUI');

            $('#swagger-ui-container pre code').each(function(i, e) {
                hljs.highlightBlock(e);
            });
        },
        onFailure: function() {
            log.error('Unable to Load SwaggerUI');
        },
        docExpansion: 'none',
        sorter: 'alpha'
    });

    swaggerUi.load();
});

<|edits_diff|>
--- js/apidoc.js
+++ js/apidoc.js
@@ -4,6 +4,7 @@
 import '../less/udata/swagger.less';

 import $ from 'expose?$!expose?jQuery!jquery';
+import commonmark from 'helpers/commonmark';
 import hljs from 'highlight.js';
 import log from 'logger';

<|current_version|>
/**
 * Display a SwaggerUI documentation
 */
import '../less/udata/swagger.less';

import $ from 'expose?$!expose?jQuery!jquery';
import commonmark from 'helpers/commonmark';
import hljs from 'highlight.js';
import log from 'logger';

// Required jQuery plugins
import 'jquery.browser';
import 'swaggerui/lib/jquery.slideto.min';
import 'swaggerui/lib/jquery.wiggle.min';
import 'script!swaggerui/lib/jquery.ba-bbq.min';

import 'expose?Handlebars!handlebars';
import 'script!swaggerui/lib/underscore-min';
import 'script!swaggerui/lib/backbone-min';

import 'script!swaggerui/swagger-ui.min';
SwaggerUi = window.SwaggerUi;

$(function() {
    hljs.initHighlightingOnLoad();
    $('pre code').each(function(i, e) {
        hljs.highlightBlock(e);
    });

    const swaggerUi = new SwaggerUi({
        url: $('meta[name="swagger-specs"]').attr('content'),
        dom_id: 'swagger-ui-container',
        supportedSubmitMethods: ['get'],
        onComplete: function(swaggerApi, swaggerUi) {
            log.debug('Loaded SwaggerUI');

            $('#swagger-ui-container pre code').each(function(i, e) {
                hljs.highlightBlock(e);
            });
        },
        onFailure: function() {
            log.error('Unable to Load SwaggerUI');
        },
        docExpansion: 'none',
        sorter: 'alpha'
    });

    swaggerUi.load();
});

<|next_version|>
/**
 * Display a SwaggerUI documentation
 */
import '../less/udata/swagger.less';

import $ from 'expose?$!expose?jQuery!jquery';
import commonmark from 'helpers/commonmark';
import hljs from 'highlight.js';
import log from 'logger';

// Required jQuery plugins
import 'jquery.browser';
import 'swaggerui/lib/jquery.slideto.min';
import 'swaggerui/lib/jquery.wiggle.min';
import 'script!swaggerui/lib/jquery.ba-bbq.min';

import 'expose?Handlebars!handlebars';
import 'script!swaggerui/lib/underscore-min';
import 'script!swaggerui/lib/backbone-min';

import 'script!swaggerui/swagger-ui.min';
SwaggerUi = window.SwaggerUi;

// Marked compatibility for SwaggerUI
window.marked = commonmark;
marked.setOptions = function() {};

$(function() {
    hljs.initHighlightingOnLoad();
    $('pre code').each(function(i, e) {
        hljs.highlightBlock(e);
    });

    const swaggerUi = new SwaggerUi({
        url: $('meta[name="swagger-specs"]').attr('content'),
        dom_id: 'swagger-ui-container',
        supportedSubmitMethods: ['get'],
        onComplete: function(swaggerApi, swaggerUi) {
            log.debug('Loaded SwaggerUI');

            $('#swagger-ui-container pre code').each(function(i, e) {
                hljs.highlightBlock(e);
            });
        },
        onFailure: function() {
            log.error('Unable to Load SwaggerUI');
        },
        docExpansion: 'none',
        sorter: 'alpha'
    });

    swaggerUi.load();
});


Fix filter button not hiding and showing when selecting different tabs.

--- TachiWeb/js/manga_info.js
+++ TachiWeb/js/manga_info.js
@@ -1,3 +1,4 @@
+var filterButton;
 var reverseOrderBtn;
 var downloadBtn;
 var refreshBtn;
@@ -10,6 +11,7 @@
 var chapterPanel;

 function onLoad() {
+	filterButton = $("#filter_btn");
 	reverseOrderBtn = $("#reverse_order_btn");
 	downloadBtn = $("#download_btn");
 	refreshBtn = $("#refresh_btn");
@@ -30,6 +32,7 @@
 					});
 }
 function selectInfoTab() {
+	filterButton.hide(fadeSpeed);
 	reverseOrderBtn.hide(fadeSpeed);
 	downloadBtn.hide(fadeSpeed);
 	moreBtn.hide(fadeSpeed);
@@ -37,6 +40,7 @@
 	chapterPanel.removeClass("selected");
 }
 function selectChapterTab() {
+	filterButton.show(fadeSpeed);
 	reverseOrderBtn.show(fadeSpeed);
 	downloadBtn.show(fadeSpeed);
 	moreBtn.show(fadeSpeed);

<|original_code|>
var reverseOrderBtn;
var downloadBtn;
var refreshBtn;
var openBrowserBtn;
var moreBtn;
var infoTab;
var chapterTab;
var fadeSpeed = 250;
var infoPanel;
var chapterPanel;

function onLoad() {
	reverseOrderBtn = $("#reverse_order_btn");
	downloadBtn = $("#download_btn");
	refreshBtn = $("#refresh_btn");
	openBrowserBtn = $("#open_browser_btn");
	moreBtn = $("#more_btn");
	infoTab = $("#info_tab");
	chapterTab = $("#chapter_tab");
	infoPanel = $("#info_panel");
	chapterPanel = $("#chapter_panel");
	setupTabs();
}
function setupTabs() {
	infoTab.click(function() {
					  selectInfoTab();
				  });
	chapterTab.click(function() {
						selectChapterTab();
					});
}
function selectInfoTab() {
	reverseOrderBtn.hide(fadeSpeed);
	downloadBtn.hide(fadeSpeed);
	moreBtn.hide(fadeSpeed);
	infoPanel.addClass("selected");
	chapterPanel.removeClass("selected");
}
function selectChapterTab() {
	reverseOrderBtn.show(fadeSpeed);
	downloadBtn.show(fadeSpeed);
	moreBtn.show(fadeSpeed);
	infoPanel.removeClass("selected");
	chapterPanel.addClass("selected");
}

<|edits_diff|>
--- TachiWeb/js/manga_info.js
+++ TachiWeb/js/manga_info.js
@@ -1,3 +1,4 @@
+var filterButton;
 var reverseOrderBtn;
 var downloadBtn;
 var refreshBtn;
@@ -10,6 +11,7 @@
 var chapterPanel;

 function onLoad() {
+	filterButton = $("#filter_btn");
 	reverseOrderBtn = $("#reverse_order_btn");
 	downloadBtn = $("#download_btn");
 	refreshBtn = $("#refresh_btn");
@@ -30,6 +32,7 @@
 					});
 }
 function selectInfoTab() {
+	filterButton.hide(fadeSpeed);
 	reverseOrderBtn.hide(fadeSpeed);
 	downloadBtn.hide(fadeSpeed);
 	moreBtn.hide(fadeSpeed);
<|current_version|>
var filterButton;
var reverseOrderBtn;
var downloadBtn;
var refreshBtn;
var openBrowserBtn;
var moreBtn;
var infoTab;
var chapterTab;
var fadeSpeed = 250;
var infoPanel;
var chapterPanel;

function onLoad() {
	filterButton = $("#filter_btn");
	reverseOrderBtn = $("#reverse_order_btn");
	downloadBtn = $("#download_btn");
	refreshBtn = $("#refresh_btn");
	openBrowserBtn = $("#open_browser_btn");
	moreBtn = $("#more_btn");
	infoTab = $("#info_tab");
	chapterTab = $("#chapter_tab");
	infoPanel = $("#info_panel");
	chapterPanel = $("#chapter_panel");
	setupTabs();
}
function setupTabs() {
	infoTab.click(function() {
					  selectInfoTab();
				  });
	chapterTab.click(function() {
						selectChapterTab();
					});
}
function selectInfoTab() {
	filterButton.hide(fadeSpeed);
	reverseOrderBtn.hide(fadeSpeed);
	downloadBtn.hide(fadeSpeed);
	moreBtn.hide(fadeSpeed);
	infoPanel.addClass("selected");
	chapterPanel.removeClass("selected");
}
function selectChapterTab() {
	reverseOrderBtn.show(fadeSpeed);
	downloadBtn.show(fadeSpeed);
	moreBtn.show(fadeSpeed);
	infoPanel.removeClass("selected");
	chapterPanel.addClass("selected");
}

<|next_version|>
var filterButton;
var reverseOrderBtn;
var downloadBtn;
var refreshBtn;
var openBrowserBtn;
var moreBtn;
var infoTab;
var chapterTab;
var fadeSpeed = 250;
var infoPanel;
var chapterPanel;

function onLoad() {
	filterButton = $("#filter_btn");
	reverseOrderBtn = $("#reverse_order_btn");
	downloadBtn = $("#download_btn");
	refreshBtn = $("#refresh_btn");
	openBrowserBtn = $("#open_browser_btn");
	moreBtn = $("#more_btn");
	infoTab = $("#info_tab");
	chapterTab = $("#chapter_tab");
	infoPanel = $("#info_panel");
	chapterPanel = $("#chapter_panel");
	setupTabs();
}
function setupTabs() {
	infoTab.click(function() {
					  selectInfoTab();
				  });
	chapterTab.click(function() {
						selectChapterTab();
					});
}
function selectInfoTab() {
	filterButton.hide(fadeSpeed);
	reverseOrderBtn.hide(fadeSpeed);
	downloadBtn.hide(fadeSpeed);
	moreBtn.hide(fadeSpeed);
	infoPanel.addClass("selected");
	chapterPanel.removeClass("selected");
}
function selectChapterTab() {
	filterButton.show(fadeSpeed);
	reverseOrderBtn.show(fadeSpeed);
	downloadBtn.show(fadeSpeed);
	moreBtn.show(fadeSpeed);
	infoPanel.removeClass("selected");
	chapterPanel.addClass("selected");
}


Print sync errors to the console when `failureActionCreator` is not set.

--- src/utils.js
+++ src/utils.js
@@ -10,7 +10,13 @@
       yield put(successActionCreator(transformedData))
     }
   } catch (err) {
+    /* eslint-disable no-console */
     if (failureActionCreator) yield put(failureActionCreator(err))
+    else
+      console.error(
+        'The following error has been ignored because no `failureActionCreator` has been set:',
+        err,
+      )
   } finally {
     if (yield cancelled()) channel.close()
   }

<|original_code|>
import { cancelled, put, take } from 'redux-saga/effects'

export function* syncChannel(channel, options) {
  const { successActionCreator, failureActionCreator, transform } = options

  try {
    while (true) {
      const data = yield take(channel)
      const transformedData = transform ? transform(data) : data
      yield put(successActionCreator(transformedData))
    }
  } catch (err) {
    if (failureActionCreator) yield put(failureActionCreator(err))
  } finally {
    if (yield cancelled()) channel.close()
  }
}

<|edits_diff|>
--- src/utils.js
+++ src/utils.js
@@ -10,6 +10,7 @@
       yield put(successActionCreator(transformedData))
     }
   } catch (err) {
+    /* eslint-disable no-console */
     if (failureActionCreator) yield put(failureActionCreator(err))
   } finally {
     if (yield cancelled()) channel.close()
<|current_version|>
import { cancelled, put, take } from 'redux-saga/effects'

export function* syncChannel(channel, options) {
  const { successActionCreator, failureActionCreator, transform } = options

  try {
    while (true) {
      const data = yield take(channel)
      const transformedData = transform ? transform(data) : data
      yield put(successActionCreator(transformedData))
    }
  } catch (err) {
    /* eslint-disable no-console */
    if (failureActionCreator) yield put(failureActionCreator(err))
  } finally {
    if (yield cancelled()) channel.close()
  }
}

<|next_version|>
import { cancelled, put, take } from 'redux-saga/effects'

export function* syncChannel(channel, options) {
  const { successActionCreator, failureActionCreator, transform } = options

  try {
    while (true) {
      const data = yield take(channel)
      const transformedData = transform ? transform(data) : data
      yield put(successActionCreator(transformedData))
    }
  } catch (err) {
    /* eslint-disable no-console */
    if (failureActionCreator) yield put(failureActionCreator(err))
    else
      console.error(
        'The following error has been ignored because no `failureActionCreator` has been set:',
        err,
      )
  } finally {
    if (yield cancelled()) channel.close()
  }
}


Add unique index to name

Add unique index to name

--- backend/database/migrations/1514382391054_word_schema.js
+++ backend/database/migrations/1514382391054_word_schema.js
@@ -7,7 +7,10 @@
   up () {
     this.create('words', (table) => {
       table.increments()
+
       table.string('name').notNullable()
+      table.unique('name');
+
       table.integer('syllablesCount').unsigned()
       table.string('ultima')
       table.boolean('hasCheckedSynonyms').default(false)

<|original_code|>
'use strict'

const Schema = use('Schema')

class WordSchema extends Schema {
  up () {
    this.create('words', (table) => {
      table.increments()
      table.string('name').notNullable()
      table.integer('syllablesCount').unsigned()
      table.string('ultima')
      table.boolean('hasCheckedSynonyms').default(false)
      table.boolean('isEmpty').default(false);
      table.timestamp('createdAt');
      table.timestamp('updatedAt');
    })
  }

  down () {
    this.drop('words')
  }
}

module.exports = WordSchema

<|edits_diff|>
--- backend/database/migrations/1514382391054_word_schema.js
+++ backend/database/migrations/1514382391054_word_schema.js
@@ -7,6 +7,7 @@
   up () {
     this.create('words', (table) => {
       table.increments()
+
       table.string('name').notNullable()
       table.integer('syllablesCount').unsigned()
       table.string('ultima')
<|current_version|>
'use strict'

const Schema = use('Schema')

class WordSchema extends Schema {
  up () {
    this.create('words', (table) => {
      table.increments()

      table.string('name').notNullable()
      table.integer('syllablesCount').unsigned()
      table.string('ultima')
      table.boolean('hasCheckedSynonyms').default(false)
      table.boolean('isEmpty').default(false);
      table.timestamp('createdAt');
      table.timestamp('updatedAt');
    })
  }

  down () {
    this.drop('words')
  }
}

module.exports = WordSchema

<|next_version|>
'use strict'

const Schema = use('Schema')

class WordSchema extends Schema {
  up () {
    this.create('words', (table) => {
      table.increments()

      table.string('name').notNullable()
      table.unique('name');

      table.integer('syllablesCount').unsigned()
      table.string('ultima')
      table.boolean('hasCheckedSynonyms').default(false)
      table.boolean('isEmpty').default(false);
      table.timestamp('createdAt');
      table.timestamp('updatedAt');
    })
  }

  down () {
    this.drop('words')
  }
}

module.exports = WordSchema


Add date input to sanity input resolver

Add date input to sanity input resolver

--- src/sanity/inputResolver/inputResolver.js
+++ src/sanity/inputResolver/inputResolver.js
@@ -1,5 +1,6 @@
 import array from 'role:@sanity/form-builder/input/array?'
 import boolean from 'role:@sanity/form-builder/input/boolean?'
+import date from 'role:@sanity/form-builder/input/date?'
 import email from 'role:@sanity/form-builder/input/email?'
 import geopoint from 'role:@sanity/form-builder/input/geopoint?'
 import number from 'role:@sanity/form-builder/input/number?'
@@ -12,6 +13,7 @@
 const coreTypes = {
   array,
   boolean,
+  date,
   email,
   geopoint,
   number,

<|original_code|>
import array from 'role:@sanity/form-builder/input/array?'
import boolean from 'role:@sanity/form-builder/input/boolean?'
import email from 'role:@sanity/form-builder/input/email?'
import geopoint from 'role:@sanity/form-builder/input/geopoint?'
import number from 'role:@sanity/form-builder/input/number?'
import object from 'role:@sanity/form-builder/input/object?'
import reference from 'role:@sanity/form-builder/input/reference?'
import string from 'role:@sanity/form-builder/input/string?'
import text from 'role:@sanity/form-builder/input/text?'
import url from 'role:@sanity/form-builder/input/url?'

const coreTypes = {
  array,
  boolean,
  email,
  geopoint,
  number,
  object,
  reference,
  string,
  text,
  url
}

const inputResolver = (field, fieldType) => {
  const inputRole = coreTypes[field.type] || coreTypes[fieldType.name]
  return field.input || inputRole
}

export default inputResolver

<|edits_diff|>
--- src/sanity/inputResolver/inputResolver.js
+++ src/sanity/inputResolver/inputResolver.js
@@ -1,5 +1,6 @@
 import array from 'role:@sanity/form-builder/input/array?'
 import boolean from 'role:@sanity/form-builder/input/boolean?'
+import date from 'role:@sanity/form-builder/input/date?'
 import email from 'role:@sanity/form-builder/input/email?'
 import geopoint from 'role:@sanity/form-builder/input/geopoint?'
 import number from 'role:@sanity/form-builder/input/number?'
<|current_version|>
import array from 'role:@sanity/form-builder/input/array?'
import boolean from 'role:@sanity/form-builder/input/boolean?'
import date from 'role:@sanity/form-builder/input/date?'
import email from 'role:@sanity/form-builder/input/email?'
import geopoint from 'role:@sanity/form-builder/input/geopoint?'
import number from 'role:@sanity/form-builder/input/number?'
import object from 'role:@sanity/form-builder/input/object?'
import reference from 'role:@sanity/form-builder/input/reference?'
import string from 'role:@sanity/form-builder/input/string?'
import text from 'role:@sanity/form-builder/input/text?'
import url from 'role:@sanity/form-builder/input/url?'

const coreTypes = {
  array,
  boolean,
  email,
  geopoint,
  number,
  object,
  reference,
  string,
  text,
  url
}

const inputResolver = (field, fieldType) => {
  const inputRole = coreTypes[field.type] || coreTypes[fieldType.name]
  return field.input || inputRole
}

export default inputResolver

<|next_version|>
import array from 'role:@sanity/form-builder/input/array?'
import boolean from 'role:@sanity/form-builder/input/boolean?'
import date from 'role:@sanity/form-builder/input/date?'
import email from 'role:@sanity/form-builder/input/email?'
import geopoint from 'role:@sanity/form-builder/input/geopoint?'
import number from 'role:@sanity/form-builder/input/number?'
import object from 'role:@sanity/form-builder/input/object?'
import reference from 'role:@sanity/form-builder/input/reference?'
import string from 'role:@sanity/form-builder/input/string?'
import text from 'role:@sanity/form-builder/input/text?'
import url from 'role:@sanity/form-builder/input/url?'

const coreTypes = {
  array,
  boolean,
  date,
  email,
  geopoint,
  number,
  object,
  reference,
  string,
  text,
  url
}

const inputResolver = (field, fieldType) => {
  const inputRole = coreTypes[field.type] || coreTypes[fieldType.name]
  return field.input || inputRole
}

export default inputResolver


Add link to my pantry from landing page

Add link to my pantry from landing page

--- wwwroot/app/src/components/LandingPage/LandingPage.js
+++ wwwroot/app/src/components/LandingPage/LandingPage.js
@@ -33,7 +33,11 @@
     return (

 Hey there, have a lovely day!

+        <Link to={'/pantry'}> My Pantry </Link>
+

+

         <button onClick={() => this.logOut()}> Log out </button>
+

     );
   }

<|original_code|>
import React, { Component } from 'react';
import { Link } from 'react-router';
import TopBar from '../TopBar/TopBar';
import TokenStore from '../../services/TokenStore';

class LandingPage extends Component {

  constructor(props) {
    super(props);

    this.state = {
      isUserLoggedIn: TokenStore.isUserLoggedIn()
    };
  }

  logOut() {
    TokenStore.logOut();
    this.setState({isUserLoggedIn: false});
  }

  renderNotLoggedUserActions() {
    return (

        <Link to={`/register`}>Create new account</Link>

        <Link to={`/login`}>Login</Link>

    );
  }

  renderLoggedInUserActions() {
    return (

 Hey there, have a lovely day!

        <button onClick={() => this.logOut()}> Log out </button>

    );
  }

  renderActions() {
    if (this.state.isUserLoggedIn) {
      return this.renderLoggedInUserActions();
    }

    return this.renderNotLoggedUserActions();
  }

  render() {
    return (

        <TopBar />
        {this.renderActions()}

    );
  }
}

export default LandingPage;

<|edits_diff|>
--- wwwroot/app/src/components/LandingPage/LandingPage.js
+++ wwwroot/app/src/components/LandingPage/LandingPage.js
@@ -33,6 +33,9 @@
     return (

 Hey there, have a lovely day!

+        <Link to={'/pantry'}> My Pantry </Link>
+

+

         <button onClick={() => this.logOut()}> Log out </button>

     );
<|current_version|>
import React, { Component } from 'react';
import { Link } from 'react-router';
import TopBar from '../TopBar/TopBar';
import TokenStore from '../../services/TokenStore';

class LandingPage extends Component {

  constructor(props) {
    super(props);

    this.state = {
      isUserLoggedIn: TokenStore.isUserLoggedIn()
    };
  }

  logOut() {
    TokenStore.logOut();
    this.setState({isUserLoggedIn: false});
  }

  renderNotLoggedUserActions() {
    return (

        <Link to={`/register`}>Create new account</Link>

        <Link to={`/login`}>Login</Link>

    );
  }

  renderLoggedInUserActions() {
    return (

 Hey there, have a lovely day!

        <Link to={'/pantry'}> My Pantry </Link>

        <button onClick={() => this.logOut()}> Log out </button>

    );
  }

  renderActions() {
    if (this.state.isUserLoggedIn) {
      return this.renderLoggedInUserActions();
    }

    return this.renderNotLoggedUserActions();
  }

  render() {
    return (

        <TopBar />
        {this.renderActions()}

    );
  }
}

export default LandingPage;

<|next_version|>
import React, { Component } from 'react';
import { Link } from 'react-router';
import TopBar from '../TopBar/TopBar';
import TokenStore from '../../services/TokenStore';

class LandingPage extends Component {

  constructor(props) {
    super(props);

    this.state = {
      isUserLoggedIn: TokenStore.isUserLoggedIn()
    };
  }

  logOut() {
    TokenStore.logOut();
    this.setState({isUserLoggedIn: false});
  }

  renderNotLoggedUserActions() {
    return (

        <Link to={`/register`}>Create new account</Link>

        <Link to={`/login`}>Login</Link>

    );
  }

  renderLoggedInUserActions() {
    return (

 Hey there, have a lovely day!

        <Link to={'/pantry'}> My Pantry </Link>

        <button onClick={() => this.logOut()}> Log out </button>

    );
  }

  renderActions() {
    if (this.state.isUserLoggedIn) {
      return this.renderLoggedInUserActions();
    }

    return this.renderNotLoggedUserActions();
  }

  render() {
    return (

        <TopBar />
        {this.renderActions()}

    );
  }
}

export default LandingPage;


Add footnotes to the Reader.

Add footnotes to the Reader.

--- src/article/reader/ReaderPackage.js
+++ src/article/reader/ReaderPackage.js
@@ -5,6 +5,7 @@
 import EntityLabelsPackage from '../shared/EntityLabelsPackage'
 import ManuscriptContentPackage from '../shared/ManuscriptContentPackage'
 import ReferenceListComponent from '../shared/ReferenceListComponent'
+import FootnoteGroupComponent from '../shared/FootnoteGroupComponent'

 export default {
   name: 'ArticleReader',
@@ -16,6 +17,7 @@
     config.import(ArticleNavPackage)

     config.addComponent('references', ReferenceListComponent)
+    config.addComponent('footnotes', FootnoteGroupComponent)

     config.addToolPanel('toolbar', [
       {

<|original_code|>
/* eslint-disable no-template-curly-in-string */
import { BasePackage, ModelComponentPackage } from '../../kit'

import ArticleNavPackage from '../ArticleNavPackage'
import EntityLabelsPackage from '../shared/EntityLabelsPackage'
import ManuscriptContentPackage from '../shared/ManuscriptContentPackage'
import ReferenceListComponent from '../shared/ReferenceListComponent'

export default {
  name: 'ArticleReader',
  configure (config) {
    config.import(BasePackage)
    config.import(ModelComponentPackage)
    config.import(ManuscriptContentPackage)
    config.import(EntityLabelsPackage)
    config.import(ArticleNavPackage)

    config.addComponent('references', ReferenceListComponent)

    config.addToolPanel('toolbar', [
      {
        name: 'mode',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'full',
        items: [
          { type: 'command-group', name: 'switch-view' }
        ]
      }
    ])
  }
}

<|edits_diff|>
--- src/article/reader/ReaderPackage.js
+++ src/article/reader/ReaderPackage.js
@@ -5,6 +5,7 @@
 import EntityLabelsPackage from '../shared/EntityLabelsPackage'
 import ManuscriptContentPackage from '../shared/ManuscriptContentPackage'
 import ReferenceListComponent from '../shared/ReferenceListComponent'
+import FootnoteGroupComponent from '../shared/FootnoteGroupComponent'

 export default {
   name: 'ArticleReader',
<|current_version|>
/* eslint-disable no-template-curly-in-string */
import { BasePackage, ModelComponentPackage } from '../../kit'

import ArticleNavPackage from '../ArticleNavPackage'
import EntityLabelsPackage from '../shared/EntityLabelsPackage'
import ManuscriptContentPackage from '../shared/ManuscriptContentPackage'
import ReferenceListComponent from '../shared/ReferenceListComponent'
import FootnoteGroupComponent from '../shared/FootnoteGroupComponent'

export default {
  name: 'ArticleReader',
  configure (config) {
    config.import(BasePackage)
    config.import(ModelComponentPackage)
    config.import(ManuscriptContentPackage)
    config.import(EntityLabelsPackage)
    config.import(ArticleNavPackage)

    config.addComponent('references', ReferenceListComponent)

    config.addToolPanel('toolbar', [
      {
        name: 'mode',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'full',
        items: [
          { type: 'command-group', name: 'switch-view' }
        ]
      }
    ])
  }
}

<|next_version|>
/* eslint-disable no-template-curly-in-string */
import { BasePackage, ModelComponentPackage } from '../../kit'

import ArticleNavPackage from '../ArticleNavPackage'
import EntityLabelsPackage from '../shared/EntityLabelsPackage'
import ManuscriptContentPackage from '../shared/ManuscriptContentPackage'
import ReferenceListComponent from '../shared/ReferenceListComponent'
import FootnoteGroupComponent from '../shared/FootnoteGroupComponent'

export default {
  name: 'ArticleReader',
  configure (config) {
    config.import(BasePackage)
    config.import(ModelComponentPackage)
    config.import(ManuscriptContentPackage)
    config.import(EntityLabelsPackage)
    config.import(ArticleNavPackage)

    config.addComponent('references', ReferenceListComponent)
    config.addComponent('footnotes', FootnoteGroupComponent)

    config.addToolPanel('toolbar', [
      {
        name: 'mode',
        type: 'tool-dropdown',
        showDisabled: false,
        style: 'full',
        items: [
          { type: 'command-group', name: 'switch-view' }
        ]
      }
    ])
  }
}


Add 200ms to load page

Add 200ms to load page

--- src/main/resources/render.js
+++ src/main/resources/render.js
@@ -18,7 +18,9 @@
 }

 page.open(system.args[1], function () {
+  window.setTimeout(function () {
     page.render(outname);
     phantom.exit();
+  }, 200);
 });

<|original_code|>
var page = require('webpage').create(),
    system = require('system'),
    outname, fs = require("fs");

String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

if (system.args.length > 2) {
  outname=system.args[2];
} else {
  outname=system.args[1].replace('.html', '.png');
}
if (outname.endsWith(".pdf")) {
  page.viewportSize = { width: 1920 * 1.35, height: 1080 * 1.35};
} else {
  page.viewportSize = { width: 1920, height: 1080 };
}

page.open(system.args[1], function () {
    page.render(outname);
    phantom.exit();
});

<|edits_diff|>
--- src/main/resources/render.js
+++ src/main/resources/render.js
@@ -18,6 +18,7 @@
 }

 page.open(system.args[1], function () {
+  window.setTimeout(function () {
     page.render(outname);
     phantom.exit();
 });
<|current_version|>
var page = require('webpage').create(),
    system = require('system'),
    outname, fs = require("fs");

String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

if (system.args.length > 2) {
  outname=system.args[2];
} else {
  outname=system.args[1].replace('.html', '.png');
}
if (outname.endsWith(".pdf")) {
  page.viewportSize = { width: 1920 * 1.35, height: 1080 * 1.35};
} else {
  page.viewportSize = { width: 1920, height: 1080 };
}

page.open(system.args[1], function () {
  window.setTimeout(function () {
    page.render(outname);
    phantom.exit();
});

<|next_version|>
var page = require('webpage').create(),
    system = require('system'),
    outname, fs = require("fs");

String.prototype.endsWith = function(suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

if (system.args.length > 2) {
  outname=system.args[2];
} else {
  outname=system.args[1].replace('.html', '.png');
}
if (outname.endsWith(".pdf")) {
  page.viewportSize = { width: 1920 * 1.35, height: 1080 * 1.35};
} else {
  page.viewportSize = { width: 1920, height: 1080 };
}

page.open(system.args[1], function () {
  window.setTimeout(function () {
    page.render(outname);
    phantom.exit();
  }, 200);
});