'use strict';

var chai = require('chai');
var expect = chai.expect;
chai.use(require('chai-as-promised'));

var Browser = require('zombie');
var browser = new Browser({
	site: 'http://localhost:' + process.env.PORT
});

describe('Given I visit /event/add', function() {
	before(function(done) {
		browser.visit('/event/add', done);
	})

	it("the page should load fine", function() {
		expect(browser.status).to.equal(200);
	});

	xit('submitted events should have a slug including their id')
});

'use strict';

var chai = require('chai');
var Browser = require('zombie');
var moment = require('moment');

var expect = chai.expect;
chai.use(require('chai-as-promised'));

const baseUrl = 'http://localhost:' + process.env.PORT;
var browser = new Browser({
	site: baseUrl
});

describe('Given I visit /event/add', function() {
	before(function(done) {
		browser.visit('/event/add', done);
	})

	it('the page should load fine', function() {
		browser.assert.status(200);
	});

	describe('given incomplete form data', function() {
		let formTitle = 'testing event';
		let formLocation = 'testing venue';

		before(function() {
			browser
				.fill('title', formTitle)
				.fill('location_text', formLocation);
			browser.querySelector('form').submit();
			return browser.wait();
		});

		it('should return to event add URL', function() {
			browser.assert.url('/event/add');
		});

		it('should preserve the input data', function() {
			browser.assert.attribute('#title', 'value', formTitle);
			browser.assert.attribute('#location_text', 'value', formLocation);
		});
	});

	describe('given complete & valid form data', function() {
		before(function() {
			browser
				.fill('title', 'testing')
				.fill('startdt', moment().add(1, 'day').format("YYYY-MM-DD HH:mm"))
				.fill('location_text', 'testing')
				.fill('host', 'testing')
				.fill('blurb', 'testing')
				.fill('email', 'test@example.com');
			browser.querySelector('form').submit();
			return browser.wait();
		});

		it('should return to the home page', function() {
			browser.assert.url('/');
		});

		xit('should produce an event with a slug that includes their ID');
	});
});

Add some basic testing of /event/add


var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Location = require('./location_model');

var XeroAccountSchema   = new Schema({
	location_id: { type: ObjectId, ref: 'Location', unique: true },
	consumer_key: String, // oAuth1
	consumer_secret: String, // oAuth1
	client_id: String, // oAuth2
	client_secret: String, // oAuth2
	access_token: String, // oAuth2
	tenant_id: String, // oAuth2
	refresh_token: String, // oAuth2
	token_expires: Date, // oAuth2
}, {
	timestamps: true
});

XeroAccountSchema.set("_perms", {
	setup: "crud",
	api: "r",
	admin: "-"
});

module.exports = mongoose.model('XeroAccount', XeroAccountSchema);

var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Location = require('./location_model');

var XeroAccountSchema   = new Schema({
	location_id: { type: ObjectId, ref: 'Location', unique: true },
	consumer_key: String, // oAuth1
	consumer_secret: String, // oAuth1
	client_id: String, // oAuth2
	client_secret: String, // oAuth2
	access_token: String, // oAuth2
	tenant_id: String, // oAuth2
	refresh_token: String, // oAuth2
	token_expires: Date, // oAuth2
}, {
	timestamps: true
});

XeroAccountSchema.set("_perms", {
	setup: "crud",
	api: "r",
	admin: "r"
});

module.exports = mongoose.model('XeroAccount', XeroAccountSchema);

Allow admins to access xeroaccounts (for now)


module.exports = function (grunt) {
    grunt.initConfig({
        pkg : grunt.file.readJSON('package.json'),

        uglify : {
            build : {
                files : {
                    'src/Lord/Laroute/templates/laroute.min.js' : 'src/Lord/Laroute/templates/laroute.js'
                }
            }
        }
    });

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

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

module.exports = function (grunt) {
    grunt.initConfig({
        pkg : grunt.file.readJSON('package.json'),

        uglify : {
            build : {
                files : {
                    'src/templates/laroute.min.js' : 'src/templates/laroute.js'
                }
            }
        }
    });

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

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

Fix file paths in the grunt config


define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(resource) {
    var dv = new DataView(resource.data.buffer, resource.data.byteOffset, resource.data.byteLength);
    resource.dataObject = {
      rectangle: {
        top: dv.getInt16(0, false),
        left: dv.getInt16(2, false),
        bottom: dv.getInt16(4, false),
        right: dv.getInt16(6, false),
      },
      type: dv.getUint16(8, false),
      visible: !!resource.data[10],
      closeBox: !!resource.data[12],
      referenceConstant: dv.getInt32(14, false),
      itemListResourceID: dv.getInt16(18, false),
    };
    switch(resource.dataObject.type) {
      case 0: resource.dataObject.type = 'modal'; break;
      case 4: resource.dataObject.type = 'modeless'; break;
      case 5: resource.dataObject.type = 'movableModal'; break;
    }
    resource.dataObject.text = macintoshRoman(resource.data, 21, resource.data[20]);
    var pos = 20 + 1 + resource.dataObject.text.length + (1 + resource.dataObject.text.length) % 2;
    if (pos + 2 <= resource.data.length) {
      resource.dataObject.positionCode = dv.getUint16(pos, false);
    }
  };

});

define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(item) {
    return item.getBytes().then(function(bytes) {
      var dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
      var dataObject = {
        rectangle: {
          top: dv.getInt16(0, false),
          left: dv.getInt16(2, false),
          bottom: dv.getInt16(4, false),
          right: dv.getInt16(6, false),
        },
        type: dv.getUint16(8, false),
        visible: !!bytes[10],
        closeBox: !!bytes[12],
        referenceConstant: dv.getInt32(14, false),
        itemListResourceID: dv.getInt16(18, false),
      };
      switch(dataObject.type) {
        case 0: dataObject.type = 'modal'; break;
        case 4: dataObject.type = 'modeless'; break;
        case 5: dataObject.type = 'movableModal'; break;
      }
      dataObject.text = macintoshRoman(bytes, 21, bytes[20]);
      var pos = 20 + 1 + dataObject.text.length + (1 + dataObject.text.length) % 2;
      if (pos + 2 <= bytes.length) {
        dataObject.positionCode = dv.getUint16(pos, false);
      }
      item.setDataObject(dataObject);
    });
  };

});

Change DLOG to new loader format


define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(resource) {
    if (resource.data.length !== 7) {
      console.error('FREF resource expected to be 7 bytes, got ' + resource.data.length);
      return;
    }
    resource.dataObject = {
      fileType: macintoshRoman(resource.data, 0, 4),
      iconListID: (resource.data[4] << 8) | resource.data[5],
    };
  };

});

define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(item) {
    return item.getBytes().then(function(bytes) {
      if (bytes.length !== 7) {
        return Promise.reject('FREF resource expected to be 7 bytes, got ' + bytes.length);
      }
      item.setDataObject({
        fileType: macintoshRoman(resource.data, 0, 4),
        iconListID: (resource.data[4] << 8) | resource.data[5],
      });
    });
  };

});

Change FREF to new loader format


(function() {
    'use strict';

    angular
        .module('lecturer')
        .controller('LoginCtrl', LoginController);

    /* @ngInject */
    function LoginController(lecturerFactory, $location) {
        console.log('Ready (Login Controller)');
        angular.element('#login-btn').addClass('active');

        if (lecturerFactory.isLoggedIn()) {
            $location.path('/courses');
        }

        var vm = this;
        vm.loginAttempt = false;
        vm.form = {};
        vm.loginUser = loginUser;

        function loginUser() {
            lecturerFactory.login(vm.form,
                function() {
                    $location.path('/lectures/1');
                },
                function() {
                    vm.loginAttempt = true;
                    vm.feedbackMessage = 'Wrong user credentials';
                    vm.feedbackType = 'alert-danger';
                    vm.feedbackIcon = 'glyphicon-exclamation-sign';
                }
            );
        }
    }
})();

(function() {
    'use strict';

    angular
        .module('lecturer')
        .controller('LoginCtrl', LoginController);

    /* @ngInject */
    function LoginController(lecturerFactory, $location) {
        console.log('Ready (Login Controller)');
        angular.element('#login-btn').addClass('active');

        if (lecturerFactory.isLoggedIn()) {
            $location.path('/courses');
        }

        var vm = this;
        vm.loginAttempt = false;
        vm.form = {};
        vm.loginUser = loginUser;

        function loginUser() {
            lecturerFactory.login(vm.form,
                function() {
                    $location.path('/courses');
                },
                function() {
                    vm.loginAttempt = true;
                    vm.feedbackMessage = 'Wrong user credentials';
                    vm.feedbackType = 'alert-danger';
                    vm.feedbackIcon = 'glyphicon-exclamation-sign';
                }
            );
        }
    }
})();

Change to courses page in stead of lecture 1 when logging in


/*global define*/

define([
        'jquery',
        'underscore',
        'backbone',
        'templates',
        'dygraphs',
        'marionette'
], function($, _, Backbone, JST, Dygraph) {
    'use strict';

    var IopsDashView = Backbone.Marionette.ItemView.extend({
        className: 'custom-gutter col-sm-12 col-xs-12 col-lg-9 col-md-9',
        template: JST['app/scripts/templates/iops-dash.ejs'],
        ui: {
            'canvas': '.iopscanvas',
            'headline': '.headline'
        },
        initialize: function() {
            this.Dygraph = Dygraph;
            _.bindAll(this, 'postRender');
            this.listenToOnce(this, 'render', this.postRender);
        },
        data: [
            [1, 10, 120],
            [2, 20, 80],
            [3, 50, 60],
            [4, 70, 80]
        ],
        postRender: function() {
            this.d = new Dygraph(this.ui.canvas[0], this.data, {
                axisLabelFontSize: 10,
                drawYAxis: false,
                height: 100,
                width: 400
            });
            this.ui.headline.text('lotta');
        }
    });

    return IopsDashView;
});

/*global define*/

define([
        'jquery',
        'underscore',
        'backbone',
        'templates',
        'dygraphs',
        'helpers/gauge-helper',
        'marionette',
], function($, _, Backbone, JST, Dygraph, gaugeHelper) {
    'use strict';

    var IopsDashView = Backbone.Marionette.ItemView.extend({
        className: 'custom-gutter col-sm-12 col-xs-12 col-lg-9 col-md-9',
        template: JST['app/scripts/templates/iops-dash.ejs'],
        ui: {
            'canvas': '.iopscanvas',
            'headline': '.headline'
        },
        initialize: function() {
            this.Dygraph = Dygraph;
            _.bindAll(this, 'postRender');
            this.App = Backbone.Marionette.getOption(this, 'App');
            this.listenToOnce(this, 'render', this.postRender);
            gaugeHelper(this);
        },
        data: [
            [1, 10, 120],
            [2, 20, 80],
            [3, 50, 60],
            [4, 70, 80]
        ],
        postRender: function() {
            this.d = new Dygraph(this.ui.canvas[0], this.data, {
                axisLabelFontSize: 10,
                drawYAxis: false,
                height: 100,
                width: 400
            });
            this.ui.headline.text('lotta');
        }
    });

    return IopsDashView;
});

Add gauge Helper so card disappears


/* eslint-env jest */

const firebaseApp = jest.genMockFromModule('firebase')

// By default, return no user.
var firebaseUser = null

firebaseApp.auth = jest.fn(() => ({
  onAuthStateChanged: jest.fn(callback => {
    // Return the Firebase user.
    callback(firebaseUser)
  }),
  signOut: jest.fn()
}))

firebaseApp.__setFirebaseUser = (user) => {
  firebaseUser = user
}

module.exports = firebaseApp

/* eslint-env jest */

const firebaseApp = jest.genMockFromModule('firebase')

// By default, return no user.
var firebaseUser = null

const FirebaseAuthMock = () => {
  return {
    onAuthStateChanged: jest.fn(callback => {
      // Return the Firebase user.
      callback(firebaseUser)
    }),
    signOut: jest.fn()
  }
}

FirebaseAuthMock.EmailAuthProvider = {
  PROVIDER_ID: 'password'
}

FirebaseAuthMock.GoogleAuthProvider = {
  PROVIDER_ID: 'google.com'
}

FirebaseAuthMock.FacebookAuthProvider = {
  PROVIDER_ID: 'facebook.com'
}

firebaseApp.auth = FirebaseAuthMock

firebaseApp.__setFirebaseUser = (user) => {
  firebaseUser = user
}

module.exports = firebaseApp

Fix mock for testing FirebaseAuthenticationUI component


Template.MasterLayout.events({

  'click [data-action="install-app"]': function(evt, tmp) {

    if (!$(evt.target).attr('href')) {
      evt.preventDefault();
      AppMarket.getSandstormHost(this.packageId, function() {
        Tracker.afterFlush(function() {
          tmp.$('[data-action="install-app"]').click();
        });
      });
    }

  }

});

Template.MasterLayout.events({

  'click [data-action="install-app"]': function(evt, tmp) {

    if (!$(evt.currentTarget).attr('href')) {
      evt.preventDefault();
      AppMarket.getSandstormHost(this.packageId, function() {
        Tracker.afterFlush(function() {
          tmp.$('[data-action="install-app"]').click();
        });
      });
    }

  }

});

Fix clicking on right-triangle in install button has no effect.


(function ($) {
    'use strict';

    /**
     * Panda Base Events Service
     * @type {void|Object|*}
     */
    Panda.Events = $.extend(Panda.Events || {}, {
        init: function () {
            // Register global events
            Panda.Events.Library.init();
        },
        on: function (listener, event, context, callback) {
            $(listener).on(event, context, function () {
                if (typeof callback === 'function') {
                    callback.apply(this, Array.prototype.slice.call(arguments));
                }
            });
        },
        one: function (listener, event, context, callback) {
            $(listener).one(event, context, function () {
                if (typeof callback === 'function') {
                    callback.apply(this, Array.prototype.slice.call(arguments));
                }
            });
        },
        off: function (listener, event, context) {
            $(listener).off(event, context);
        },
        dispatch: function (listener, event, callback) {
            $(listener).trigger(event, callback);
        }
    });
})(jQuery);

(function ($) {
    'use strict';

    /**
     * Panda Base Events Service
     * @type {void|Object|*}
     */
    Panda.Events = $.extend(Panda.Events || {}, {
        /**
         * Initialize the Panda Events Library
         */
        init: function () {
            // Register global events
            Panda.Events.Library.init();
        },

        /**
         * Add an event listener using jQuery's 'on'
         *
         * @param {object|string} listener
         * @param {string} event
         * @param {string} context
         * @param {function} callback
         */
        on: function (listener, event, context, callback) {
            $(listener).on(event, context, function () {
                if (typeof callback === 'function') {
                    callback.apply(this, Array.prototype.slice.call(arguments));
                }
            });
        },

        /**
         * Add an event listener using jQuery's 'one'
         *
         * @param {object|string} listener
         * @param {string} event
         * @param {string} context
         * @param {function} callback
         */
        one: function (listener, event, context, callback) {
            $(listener).one(event, context, function () {
                if (typeof callback === 'function') {
                    callback.apply(this, Array.prototype.slice.call(arguments));
                }
            });
        },

        /**
         * Remove an event listener.
         *
         * @param {object|string} listener
         * @param {string} event
         * @param {string} context
         */
        off: function (listener, event, context) {
            $(listener).off(event, context);
        },

        /**
         * Trigger a specific event
         *
         * @param {object|string} listener
         * @param {string} event
         * @param {function} callback
         */
        dispatch: function (listener, event, callback) {
            $(listener).trigger(event, callback);
        }
    });
})(jQuery);

Add comments in Service functions


// index
// ========
// Pulls in everything needed for use via npm.

'use strict';

var winston = require('winston');
var LastDitch = require('./last_ditch.js');

var singleton = new LastDitch();

// The result of requiring this modules is a method that can be called directly with an
// Error object.
module.exports = singleton.go;

// Make the full class available as well as the singleton's `send` method
module.exports.LastDitch = LastDitch;

// `setupTopLevelHandler` makes it very easy to set up a top-level exception handler.
// Set `options.go` to provide your own `LastDitch` instance's `go()` method, or really
// any other method you'd like called (of the signature `function(err, cb)`)
module.exports.setupTopLevelHandler = function setupTopLevelHandler(options) {
  options = options || {};
  options.go = options.go || singleton.go;

  process.on('uncaughtException', function(err) {
    options.go(err, function() {
      winston.info('Error saved! Exiting...');
      process.exit(1);
    });
  });
};

// index
// ========
// Pulls in everything needed for use via npm.

'use strict';

var LastDitch = require('./last_ditch.js');

var singleton = new LastDitch();

// The result of requiring this modules is a method that can be called directly with an
// Error object.
module.exports = singleton.go;

// Make the full class available as well as the singleton's `send` method
module.exports.LastDitch = LastDitch;

// `setupTopLevelHandler` makes it very easy to set up a top-level exception handler.
// Set `options.go` to provide your own `LastDitch` instance's `go()` method, or really
// any other method you'd like called (of the signature `function(err, cb)`)
module.exports.setupTopLevelHandler = function setupTopLevelHandler(options) {
  options = options || {};
  options.go = options.go || singleton.go;

  process.on('uncaughtException', function(err) {
    options.go(err, function() {
      process.exit(1);
    });
  });
};

Remove winston log in uncaught exception handler


'use strict';

CKEDITOR.editorConfig = function(config) {
  config.toolbar =
  [
    {
      name: 'styles',
      items : [ 'Format' ]
    },
    {
      name: 'basicstyles',
      items : [ 'Bold','Italic','Strike','-','RemoveFormat' ]
    },
    {
      name: 'paragraph',
      items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-' ]
    },
    {
      name: 'links',
      items : [ 'Link','Unlink' ]
    }
  ];
};

CKEDITOR.editorConfig = function (config) {
  config.toolbar =
  [
    {
      name: 'styles',
      items: ['Format']
    },
    {
      name: 'basicstyles',
      items: ['Bold', 'Italic', 'Strike', '-', 'RemoveFormat']
    },
    {
      name: 'paragraph',
      items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-']
    },
    {
      name: 'links',
      items: ['Link', 'Unlink']
    },
    {
      name: 'insert',
      items: ['Image']
    }
  ]
}

Enable insert image in wysiwyg editor


"use strict";

angular.module('arethusa.core').service('languageSettings', [
  'documentStore',
  function(documentStore) {
    var self = this;

    this.languageSpecifics = {
      'ara' : {
        name: 'Arabic',
        lang: 'ar',
        leftToRight: false,
        font: 'Amiri'
      },
      'grc' : {
        name: 'Greek',
        lang: 'gr',
        leftToRight: true
      }
    };

    this.langNames = arethusaUtil.inject({}, self.languageSpecifics, function(memo, code, obj) {
      memo[obj.lang] = obj.name;
    });

    this.getFor = function(documentName) {
      var document = documentStore.store[documentName];
      if (document === undefined) {
        return undefined;
      }

      var lang = document.json.treebank["_xml:lang"];
      if (lang in this.languageSpecifics) {
        return this.languageSpecifics[lang];
      }

      return undefined;
    };
  }
]);

"use strict";

angular.module('arethusa.core').service('languageSettings', [
  'documentStore',
  function(documentStore) {
    var self = this;

    this.languageSpecifics = {
      'ara' : {
        name: 'Arabic',
        lang: 'ar',
        leftToRight: false,
        font: 'Amiri'
      },
      'grc' : {
        name: 'Greek',
        lang: 'gr',
        leftToRight: true
      },
      'heb' : {
        name: 'Hebrew',
        lang: 'he',
        leftToRight: false
      }
    };

    this.langNames = arethusaUtil.inject({}, self.languageSpecifics, function(memo, code, obj) {
      memo[obj.lang] = obj.name;
    });

    var settings = {};
    this.setFor = function(documentName, lang) {
      settings[documentName] = self.languageSpecifics[lang];
    };

    this.getFor = function(documentName) {
      var cached = settings[documentName];
      if (cached) {
        return cached;
      } else {
        var document = documentStore.store[documentName];
        if (document === undefined) {
          return undefined;
        }

        var lang = document.json.treebank["_xml:lang"];
        if (lang in self.languageSpecifics) {
          var langObj = self.languageSpecifics[lang];
          self.setFor('treebank', langObj);
          return langObj;
        }

        return undefined;
      }
    };
  }
]);

Refactor languageSettings and add Hebrew


module.exports = {
  afterInstall: function () {
    const packagesToRemove = [
      'ember-frost-button',
      'ember-frost-checkbox',
      'ember-frost-css-core',
      'ember-frost-icons',
      'ember-frost-link',
      'ember-frost-loading',
      'ember-frost-password',
      'ember-frost-select',
      'ember-frost-text',
      'ember-frost-textarea',
      'ember-frost-theme'
    ].map((packageName) => {
      return {name: packageName}
    })

    return this.removePackagesFromProject(packagesToRemove)
      .then(() => {
        return this.addBowerPackagesToProject([
          {name: 'lodash', target: '^4.10.0'}
        ])
      })
      .then(() => {
        return this.addAddonsToProject({
          packages: [
            {name: 'ember-computed-decorators', target: '>=0.2.2 <2.0.0'},
            {name: 'ember-lodash', target: '>=0.0.6 <2.0.0'},
            {name: 'ember-one-way-controls', target: '>=0.5.3 <2.0.0'}
          ]
        })
      })
  },

  normalizeEntityName: function () {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  }
}

module.exports = {
  afterInstall: function () {
    const packagesToRemove = [
      'ember-frost-button',
      'ember-frost-checkbox',
      'ember-frost-css-core',
      'ember-frost-icons',
      'ember-frost-link',
      'ember-frost-loading',
      'ember-frost-password',
      'ember-frost-select',
      'ember-frost-text',
      'ember-frost-textarea',
      'ember-frost-theme'
    ].map((packageName) => {
      return {name: packageName}
    })

    return this.removePackagesFromProject(packagesToRemove)
      .then(() => {
        return this.addBowerPackagesToProject([
          {name: 'lodash', target: '^4.10.0'},
          {name: 'perfect-scrollbar', target: '>=0.6.7 <2.0.0'}
        ])
      })
      .then(() => {
        return this.addAddonsToProject({
          packages: [
            {name: 'ember-computed-decorators', target: '>=0.2.2 <2.0.0'},
            {name: 'ember-lodash', target: '>=0.0.6 <2.0.0'},
            {name: 'ember-one-way-controls', target: '>=0.5.3 <2.0.0'}
          ]
        })
      })
  },

  normalizeEntityName: function () {
    // this prevents an error when the entityName is
    // not specified (since that doesn't actually matter
    // to us
  }
}

Fix blueprints to include perfect-scrollbar


const { GettextExtractor, JsExtractors } = require('gettext-extractor');

const extractor = new GettextExtractor();

extractor
  .createJsParser([
    JsExtractors.callExpression('gettext', {
      arguments: {
        text: 0,
        context: 1,
      },
    }),
    JsExtractors.callExpression('gettext_noop', {
      arguments: {
        text: 0,
        context: 1,
      },
    }),
    JsExtractors.callExpression('ngettext', {
      arguments: {
        text: 1,
        textPlural: 2,
        context: 3,
      },
    }),
  ])
  .parseFilesGlob('./src/**/*.@(ts|js|tsx)');

extractor.savePotFile('../wagtail/admin/locale/en/LC_MESSAGES/djangojs.po');

extractor.printStats();

const { GettextExtractor, JsExtractors } = require('gettext-extractor');

const extractor = new GettextExtractor();

extractor
  .createJsParser([
    JsExtractors.callExpression('gettext', {
      arguments: {
        text: 0,
        context: 1,
      },
    }),
    JsExtractors.callExpression('gettext_noop', {
      arguments: {
        text: 0,
        context: 1,
      },
    }),
    JsExtractors.callExpression('ngettext', {
      arguments: {
        text: 0,
        textPlural: 1,
        context: 3,
      },
    }),
  ])
  .parseFilesGlob('./src/**/*.@(ts|js|tsx)');

extractor.savePotFile('../wagtail/admin/locale/en/LC_MESSAGES/djangojs.po');

extractor.printStats();

Fix JS string extraction for ngettext


'use strict';
const fs = require('fs');
const _ = require('lodash');
const legalityChecks = fs.readdirSync(`${__dirname}/checks`)
  .filter(filename => filename.endsWith('.js'))
  .map(filename => require(`./checks/${filename}`));

module.exports = pkmn => {
  const failedCheck = legalityChecks.filter(check => matchesFilter(pkmn, check.filter)).find(check => !check.test(pkmn));
  return failedCheck ? {isLegal: false, reason: failedCheck.description} : {isLegal: true, reason: null};
};

function matchesFilter (pkmn, filter) {
  if (typeof filter === 'function') return filter(pkmn);
  if (typeof filter === 'object') return _.matches(filter)(pkmn);
  return true;
}

'use strict';
const fs = require('fs');
const _ = require('lodash');
const legalityChecks = fs.readdirSync(`${__dirname}/checks`)
  .filter(filename => filename.endsWith('.js'))
  .map(filename => {
    const check = require(`./checks/${filename}`);
    if (!_.isFunction(check.test)) throw new TypeError(`The check ${filename} is missing a 'test' function property`);
    if (!_.isString(check.description)) throw new TypeError(`The check ${filename} is missing a 'description' string property`);
    return check;
  });

module.exports = pkmn => {
  const failedCheck = legalityChecks.filter(check => matchesFilter(pkmn, check.filter)).find(check => !check.test(pkmn));
  return failedCheck ? {isLegal: false, reason: failedCheck.description} : {isLegal: true, reason: null};
};

function matchesFilter (pkmn, filter) {
  if (typeof filter === 'function') return filter(pkmn);
  if (typeof filter === 'object') return _.matches(filter)(pkmn);
  return true;
}

Throw an error if a check is missing a test or description


// Samesound Angular Application.
// Defines the main module of the application.

'use strict';

var samesoundApp = angular
    .module('samesoundApp', ['ngResource', 'ngRoute', 'ui.router', 'ngAnimate'])
    .config(['$locationProvider', function ($locationProvider) {
        //$locationProvider.html5Mode(true);
        //$locationProvider.hashPrefix('#');
    }])
    .constant('config', {
        apiUrl: 'https://localhost:44300/api/'
    });

// Samesound Angular Application.
// Defines the main module of the application.

'use strict';

var samesoundApp = angular
    .module('samesoundApp', ['ngResource', 'ngRoute', 'ui.router', 'ngAnimate'])
    .config(['$locationProvider', function ($locationProvider) {
        //$locationProvider.html5Mode(true);
        //$locationProvider.hashPrefix('#');
    }])
    .constant('config', {
        apiUrl: '/api/'
    });

Fix apiUrl issue when deployed to azure


/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';
import React, {
  AppRegistry,
  Component,
  StyleSheet,
  Text,
  View
} from 'react-native';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './app/reducers/rootReducer.js';
import ViewContainer from './app/containers/container_viewContainer';
import Menu from './app/components/Menu.js';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import promise from 'redux-promise';
const SideMenu = require('react-native-side-menu');

//creates logger
const logger = createLogger();
// creates store
const store = createStore(
  rootReducer,
  applyMiddleware(thunk, promise, logger)
);

class findAR extends Component {

  constructor() {
    super();
  }

  onMenuItemSelected () {
    return '';
  }
  render() {
    const menu = <Menu onItemSelected={this.onMenuItemSelected} navigator={navigator}/>;
    return (
      <Provider store={store}>
        <SideMenu menu={menu}>
          <ViewContainer >
          </ViewContainer>
        </SideMenu>
      </Provider>
    );
  }
}

AppRegistry.registerComponent('findAR', () => findAR);

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict';
import React, {
  AppRegistry,
  Component,
  StyleSheet,
  Text,
  View
} from 'react-native';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './app/reducers/rootReducer.js';
import ViewContainer from './app/containers/container_viewContainer';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import promise from 'redux-promise';

//creates logger
const logger = createLogger();
// creates store
const store = createStore(
  rootReducer,
  applyMiddleware(thunk, promise, logger)
);

const findAR = () => (
  <Provider store={store}>
    <ViewContainer />
  </Provider>
);

AppRegistry.registerComponent('findAR', () => findAR);

Remove SideMenu from app root


import HomeModule from './home';

describe('HomeModule', function() {
  let element, scope;

  beforeEach(angular.mock.module('app.home'));

  beforeEach(angular.mock.inject(($rootScope, $compile) => {
    scope = $rootScope.$new();
    element = angular.element('<home></home>');
    element = $compile(element)(scope);
    $rootScope.$digest();
  }));

  it('should render into a home-container div', () => {
    expect(element.find('div.home-container').length).to.equal(1);
  });

  it('should have a controller with a name property', () => {
    expect(element.isolateScope().$ctrl).to.exist;
  });

  // this is not a meaningful test - it's serving as an example for now
  it('should update its name if the name is updated', () => {
    element.isolateScope().$ctrl.name = 'Hello world';
    element.isolateScope().$apply();
    expect(element.find('h1').text()).to.equal('Hello world');
  });
});

describe('HomeController', function() {
  let HomeController;

  beforeEach(angular.mock.module('app.home'));
  beforeEach(angular.mock.inject(($componentController) => {
    HomeController = $componentController('home', null, {});
  }));

  it ('should be a component called home with a name property', () => {
    expect(HomeController).to.exist;
  });

});

import HomeModule from './home';

describe('HomeModule', function() {
  let element, scope;

  beforeEach(angular.mock.module('app.home'));

  beforeEach(angular.mock.inject(($rootScope, $compile, $httpBackend) => {

    $httpBackend.whenGET("/api/plan/").respond([]);

    scope = $rootScope.$new();
    element = angular.element('<home></home>');
    element = $compile(element)(scope);
    $rootScope.$digest();
  }));

  it('should render into a home-container div', () => {
    expect(element.find('div.home-container').length).to.exist;
  });

  it('should have a controller', () => {
    expect(element.isolateScope().$ctrl).to.exist;
  });

  // this is not a meaningful test - it's serving as an example for now
  it('should update its name if the name is updated', () => {
    element.isolateScope().$ctrl.name = '';
    element.isolateScope().$apply();
    expect(element.find('h1').text()).to.equal('');
  });
});

describe('HomeController', function() {
  let HomeController;

  beforeEach(angular.mock.module('app.home'));
  beforeEach(angular.mock.inject(($componentController) => {
    HomeController = $componentController('home', null, {});
  }));

  it ('should exist', () => {
    expect(HomeController).to.exist;
  });

});

Fix bug with http causing test failure


var forEachEls = require("../foreach-els")

module.exports = function(els, events) {
  events = (typeof events === "string" ? events.split(" ") : events)

  events.forEach(function(e) {
    var event
    if (document.createEvent) {
      event = document.createEvent("HTMLEvents")
      event.initEvent(e, true, true)
    }
    else {
      event = document.createEventObject()
      event.eventType = e
    }

    event.eventName = e

    if (document.createEvent) {
      forEachEls(els, function(el) {
        el.dispatchEvent(event)
      })
    }
    else {
      forEachEls(els, function(el) {
        el.fireEvent("on" + event.eventType, event)
      })
    }
  })
}

var forEachEls = require("../foreach-els")

module.exports = function(els, events) {
  events = (typeof events === "string" ? events.split(" ") : events)

  events.forEach(function(e) {
    var event // = new CustomEvent(e) // doesn't everywhere yet
    event = document.createEvent("HTMLEvents")
    event.initEvent(e, true, true)
    event.eventName = e

    forEachEls(els, function(el) {
      el.dispatchEvent(event)
    })
  })
}

Drop fireEvent since we are supporting IE10


var _paramanders$elm_twitch_chat$Native_Jsonp = function() {

  function jsonp(url, callbackName)
  {

    return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) {
      window[callbackName] = function(content)
      {
        callback(_elm_lang$core$Native_Scheduler.succeed(JSON.stringify(content)));
      };

      var scriptTag = createScript(url, callbackName);
      document.head.appendChild(scriptTag);
      document.head.removeChild(scriptTag);
    });
  }

  function createScript(url, callbackName)
  {
    var s = document.createElement('script');
    s.type = 'text/javascript';

    if (url.indexOf('?') >= 0)
    {
      s.src = url + '&callback=' + callbackName;
    }
    else {
      s.src = url + '?callback=' + callbackName;
    }

    return s;
  }

  return {
    jsonp: F2(jsonp)
  };

}();

var _paramanders$elm_twitch_chat$Native_Jsonp = function() {

  function jsonp(url, callbackName)
  {
    return _elm_lang$core$Native_Scheduler.nativeBinding(function(callback) {
      window[callbackName] = function(content)
      {
        callback(_elm_lang$core$Native_Scheduler.succeed(JSON.stringify(content)));
        delete window[callbackName];
      };

      var scriptTag = createScript(url, callbackName);
      document.head.appendChild(scriptTag);
      document.head.removeChild(scriptTag);
    });
  }

  function createScript(url, callbackName)
  {
    var s = document.createElement('script');
    s.type = 'text/javascript';

    if (url.indexOf('?') >= 0)
    {
      s.src = url + '&callback=' + callbackName;
    }
    else {
      s.src = url + '?callback=' + callbackName;
    }

    return s;
  }

  return {
    jsonp: F2(jsonp)
  };

}();

Remove JSONP callback function once done


import assert  from 'assert';
import Answers from '../../src/es6/04-Quiz.js';

describe("04 - Quiz", () => {
  it("Question #1", () => {
    assert.equal(Answers.answer1, "React.Component", "Check the line that contains `extends` word.")
  });

  it("Question #2", () => {
    assert.equal(Answers.answer2, true, "It's not HTML (as we said in exercises 1 and 2, so what is it?");
  });

  it("Question #3", () => {
    assert.equal(Answers.answer3, 'render', "In every component we did create there was one method with HTML-like looking code (JSX). What was that method?");
  });

  it("question #4", () => {
    assert.equal(Answers.answer4, 'className', "`class` is a reserved word in JavaScript. See exercise 2.");
  });

  it("Question #5", () => {
    assert.equal(Answers.answer5, false, "See the comments in exercise #3");
  });

  it("Question #6", () => {
    assert.equal(Answers.answer6, 'setState', "See the `onNameChange` method from exercise #3");
  });

  it("Question #7", () => {
    assert.equal(Answers.answer7, true, "I'll make it easier for you: yes you have. Why? See exercise #3! It's very important.");
  });
});

import assert  from 'assert';
import Answers from '../../src/es6/04-Quiz.js';

describe("04 - Quiz", () => {
  it("Question #1", () => {
    assert.equal(Answers.answer1 === "React.Component", true, "Check the line that contains `extends` word.")
  });

  it("Question #2", () => {
    assert.equal(Answers.answer2, true, "It's not HTML (as we said in exercises 1 and 2, so what is it?");
  });

  it("Question #3", () => {
    assert.equal(Answers.answer3 === 'render', true, "In every component we did create there was one method with HTML-like looking code (JSX). What was that method?");
  });

  it("question #4", () => {
    assert.equal(Answers.answer4 === 'className', true, "`class` is a reserved word in JavaScript. See exercise 2.");
  });

  it("Question #5", () => {
    assert.equal(Answers.answer5, false, "See the comments in exercise #3");
  });

  it("Question #6", () => {
    assert.equal(Answers.answer6 === 'setState', true, "See the `onNameChange` method from exercise #3");
  });

  it("Question #7", () => {
    assert.equal(Answers.answer7, true, "I'll make it easier for you: yes you have. Why? See exercise #3! It's very important.");
  });
});

Improve quiz's test to not show answers in string diffs.


var gulp = require('gulp'),
  babel = require('babelify'),
  browserify = require('browserify'),
  buffer = require('vinyl-buffer'),
  source = require('vinyl-source-stream'),
  sourcemaps = require('gulp-sourcemaps');

gulp.task('scripts.bundle', function () {
  return browserify("./source/index.js")
    .transform(babel)
    .bundle()
    .pipe(source('keensole.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init())
    .pipe(sourcemaps.write())
    .pipe(gulp.dest('./dist'));
});

gulp.task('build', ['scripts.bundle']);

var gulp      = require('gulp'),
  babel       = require('babelify'),
  browserify  = require('browserify'),
  buffer      = require('vinyl-buffer'),
  source      = require('vinyl-source-stream'),
  sourcemaps  = require('gulp-sourcemaps');

gulp
  // Transform ES6 Modules to ES5 and Bundle <keensole 👨💻>
  .task('scripts.bundle', function () {
    return browserify("./source/index.js")
      .transform(babel)
      .bundle()
      .pipe(source('keensole.js'))
      .pipe(buffer())
      .pipe(sourcemaps.init())
      .pipe(sourcemaps.write())
      .pipe(gulp.dest('./dist'));
  })

  .task('build', ['scripts.bundle'])

  .task('deafult', ['build']);

Add default task to gulp file 🤷


/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    contentSecurityPolicy: {
      'img-src': "'self' data:",
      'media-src': "'self' http://vjs.zencdn.net"
    },
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

Fix Content-Security-Policy warnings in the dummy app.


  easyXDM = window.easyXDM.noConflict();
  delete window['easyXDM'];

  return easyXDM;
});

  easyXDM = window.easyXDM.noConflict();
  return easyXDM;
});

Fix bug with delete on IE8


// To remove expired alerts from the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.remove({'status': 'CLOSED'});
db.alerts.remove({'expireTime': { $lt: now }});

// To remove expired alerts from the alerta database run this script from cron like so:
// * * * * * /usr/bin/mongo --quiet monitoring /opt/alerta/sbin/removeExpiredAlerts.js
now = new Date();
db.alerts.remove({ 'status': 'CLOSED', 'expireTime': { $lt: now }});

Rollback remove expired OR closed alerts


var crypto = require('crypto')
var fs = require('fs')
var path = require('path')

var fingerprintPath = path.resolve(__dirname, '..', '..', 'node_modules', '.atom-ci-fingerprint')

module.exports = {
  fingerprint: function () {
    var packageJson = fs.readFileSync(path.resolve(__dirname, '..', '..', 'package.json'))
    var body = packageJson.toString() + process.platform
    return crypto.createHash('sha1').update(body).digest('hex')
  },

  writeFingerprint: function () {
    var fingerprint = this.fingerprint()
    fs.writeFileSync(fingerprintPath, fingerprint)
    console.log('Wrote ci fingerprint:', fingerprintPath, fingerprint)
  }

  readFingerprint: function() {
    if (fs.existsSync(fingerprintPath)) {
      return fs.readFileSync(fingerprintPath).toString()
    } else {
      return null
    }
  }

  fingerprintMatches: function () {
    return this.readFingerprint() && this.readFingerprint() === this.fingerprint()
  }
}

var crypto = require('crypto')
var fs = require('fs')
var path = require('path')

var fingerprintPath = path.resolve(__dirname, '..', '..', 'node_modules', '.atom-ci-fingerprint')

module.exports = {
  fingerprint: function () {
    var packageJson = fs.readFileSync(path.resolve(__dirname, '..', '..', 'package.json'))
    var body = packageJson.toString() + process.platform
    return crypto.createHash('sha1').update(body).digest('hex')
  },

  writeFingerprint: function () {
    var fingerprint = this.fingerprint()
    fs.writeFileSync(fingerprintPath, fingerprint)
    console.log('Wrote ci fingerprint:', fingerprintPath, fingerprint)
  },

  readFingerprint: function() {
    if (fs.existsSync(fingerprintPath)) {
      return fs.readFileSync(fingerprintPath).toString()
    } else {
      return null
    }
  },

  fingerprintMatches: function () {
    return this.readFingerprint() && this.readFingerprint() === this.fingerprint()
  }
}

Add a couple missing commas


(function (window) {
	'use strict';

	var HearingTest = Object.create(null);
	var context = new window.AudioContext();

	HearingTest.init = function init(frequency) {
		frequency = frequency || 440;

		var sound = this.createSound();
		sound.frequency.value = frequency;
		this.connect(sound);

		this.sound = sound;

		return sound;
	};

	HearingTest.createSound = function createSound() {
		return context.createOscillator();
	};

	HearingTest.connect = function connect(sound) {
		return sound.connect(context.destination);
	};

	HearingTest.playSound = function playSound(delay) {
		delay = delay || 0;
		this.sound.start(delay);
	};

	HearingTest.stopSound = function stopSound(delay) {
		delay = delay || 0;
		this.sound.stop(delay);
	};

	window.HearingTest = HearingTest;
}(window));

(function (exports) {
	'use strict';

	var HearingTest = Object.create(null);
	var context = new window.AudioContext();

	HearingTest.init = function init(frequency) {
		frequency = frequency || 440;

		var sound = this.createSound();
		sound.frequency.value = frequency;
		this.connect(sound);

		this.sound = sound;

		return sound;
	};

	HearingTest.createSound = function createSound() {
		return context.createOscillator();
	};

	HearingTest.connect = function connect(sound) {
		return sound.connect(context.destination);
	};

	HearingTest.playSound = function playSound(delay) {
		delay = delay || 0;
		this.sound.start(delay);
	};

	HearingTest.stopSound = function stopSound(delay) {
		delay = delay || 0;
		this.sound.stop(delay);
	};

	exports.HearingTest = HearingTest;
}(window));

Replace argument name window -> exports


const fse = require("fs-extra");

const findUpdatedFiles = (
  sourceFilesArtifacts,
  sourceFilesArtifactsUpdatedTimes
) => {
  let updatedFiles = [];
  // Stat all the source files, getting there updated times, and comparing them to
  // the artifact updated times.
  const sourceFiles = Object.keys(sourceFilesArtifacts);

  let sourceFileStats;
  sourceFileStats = sourceFiles.map(file => {
    try {
      return fse.statSync(file);
    } catch (error) {
      // Ignore it. This means the source file was removed
      // but the artifact file possibly exists. Return null
      // to signfy that we should ignore it.
      return null;
    }
  });

  sourceFiles.forEach((sourceFile, index) => {
    const sourceFileStat = sourceFileStats[index];

    // Ignore updating artifacts if source file has been removed.
    if (sourceFileStat == null) return;

    const artifactsUpdatedTime =
      sourceFilesArtifactsUpdatedTimes[sourceFile] || 0;
    const sourceFileUpdatedTime = (
      sourceFileStat.mtime || sourceFileStat.ctime
    ).getTime();

    if (sourceFileUpdatedTime > artifactsUpdatedTime) {
      updatedFiles.push(sourceFile);
    }
  });
  return updatedFiles;
};

module.exports = {
  findUpdatedFiles
};

const fse = require("fs-extra");

const findUpdatedFiles = (
  sourceFilesArtifacts,
  sourceFilesArtifactsUpdatedTimes
) => {
  // Stat all the source files, getting there updated times, and comparing them to
  // the artifact updated times.
  const sourceFiles = Object.keys(sourceFilesArtifacts);

  let sourceFileStats;
  sourceFileStats = sourceFiles.map(file => {
    try {
      return fse.statSync(file);
    } catch (error) {
      // Ignore it. This means the source file was removed
      // but the artifact file possibly exists. Return null
      // to signfy that we should ignore it.
      return null;
    }
  });

  return sourceFiles
    .map((sourceFile, index) => {
      const sourceFileStat = sourceFileStats[index];

      // Ignore updating artifacts if source file has been removed.
      if (sourceFileStat == null) return;

      const artifactsUpdatedTime =
        sourceFilesArtifactsUpdatedTimes[sourceFile] || 0;
      const sourceFileUpdatedTime = (
        sourceFileStat.mtime || sourceFileStat.ctime
      ).getTime();

      if (sourceFileUpdatedTime > artifactsUpdatedTime) return sourceFile;
    })
    .filter(file => file);
};

module.exports = {
  findUpdatedFiles
};

Change forEach to use map instead


const mongoose = require('mongoose');
const logger = require('../logging');

const DB_URL = process.env.SDF_DATABASE_URL;
const DB_NAME = process.env.SDF_DATABASE_NAME || 'sdf';

const DB_CONN_STR = DB_URL || `mongodb://localhost/${DB_NAME}`;

// connecting to db

console.log(`Connecting to mongodb using '${DB_CONN_STR}'`);
mongoose.Promise = global.Promise;
mongoose.connect(DB_CONN_STR);

const db = mongoose.connection;
db.on('error', (err) => {
  logger.error('Could not connect to database.', { err });
});

const mongoose = require('mongoose');
const logger = require('../logging');

const DB_URL = process.env.SDF_DATABASE_URL;
const DB_NAME = process.env.SDF_DATABASE_NAME || 'sdf';

const DB_CONN_STR = DB_URL || `mongodb://localhost/${DB_NAME}`;

// connecting to db

logger.info(`Connecting to mongodb using '${DB_CONN_STR}'`);
mongoose.Promise = global.Promise;
mongoose.connect(DB_CONN_STR);

const db = mongoose.connection;
db.on('error', (err) => {
  logger.error('Could not connect to database.', { err });
});

Use logger for db connection


'use strict';

const fs = require('fs');

const AbstractReader = require('./abstract-reader');

class FileReader extends AbstractReader {

    constructor(fd) {
        super();
        this.buffer = fd;
    }

    size() {
        return fs.fstatSync(this.buffer).size;
    }

    read(buffer, offset) {
        return fs.readSync(this.buffer, buffer, 0, buffer.length, offset);
    }

}

module.exports = FileReader;

'use strict';

const fs = require('fs');

const AbstractReader = require('./abstract-reader');

class FileReader extends AbstractReader {

    constructor(fd) {
        super();
        this.fd = fd;
    }

    size() {
        return fs.fstatSync(this.fd).size;
    }

    read(buffer, offset) {
        return fs.readSync(this.fd, buffer, 0, buffer.length, offset);
    }

}

module.exports = FileReader;

Rename buffer to fd in FileReader


import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import immutableStateInvariant from 'redux-immutable-state-invariant'

import isPlainObject from './isPlainObject'

const IS_PRODUCTION = process.env.NODE_ENV === 'production'

export function getDefaultMiddleware(isProduction = IS_PRODUCTION) {
  const middlewareArray = [thunk]

  if (!isProduction) {
    middlewareArray.unshift(immutableStateInvariant())
  }

  return middlewareArray
}

export function configureStore(options = {}) {
  const {
    reducer,
    middleware = getDefaultMiddleware(),
    devTools = true,
    preloadedState,
    enhancers = []
  } = options

  let rootReducer

  if (typeof reducer === 'function') {
    rootReducer = reducer
  } else if (isPlainObject(reducer)) {
    rootReducer = combineReducers(reducer)
  } else {
    throw new Error(
      'Reducer argument must be a function or an object of functions that can be passed to combineReducers'
    )
  }

  const middlewareEnhancer = applyMiddleware(...middleware)

  const storeEnhancers = [middlewareEnhancer, ...enhancers]

  let finalCompose = devTools ? composeWithDevTools : compose

  const composedEnhancer = finalCompose(...storeEnhancers)

  const store = createStore(rootReducer, preloadedState, composedEnhancer)

  return store
}

import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import createImmutableStateInvariantMiddleware from 'redux-immutable-state-invariant'
import createSerializableStateInvariantMiddleware from './serializableStateInvariantMiddleware'

import isPlainObject from './isPlainObject'

const IS_PRODUCTION = process.env.NODE_ENV === 'production'

export function getDefaultMiddleware(isProduction = IS_PRODUCTION) {
  let middlewareArray = [thunk]

  if (!isProduction) {
    middlewareArray = [
      createImmutableStateInvariantMiddleware(),
      thunk,
      createSerializableStateInvariantMiddleware()
    ]
  }

  return middlewareArray
}

export function configureStore(options = {}) {
  const {
    reducer,
    middleware = getDefaultMiddleware(),
    devTools = true,
    preloadedState,
    enhancers = []
  } = options

  let rootReducer

  if (typeof reducer === 'function') {
    rootReducer = reducer
  } else if (isPlainObject(reducer)) {
    rootReducer = combineReducers(reducer)
  } else {
    throw new Error(
      'Reducer argument must be a function or an object of functions that can be passed to combineReducers'
    )
  }

  const middlewareEnhancer = applyMiddleware(...middleware)

  const storeEnhancers = [middlewareEnhancer, ...enhancers]

  let finalCompose = devTools ? composeWithDevTools : compose

  const composedEnhancer = finalCompose(...storeEnhancers)

  const store = createStore(rootReducer, preloadedState, composedEnhancer)

  return store
}

Add serializable state middleware by default


// Install ES2015-complaint polyfills for Object, Array, String, Function,
// Symbol, Map, and Set, patching the native implementations if available.
require("meteor-ecmascript-runtime");

// Install a global ES2015-compliant Promise constructor that knows how to
// run all its callbacks in Fibers.
var Promise = global.Promise = global.Promise ||
  require("promise/lib/es6-extensions");
require("meteor-promise").makeCompatible(Promise, require("fibers"));

// Verify that the babel-runtime package is available to be required.
// The .join("/") prevents babel-plugin-transform-runtime from
// "intelligently" converting this to an import statement.
var regenerator = require([
  "babel-runtime",
  "regenerator"
].join("/")).default;

// Use Promise.asyncApply to wrap calls to runtime.async so that the
// entire async function will run in its own Fiber, not just the code that
// comes after the first await.
var realAsync = regenerator.async;
regenerator.async = function () {
  return Promise.asyncApply(realAsync, regenerator, arguments);
};

// Install global.meteorBabelHelpers so that the compiler doesn't need to
// add boilerplate at the top of every file.
require("meteor-babel").defineHelpers();

// Installs source map support with a hook to add functions to look for
// source maps in custom places.
require('./source-map-retriever-stack.js');

// Install ES2015-complaint polyfills for Object, Array, String, Function,
// Symbol, Map, and Set, patching the native implementations if available.
require("meteor-ecmascript-runtime");

// Install a global ES2015-compliant Promise constructor that knows how to
// run all its callbacks in Fibers.
var Promise = global.Promise = global.Promise ||
  require("promise/lib/es6-extensions");
require("meteor-promise").makeCompatible(Promise, require("fibers"));

// Verify that the babel-runtime package is available to be required.
// The .join("/") prevents babel-plugin-transform-runtime from
// "intelligently" converting this to an import statement.
var regenerator = require([
  "babel-runtime",
  "regenerator"
].join("/"));

// Use Promise.asyncApply to wrap calls to runtime.async so that the
// entire async function will run in its own Fiber, not just the code that
// comes after the first await.
var realAsync = regenerator.async;
regenerator.async = function () {
  return Promise.asyncApply(realAsync, regenerator, arguments);
};

// Install global.meteorBabelHelpers so that the compiler doesn't need to
// add boilerplate at the top of every file.
require("meteor-babel").defineHelpers();

// Installs source map support with a hook to add functions to look for
// source maps in custom places.
require('./source-map-retriever-stack.js');

Fix babel-runtime/regenerator import in tools runtime setup.


let auth = require('./auth');
let express = require('express');
let router = express.Router();
let passport = require('passport');

router.post('/login', function(req, res, next) {
    passport.authenticate(req.body.strategy || 'local', function(err, user) {
        if (err || !user) {
            let errorResponse = { err: err };
            if (err.message) {
                errorResponse.message = err.message;
            }
            res.statusCode = 401;
            res.json(errorResponse);
            return;
        }
        req.logIn(user, function(err) {
            if (err) {
                return next(err);
            }
            res.json(user.toObject());
        });
    })(req, res, next);
});

router.post('/logout', function (req, res, next) {
    req.session.destroy();
    res.json({
        status: 'success'
    });
});

router.get('/verify', function (req, res, next) {
    if (!req.isAuthenticated()) {
        res.statusCode = 401;
        res.end();
        return;
    }
    res.json(req.user.toObject());
});

module.exports = router;

/**
 * Copyright © 2017 Highpine. All rights reserved.
 *
 * @author    Max Gopey <gopeyx@gmail.com>
 * @copyright 2017 Highpine
 * @license   https://opensource.org/licenses/MIT  MIT License
 */

let express = require('express');
let router = express.Router();
let passport = require('passport');

router.post('/login', function(req, res, next) {
    passport.authenticate(req.body.strategy || 'local', function(err, user) {
        if (err || !user) {
            let errorResponse = { err: err };
            if (err.message) {
                errorResponse.message = err.message;
            }
            res.statusCode = 401;
            res.json(errorResponse);
            return;
        }
        req.logIn(user, function(err) {
            if (err) {
                return next(err);
            }
            res.json(user.toObject());
        });
    })(req, res, next);
});

router.post('/logout', function (req, res, next) {
    req.session.regenerate(err => {
        if (err) {
            return next(err);
        }
        res.json({
            status: 'success'
        });
    });
});

router.get('/verify', function (req, res, next) {
    if (!req.isAuthenticated()) {
        res.statusCode = 401;
        res.end();
        return;
    }
    res.json(req.user.toObject());
});

module.exports = router;

Fix / improve session handling on logout.


"use strict";

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

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

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

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

        // Create the error
        super(error);

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

"use strict";

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

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

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

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

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

        // Create the error
        super(error);

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

Use barbe to render dynamic fields.


function Sites( api ) {
	this.api = api;
}

Sites.prototype.query = function( args ) {
	return new Promise( ( resolve, reject ) => {
		this.api
			.get( '/sites' )
			.query( args )
			.end( ( err, res ) => {
				if ( err ) {
					return reject( err.response.body );
				}

				return resolve( res.body );
			});
	});
}

module.exports = Sites;

function Sites( api ) {
	this.api = api;
}

Sites.prototype.query = function( args ) {
	return new Promise( ( resolve, reject ) => {
		this.api
			.get( '/sites' )
			.query( args )
			.end( ( err, res ) => {
				if ( err ) {
					return reject( err );
				}

				return resolve( res.body );
			});
	});
}

module.exports = Sites;

Return full error object when a request fails


var winston = require('winston'),
    path    = require('path');

var logLevel = 'debug';

var sharedLogger = function(filename) {
  return new winston.Logger({
    transports: [
      new winston.transports.Console({
        prettyPrint: true,
        timestamp: true,
        level: logLevel,
        label: path.basename(filename, '.js')
      })
    ]
  });
};

sharedLogger.setLevel = function (val) {
  logLevel = val;
}

function failedPromiseHandler(logger) {
  logger = logger || sharedLogger;

  return function(err) {
    logger.error(err.stack);
  };
}

function uuid() {
	return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

module.exports = {
  logger: sharedLogger,
  failedPromiseHandler: failedPromiseHandler,
  uuid: uuid
}

var winston = require('winston'),
    path    = require('path');

var logLevel = 'warn';

var sharedLogger = function(filename) {
  return new winston.Logger({
    transports: [
      new winston.transports.Console({
        prettyPrint: true,
        timestamp: true,
        level: logLevel,
        label: path.basename(filename, '.js')
      })
    ]
  });
};

sharedLogger.setLevel = function (val) {
  logLevel = val;
}

function failedPromiseHandler(logger) {
  logger = logger || sharedLogger;

  return function(err) {
    logger.error(err.stack);
  };
}

function uuid() {
	return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
    return v.toString(16);
  });
}

module.exports = {
  logger: sharedLogger,
  failedPromiseHandler: failedPromiseHandler,
  uuid: uuid
}

Set default log level to warn


'use strict';
const path = require('path');
const extract = require('tar').Extract;
const zlib = require('zlib');
const fs = require('fs');

module.exports = function unzipAndExtract(fileName, callback) {
  let p = path.join(process.cwd(), fileName);
  let exx = extract({
    path: process.cwd()
  })
  .on('error', callback)
  .on('end', callback);
  let gunz = zlib.createGunzip();
  fs.createReadStream(p)
  .on('error', callback)
  .pipe(gunz)
  .pipe(exx);
};

'use strict';
const path = require('path');
const extract = require('tar').Extract;
const zlib = require('zlib');
const fs = require('fs');

module.exports = function unzipAndExtract(fileName, callback) {
  let p = path.join(process.cwd(), fileName);
  let exx = extract({
    path: process.cwd()
  })
  .on('error', callback)
  .on('end', callback.bind(null, null, fileName.replace('TAR', '').replace('.tgz', '')));
  let gunz = zlib.createGunzip();
  fs.createReadStream(p)
  .on('error', callback)
  .pipe(gunz)
  .pipe(exx);
};

Make sure we return the filename when finished.


Class Node {
  constructor(d) {
    this.data = d;
    this.next = null
  }
}

Class LinkedList {
  constructor() {
    this.head = null;
    this.size = 0
  }

  reverse(linkList) {
    let current = linkList.head;
    let prev;
    let next;

    while(current) {
      // increment next, point next to current.next node
      next = current.next;
      // set reference/pointer to prev, no longer pointing to current.next/next
      current.next = prev;
      // increment prev, point to current node
      prev = current;
      // increment current, point to next
      current = next;
    }
    // point head to prev which should be the tail, with current null
    linkList.head = prev;

    return linkList;
  }
}

Class Node {
  constructor(d) {
    this.data = d;
    this.next = null
  }
}

Class LinkedList {
  constructor() {
    this.head = null;
    this.size = 0
  }

  reverse() {
    let current = this.head;
    let prev;
    let next;

    while(current) {
      // increment next, point next to current.next node
      next = current.next;
      // set reference/pointer to prev, no longer pointing to current.next/next
      current.next = prev;
      // increment prev, point to current node
      prev = current;
      // increment current, point to next
      current = next;
    }
    // point head to prev which should be the tail, with current null
    this.head = prev;

    return this;
  }
}

Change reference to head within reverse()


/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    async = require('async'),
    Question = mongoose.model('Question'),
    _ = require('underscore');

/**
 * Find question by id
 */
exports.question = function(req, res, next, id) {
    Question.load(id, function(err, question) {
        if (err) return next(err);
        if (!question) return next(new Error('Failed to load question ' + id));
        req.question = question;
        next();
    });
};

/**
 * Show an question
 */
exports.show = function(req, res) {
    res.jsonp(req.question);
};

/**
 * List of Questions
 */
exports.all = function(req, res) {
    Question.find({official:true, numAnswers: {$lt : 3}}).select('-_id').exec(function(err, questions) {
        if (err) {
            res.render('error', {
                status: 500
            });
        } else {
            res.jsonp(questions);
        }
    });
};

/**
 * List of Questions (for Game class)
 */
exports.allQuestionsForGame = function(cb) {
    Question.find({official:true, numAnswers: 2}).select('-_id').exec(function(err, questions) {
        if (err) {
            console.log(err);
        } else {
            cb(questions);
        }
    });
};

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
    async = require('async'),
    Question = mongoose.model('Question'),
    _ = require('underscore');

/**
 * Find question by id
 */
exports.question = function(req, res, next, id) {
    Question.load(id, function(err, question) {
        if (err) return next(err);
        if (!question) return next(new Error('Failed to load question ' + id));
        req.question = question;
        next();
    });
};

/**
 * Show an question
 */
exports.show = function(req, res) {
    res.jsonp(req.question);
};

/**
 * List of Questions
 */
exports.all = function(req, res) {
    Question.find({official:true, numAnswers: {$lt : 3}}).select('-_id').exec(function(err, questions) {
        if (err) {
            res.render('error', {
                status: 500
            });
        } else {
            res.jsonp(questions);
        }
    });
};

/**
 * List of Questions (for Game class)
 */
exports.allQuestionsForGame = function(cb) {
    Question.find({official:true, numAnswers: {$lt : 3}}).select('-_id').exec(function(err, questions) {
        if (err) {
            console.log(err);
        } else {
            cb(questions);
        }
    });
};

Change question back to regular


import NavigationBase from '../navigation/anim-base';

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

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

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

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

import NavigationBase from '../navigation/anim-base';

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

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

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

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

Disable Parallax3D on navigation page


angular.module('resourceSolver', [])
.provider('resourceSolver', function ResourceSolver() {
  var baseUrl = '';

  this.setBaseUrl = function(url) {
    baseUrl = url;
  };

  this.$get = function() {

    return {
      getBaseUrl: function() {
        return baseUrl;
      }
    };
  };
}).run(function($rootScope, $state) {

  $rootScope.$on('$stateChangeStart', function(event, state, params) {
    $state.next = state;
    $state.nextParams = params;
  });
})
.constant('rs', function(res) {

  function Solver($resource, resourceSolver, $state) {
    var baseUrl = resourceSolver.getBaseUrl();
    var action = res.action || 'get';

    return $resource(baseUrl+res.url, $state.nextParams)[action]().$promise;
  };

  return ['$resource', 'resourceSolver', '$state', Solver];
});

angular.module('resourceSolver', ['ui.router'])
.provider('resourceSolver', function ResourceSolver() {
  var baseUrl = '';

  this.setBaseUrl = function(url) {
    baseUrl = url;
  };

  this.$get = function() {

    return {
      getBaseUrl: function() {
        return baseUrl;
      }
    };
  };
}).config(['$provide', function($provide) {

  $provide.decorator("$state", function($delegate, $rootScope) {
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
      $delegate.next = toState;
      $delegate.nextParams = toParams;
    });
    return $delegate;
  });

}])
.constant('rs', function(res) {

  function Solver($resource, resourceSolver, $state) {
    var baseUrl = resourceSolver.getBaseUrl();
    var action = res.action || 'get';

    return $resource(baseUrl+res.url, $state.nextParams)[action]().$promise;
  };

  return ['$resource', 'resourceSolver', '$state', Solver];
});

Refactor run configuration into decorator


'use strict';

var memoize      = require('memoizee/lib/primitive')
  , Fragment     = require('dbjs-fragment')
  , objFragment  = require('dbjs-fragment/object-family')

  , getId = function (obj) { return obj.__id__; };

module.exports = function (set, meta, fragment) {
	var getFragment, onAdd;

	if (!fragment) fragment = new Fragment();
	getFragment = memoize(function (obj) {
		return objFragment(obj, meta);
	}, { serialize: getId });

	set.forEach(onAdd = function (obj) {
		fragment.sets.add(getFragment(obj));
	});

	set.on('change', function (event) {
		if (event.type === 'add') {
			onAdd(event.value);
			return;
		}
		if (event.type === 'delete') {
			fragment.sets.delete(getFragment(event.value));
			return;
		}
		throw new TypeError("Unsupported event: " + event.type);
	});
	return fragment;
};

'use strict';

var memoize      = require('memoizee/lib/primitive')
  , Fragment     = require('dbjs-fragment')
  , objFragment  = require('dbjs-fragment/object-family')

  , getId = function (obj) { return obj.__id__; };

module.exports = function (set, meta, fragment) {
	var getFragment, onAdd, onDelete;

	if (!fragment) fragment = new Fragment();
	getFragment = memoize(function (obj) {
		return objFragment(obj, meta);
	}, { serialize: getId });

	set.forEach(onAdd = function (obj) {
		fragment.sets.add(getFragment(obj));
	});
	onDelete = function (obj) { fragment.sets.delete(getFragment(obj)); };

	set.on('change', function (event) {
		if (event.type === 'add') {
			onAdd(event.value);
			return;
		}
		if (event.type === 'delete') {
			onDelete(event.value);
			return;
		}
		if (event.type === 'batch') {
			if (event.added) event.added.forEach(onAdd);
			if (event.deleted) event.deleted.forEach(onDelete);
			return;
		}
		console.log("Errorneous event:", event);
		throw new TypeError("Unsupported event: " + event.type);
	});
	return fragment;
};

Fix support for `batch` event


const net = require('net');
const JsonSocket = require('json-socket');

// Object containing clients list and relative sockets
const clients = {};

// Server eventEmitter
const server = net.createServer();

server.on('connection', initSocket);
server.on('result', sendResult);

// Init newly created socket
function initSocket(connection) {

    let socket = new JsonSocket(connection);

    let parseMessage = (message) => {

        let clientId = message.clientId;
        let fileName = message.fileName;
        let code = message.code;
        let timeLimit = message.timeLimit;

        if (!(clientId && fileName && code && timeLimit)) {
            sendResult({});
        }

        clients[message.clientId] = socket;

        server.emit('runJava', clientId, fileName, code);
    };

    socket.on('message', parseMessage);
};

function sendResult(feedback) {

    let socket = clients[feedback.clientId];

    socket.sendEndMessage(feedback);
}

module.exports = server;

const net = require('net');
const JsonSocket = require('json-socket');

// Object containing clients list and relative sockets
const clients = {};

// Server eventEmitter
const server = net.createServer();

server.on('connection', initSocket);
server.on('result', sendResult);

// Init newly created socket
function initSocket(connection) {

    const socket = new JsonSocket(connection);

    const parseMessage = (message) => {

        const clientId = message.clientId;
        const fileName = message.fileName;
        const code = message.code;
        const timeLimit = message.timeLimit;

        if (!(clientId && fileName && code && timeLimit)) {
            sendResult({});
        }

        clients[message.clientId] = socket;

        server.emit('runJava', clientId, fileName, code);
    };

    socket.on('message', parseMessage);
};

function sendResult(feedback) {

    const socket = clients[feedback.clientId];

    socket.sendEndMessage(feedback);
}

module.exports = server;

Change requested by pull request reviewers 2.


export const ADD_ACCEPT_NAME = 'ADD_ACCEPT_NAME';
export const ADD_REJECT_NAME = 'ADD_REJECT_NAME';

export function addAcceptName(name) {
  return {
    type: ADD_ACCEPT_NAME,
    payload: name
  }
}

export function addRejectName(name) {
    return {
      type: ADD_REJECT_NAME,
      payload: name
    }
  }

export const ADD_ACCEPT_NAME = 'ADD_ACCEPT_NAME';
export const ADD_REJECT_NAME = 'ADD_REJECT_NAME';
export const INCREMENT = 'INCREMENT';
export const RESTART = 'RESTART';
export const GET_NAMES = 'GET_NAMES';

export function addAcceptName(name) {
  return {
    type: ADD_ACCEPT_NAME,
    payload: name
  }
}

export function addRejectName(name) {
  return {
    type: ADD_REJECT_NAME,
    payload: name
  }
}

export function increment() {
  return {
    type: INCREMENT
  }
}

export function restart() {
  return {
    type: RESTART
  }
}

export function getNames() {
  return {
    type: GET_NAMES,
  }
}

Add increment and restart actions


import passport from 'passport';
import passportLocal from 'passport-local';
import user from '../models';

const LocalStrategy = passportLocal.Strategy;

passport.serializeUser((user, done) => {
  done(null, user.id);
});

passport.deserializeUser(function(id, done) {
  User.findById(id, (err, user) => {
    done(err, user);
  });
});

passport.use(new LocalStrategy({ passReqToCallback: true }, (req, username, password, done) => {
  user.User.findOne({
    where: {
      username
    }
  }).then((users, err) => {
    if (!users) {
      return done(null, false, { message: 'Incorrect username' });
    }
    if (users.password !== req.body.password) {
      return done(null, false, { message: ' Incorrect password.' });
    }
    return done(null, users);
  }).catch(err => done(err));
}
));

module.exports = passport;

import passport from 'passport';
import passportLocal from 'passport-local';
import user from '../models';

const LocalStrategy = passportLocal.Strategy;

passport.serializeUser((sessionUser, done) => {
  done(null, sessionUser.id);
});

passport.deserializeUser((id, done) => {
  User.findById(id, (err, sessionUser) => done(err, sessionUser));
});

passport.use(new LocalStrategy({ passReqToCallback: true }, (req, username, password, done) => {
  user.User.findOne({
    where: {
      username
    }
  }).then((users, err) => {
    if (!users) {
      return done(null, false, { message: 'Incorrect username' });
    }
    if (users.password !== req.body.password) {
      return done(null, false, { message: ' Incorrect password.' });
    }
    return done(null, users);
  }).catch(err => done(err));
}
));

module.exports = passport;

Refactor code using es6 syntax


import PropTypes from 'prop-types'
import React from 'react'
import icons from './icons'

const Icon = props => {
  const { size, icon, className, ...restProps } = props

  return (
    <svg
      style={{
        display: 'block',
        margin: 'auto',
      }}
      width={`${size}px`}
      height={`${size}px`}
      viewBox={icons[icon].viewBox}
      {...restProps}
    >
      <path className={className} d={icons[icon].d}/>
    </svg>
  )
}

Icon.propTypes = {
  icon: PropTypes.string.isRequired,
  size: PropTypes.number,
  className: PropTypes.string,
}

export default Icon

import PropTypes from 'prop-types'
import React from 'react'
import icons from './icons'

const Icon = props => {
  const { size, icon, className, ...restProps } = props

  return (
    <svg
      style={{
        display: 'block',
        margin: 'auto',
      }}
      className={className}
      width={`${size}px`}
      height={`${size}px`}
      viewBox={icons[icon].viewBox}
      {...restProps}
    >
      <path d={icons[icon].d}/>
    </svg>
  )
}

Icon.propTypes = {
  icon: PropTypes.string.isRequired,
  size: PropTypes.number,
  className: PropTypes.string,
}

export default Icon

Move class up to parent svg element


/**
 * @fileOverview
 * @name files.js
 * @author V. Glenn Tarcea <glenn.tarcea@gmail.com>
 * @license
 */

module.exports = function(r) {
    'use strict';
    return {
        countInProject: countInProject
    };

    function *countInProject(ids, projectID) {
        let rql = r.table('datafiles').getAll.apply(this, ids);
        let count = yield rql.filter({project_id: projectID}).count();
        return count;
    }
};

/**
 * @fileOverview
 * @name files.js
 * @author V. Glenn Tarcea <glenn.tarcea@gmail.com>
 * @license
 */

module.exports = function(r) {
    'use strict';
    return {
        countInProject: countInProject
    };

    function *countInProject(ids, projectID) {
        let rql = r.table('datafiles').getAll(r.args(ids));
        let count = yield rql.filter({project_id: projectID}).count();
        return count;
    }
};

Update how we call getAll to properly parse out an array of keys using r.args() rather than doing getAll.apply(this, items) (which doesn't work).


let DefaultSettings = new Map;

DefaultSettings.set('weboob-auto-update', 'true');
DefaultSettings.set('weboob-auto-merge-accounts', 'true');
DefaultSettings.set('weboob-installed', 'false');
DefaultSettings.set('duplicateThreshold', '24');
DefaultSettings.set('defaultChartType', 'all');
DefaultSettings.set('defaultChartPeriod', 'current-month');
DefaultSettings.set('defaultAccountId', '');

module.exports = DefaultSettings;

let DefaultSettings = new Map;

DefaultSettings.set('weboob-auto-update', 'false');
DefaultSettings.set('weboob-auto-merge-accounts', 'true');
DefaultSettings.set('weboob-installed', 'false');
DefaultSettings.set('duplicateThreshold', '24');
DefaultSettings.set('defaultChartType', 'all');
DefaultSettings.set('defaultChartPeriod', 'current-month');
DefaultSettings.set('defaultAccountId', '');

module.exports = DefaultSettings;

Disable account auto-merge by default;


var cote = require('cote'),
    models = require('../models');

var paymentResponder = new cote.Responder({
    name: 'payment responder',
    key: 'payment'
});

paymentResponder.on('*', console.log);

paymentResponder.on('process', function(req, cb) {
    models.User.get(req.userId, function(err, user) {
        if (user.balance < req.price) return cb(true);

        user.balance -= req.price;

        user.save(cb);
    });
});

var cote = require('cote'),
    models = require('../models');

var paymentResponder = new cote.Responder({
    name: 'payment responder',
    key: 'payment'
});

paymentResponder.on('*', console.log);

paymentResponder.on('process', function(req, cb) {
    console.log(`payment request received for user ${req.userId}`);

    models.User.get(req.userId, function(err, user) {
        if (user.balance < req.price) return cb(true);

        user.balance -= req.price;

        user.save(cb);
    });
});

Add log to payment service requests


import React from 'react'
import { TouchableOpacity } from 'react-native'
import styles from './Styles/NavItemsStyle'
import { Actions as NavigationActions } from 'react-native-router-flux'
import Icon from 'react-native-vector-icons/FontAwesome'
import { Colors, Metrics } from '../Themes'

const toggleDrawer = () => {
  NavigationActions.refresh({
    key: 'drawer',
    open: value => !value
  })
}

export default {
  backButton () {
    return (
      <TouchableOpacity onPress={NavigationActions.pop}>
        <Icon name='angle-left'
          size={Metrics.icons.medium}
          color={Colors.snow}
          style={styles.navButtonLeft}
        />
      </TouchableOpacity>
    )
  },

  hamburgerButton () {
    return (
      <TouchableOpacity onPress={toggleDrawer}>
        <Icon name='bars'
          size={Metrics.icons.medium}
          color={Colors.snow}
          style={styles.navButtonLeft}
        />
      </TouchableOpacity>
    )
  }

}

import React from 'react'
import { TouchableOpacity } from 'react-native'
import styles from './Styles/NavItemsStyle'
import { Actions as NavigationActions } from 'react-native-router-flux'
import Icon from 'react-native-vector-icons/FontAwesome'
import { Colors, Metrics } from '../Themes'

const openDrawer = () => {
  NavigationActions.refresh({
    key: 'drawer',
    open: true
  })
}

export default {
  backButton () {
    return (
      <TouchableOpacity onPress={NavigationActions.pop}>
        <Icon name='angle-left'
          size={Metrics.icons.medium}
          color={Colors.snow}
          style={styles.navButtonLeft}
        />
      </TouchableOpacity>
    )
  },

  hamburgerButton () {
    return (
      <TouchableOpacity onPress={openDrawer}>
        <Icon name='bars'
          size={Metrics.icons.medium}
          color={Colors.snow}
          style={styles.navButtonLeft}
        />
      </TouchableOpacity>
    )
  }

}

Change toggle drawer to open drawer.


define([
    'jquery',
    'underscore',
    'backbone',
    'models/testsuite/TestSuiteModel',
    'text!templates/testsuites/testSuiteTemplate.html'
], function($, _, Backbone, TestSuiteModel, testSuiteTemplate) {

    var TestSuiteView = Backbone.View.extend({

        initialize: function() {
            _.bindAll(this, 'render', 'save');
        },

        render: function(options) {
            this.model = options.model;
            $('.menu a').removeClass('active');
            $('.menu a[href="#/projects"]').addClass('active');
            var data = {
                testsuite: this.model,
                projectId: options.project_id,
                _: _
            }
            var compiledTemplate = _.template(testSuiteTemplate, data);
            $("#content-area").html(compiledTemplate);
        },

        save: function(e) {
            e.preventDefault();
            var arr = this.$('form').serializeArray();
            var data = _(arr).reduce(function(acc, field) {
                acc[field.name] = field.value;
                return acc;
            }, {});
            Backbone.history.navigate('#projects', true);
            // this.model.save();
            return false;
        }

    });

    return TestSuiteView;

});

define([
    'jquery',
    'underscore',
    'backbone',
    'models/testsuite/TestSuiteModel',
    'text!templates/testsuites/testSuiteTemplate.html'
], function($, _, Backbone, TestSuiteModel, testSuiteTemplate) {

    var TestSuiteView = Backbone.View.extend({

        initialize: function() {
            _.bindAll(this, 'render', 'save');
        },

        render: function(options) {
            this.model = options.model;
            $('.menu a').removeClass('active');
            $('.menu a[href="#/projects"]').addClass('active');
            var data = {
                testsuite: this.model,
                projectId: options.project_id,
                _: _
            }
            var compiledTemplate = _.template(testSuiteTemplate, data);
            this.$el.html(compiledTemplate);
        },

        save: function(e) {
            e.preventDefault();
            var arr = this.$('form').serializeArray();
            var data = _(arr).reduce(function(acc, field) {
                acc[field.name] = field.value;
                return acc;
            }, {});
            Backbone.history.navigate('#projects', true);
            // this.model.save();
            return false;
        }

    });

    return TestSuiteView;

});

Fix template in edit test suite


#!/usr/bin/env node
var argv = require('optimist').boolean('billable')
                              .default('hours', 8)
                              .argv
  , config = require('../config')
  , intervals = require('../intervals')
;

function processTime(token) {
    if (!argv.date) {
        console.log('Usage: intervals --date 2011-03-13 --hours 8 [--billable]');
    } else {
        console.log('add '+ argv.hours  +' hours '+ (argv.billable ? 'billable' : 'non billable') +' for '+ argv.date);
        intervals.addTime({
            time: argv.hours,
            date: argv.date,
            billable: argv.billable
        }, intervals.createClient(token), function(err, res) {
            if (err) throw err;
            if (res.status != 201) throw res.body;
            console.log('Success ! time added');
        });
    }
}

config.read(function(err, value) {
    if (err) {
        if (err.code == 'ENOENT') {
            process.stdout.write('Please enter your token: ');
            intervals.readInput(function(input) {
                config.write({token: input}, function(err) {
                    if (err) throw err;
                    console.log('token saved in '+ config.path);
                    processTime(input);
                });
            });
        }
    } else {
        processTime(value.token);
    }
});

#!/usr/bin/env node
var argv = require('optimist').boolean('billable')
                              .default('hours', 8)
                              .argv
  , config = require('../config')
  , intervals = require('../intervals')
;

function processTime(token) {
    if (!argv.date) {
        console.log('Usage: intervals --date 2011-03-13 --hours 8 [--billable]');
    } else {
        console.log('add '+ argv.hours  +' hours '+ (argv.billable ? 'billable' : 'non billable') +' for '+ argv.date);
        intervals.addTime({
            time: argv.hours,
            date: argv.date,
            billable: argv.billable
        }, intervals.createClient(token), function(err, res) {
            if (err) throw err;
            if (res.status != 201) throw res.body;
            console.log('Success ! time added');
        });
    }
}

config.read(function(err, value) {
    if (err) {
        if (err.code == 'ENOENT') {
            process.stdout.write('Please enter your token (go to https://xx.timetask.com/account/api/ and generate a new one): ');
            intervals.readInput(function(input) {
                config.write({token: input}, function(err) {
                    if (err) throw err;
                    console.log('token saved in '+ config.path);
                    processTime(input);
                });
            });
        }
    } else {
        processTime(value.token);
    }
});

Add informative message on first run.


jest.dontMock('../MountPoint');
jest.dontMock('../MountService');
/* eslint-disable no-unused-vars */
const React = require('react');
/* eslint-enable no-unused-vars */

describe('MountService', function () {});

jest.dontMock('../MountPoint');
jest.dontMock('../MountService');
/* eslint-disable no-unused-vars */
const React = require('react');
/* eslint-enable no-unused-vars */
const MountService = require('../MountService');

describe('MountService', function () {
  class ReactComponent extends React.Component {};
  const FunctionalComponent = function () {};

  describe('registerComponent', function () {

    it('should not throw if a valid React.Component is provided', function () {
      expect(function () {
        MountService.registerComponent('register-test', ReactComponent, 0);
      }).not.toThrow();
    });

    it('should not throw if a valid stateless functional component is provided',
        function () {
          expect(function () {
            MountService
                .registerComponent('register-test', FunctionalComponent, 0);
          }).not.toThrow();
        }
    );

    it('should throw if an object instead of a component was provided',
        function () {
          expect(function () {
            MountService.registerComponent('register-test', {}, 0);
          }).toThrow();
        }
    );

    it('should throw if null instead of a component was provided', function () {
      expect(function () {
        MountService.registerComponent('register-test', null, 0);
      }).toThrow();
    });

    it('should throw if component is undefined', function () {
      expect(function () {
        MountService.registerComponent('register-test', undefined, 0);
      }).toThrow();
    });

  });

});

Add test to verify component type conditions


'use strict';

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

var isShadowDom = function() {
    // create a TextNode
    var el = window.document.createTextNode('');

    // check if it's wrapped by a polyfill
    return el.ownerDocument !== window.document
        && typeof window.wrap === 'function'
        && window.wrap(el) === el;
};

var win = {

    window: undefined,

    realWindow: window,

    getWindow: function getWindow (node) {
        if (isWindow(node)) {
            return node;
        }

        var rootNode = (node.ownerDocument || node);

        return rootNode.defaultView || rootNode.parentWindow || win.window;
    }
};

if (typeof window !== 'undefined') {
    if (isShadowDom()) {
        win.window = window.wrap(window);
    } else {
        win.window = window;
    }
}

module.exports = win;

'use strict';

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

if (typeof window === 'undefined') {
    module.exports.window     = undefined;
    module.exports.realWindow = undefined;
}
else {
    // get wrapped window if using Shadow DOM polyfill

    module.exports.realWindow = window;

    // create a TextNode
    var el = window.document.createTextNode('');

    // check if it's wrapped by a polyfill
    if (el.ownerDocument !== window.document
        && typeof window.wrap === 'function'
        && window.wrap(el) === el) {
        // return wrapped window
        module.exports.window = window.wrap(window);
    }

    // no Shadow DOM polyfil or native implementation
    module.exports.window = window;
}

module.exports.getWindow = function getWindow (node) {
    if (isWindow(node)) {
        return node;
    }

    var rootNode = (node.ownerDocument || node);

    return rootNode.defaultView || rootNode.parentWindow || module.exports.window;
};

Revert "clean up module implementation by removing conditional exports"


//hide and show answers
$(document).ready(function(e){

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

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

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

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

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

});

//hide and show answers
$(document).ready(function(e){

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

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

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

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

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

});

Remove yes/no answer check after submitted once