/**
 * Get an image's width and height
 * @param {(File|blob|string)} File, blob, or URL string
 * @returns {Promise} resolved with object containing image width and height
 */
module.exports = function browserImageSize (image) {
  return new Promise(function (resolve, reject) {
    var DOMURL = window.URL || window.webkitURL || window
    var url = typeof image === 'string' ? image : DOMURL.createObjectURL(image)
    var img = document.createElement('img')

    img.onload = function onload () {
      if (typeof image !== 'string')
        DOMURL.revokeObjectURL(url)
      resolve({width: img.width, height: img.height})
    }

    img.onerror = function onerror (err) {
      if (typeof image !== 'string')
        DOMURL.revokeObjectURL(url)
      reject(err)
    }

    img.src = url
  })
}

/* istanbul ignore next */
var DOMURL = window.URL || window.webkitURL || window

/**
 * Get an image's width and height
 * @param {(File|blob|string)} File, blob, or URL string
 * @returns {Promise} resolved with object containing image width and height
 */
module.exports = function browserImageSize (image) {
  return new Promise(function (resolve, reject) {
    var url = typeof image === 'string' ? image : DOMURL.createObjectURL(image)
    var img = document.createElement('img')

    img.onload = function onload () {
      if (typeof image !== 'string')
        DOMURL.revokeObjectURL(url)
      resolve({width: img.width, height: img.height})
    }

    img.onerror = function onerror (err) {
      if (typeof image !== 'string')
        DOMURL.revokeObjectURL(url)
      reject(err)
    }

    img.src = url
  })
}

Move DOMURL outside and add istanbul ignore


##USER STORIES

// /As a user i’d like to do three things to a list of numbers.
// Using “sum” and the list I want to add together all the numbers whether the list is even or odd in length.
// I’d like to use “mean” to return the average of all the numbers in the list.
// Finally I’d like to use “median” to return the median number of the list./

##PSEUDOCODE

input: An array of numbers
output: 1) the sum of all the numbers inside the array, 2) the "mean" average of the numbers inside the array, 3) the median number from the array

# Create an array of single-digit numbers
# Iterate through the array of numbers to calculate and return its sum (non-destructively)

# Define a method that accepts the array as an argument and returns the "mean" average
  # Divide the sum of the array by the    amount of numbers inside the array
  # Return the "mean average" number

# Define a method that accepts the array as an argument and returns the "median" number
  # Sort the array in ascending order
    # IF array length odd?,
      # Subtract the array(by length) by 1, and divide by 2
      # return median value
    # ELSE if array length even?,
      # Take array(by length) and divide by 2,
      # add this value to the value of
      # The array(by length), subtracted by 1, divided by 2
      # Take the sum of these index values and divide by 2
      # return median value

Update file to exclude User Stories.


import Model from "ember-data/model";
import attr from "ember-data/attr";
import { belongsTo, hasMany } from "ember-data/relationships";
import { computed, get } from "@ember/object";

export default Model.extend({
  stockQuantity: attr("number"),
  product: belongsTo("product"),
  price: belongsTo("price"),
  bom: belongsTo("bom", { async: false }),
  skuImages: hasMany("sku-image"),
  skuFields: hasMany("sku-field"),

  attributes: computed("skuFields.[]", function() {
    return get(this, "skuFields").reduce((hash, attribute) => {
      hash[get(attribute, "slug")] = get(attribute, "values");
      return hash;
    }, {});
  })
});

import Model from "ember-data/model";
import attr from "ember-data/attr";
import { belongsTo, hasMany } from "ember-data/relationships";
import { computed, get } from "@ember/object";

export default Model.extend({
  stockQuantity: attr("number"),
  price: attr("number"),
  // price: belongsTo("price"),
  product: belongsTo("product"),
  bom: belongsTo("bom", { async: false }),
  skuImages: hasMany("sku-image"),
  skuFields: hasMany("sku-field"),

  attributes: computed("skuFields.[]", function() {
    return get(this, "skuFields").reduce((hash, attribute) => {
      hash[get(attribute, "slug")] = get(attribute, "values");
      return hash;
    }, {});
  })
});

Change price back to number temporarily


(function (module) {
    module.controller("SamplesController", SamplesController);
    SamplesController.$inject = ["$state", "project", "$filter", "samples", "processTemplates"];

    function SamplesController($state, project, $filter, samples, processTemplates) {
        var ctrl = this;

        ctrl.project = project;
        ctrl.viewSample = viewSample;
        ctrl.samples = samples;
        ctrl.createSample = createSample;

        if (ctrl.samples.length !== 0) {
            var sortedSamples = $filter('orderBy')(ctrl.samples, 'name');
            ctrl.current = sortedSamples[0];
            $state.go('projects.project.samples.list.edit', {sample_id: ctrl.current.id});
        }

        //////////////////

        function viewSample(sample) {
            ctrl.current = sample;
            $state.go('projects.project.samples.list.edit', {sample_id: ctrl.current.id});
        }

        function createSample() {
            var template = processTemplates.getTemplateByName('As Received');
            processTemplates.setActiveTemplate(template);
            $state.go('projects.project.processes.create');
        }
    }
}(angular.module('materialscommons')));

(function (module) {
    module.controller("SamplesController", SamplesController);
    SamplesController.$inject = ["$state", "project", "$filter", "samples"];

    function SamplesController($state, project, $filter, samples) {
        var ctrl = this;

        ctrl.project = project;
        ctrl.viewSample = viewSample;
        ctrl.samples = samples;
        ctrl.createSample = createSample;

        if (ctrl.samples.length !== 0) {
            var sortedSamples = $filter('orderBy')(ctrl.samples, 'name');
            ctrl.current = sortedSamples[0];
            $state.go('projects.project.samples.list.edit', {sample_id: ctrl.current.id});
        }

        //////////////////

        function viewSample(sample) {
            ctrl.current = sample;
            $state.go('projects.project.samples.list.edit', {sample_id: ctrl.current.id});
        }

        function createSample() {
            $state.go('projects.project.processes.create', {process: 'As Received', process_id: ''});
        }
    }
}(angular.module('materialscommons')));

Create sample using new process create method.


var fs = Npm.require('fs');
var path = Npm.require('path');
var iced = Npm.require('iced-coffee-script');

var handler = function (compileStep) {
  var source = compileStep.read().toString('utf8');
  var outputFile = compileStep.inputPath + ".js";

  options = {
    bare: true,
    filename: compileStep.inputPath,
    literate: path.extname(compileStep.inputPath) === '.litcoffee'
  };

  try {
    var output = iced.compile(source, options);
  } catch (e) {
    throw new Error(
      compileStep.inputPath + ':' +
      (e.location ? (e.location.first_line + ': ') : ' ') +
      e.message
    );
  }

  compileStep.addJavaScript({
    path: outputFile,
    sourcePath: compileStep.inputPath,
    data: output
  });
};

Plugin.registerSourceHandler('coffee', handler);
Plugin.registerSourceHandler('litcoffee', handler);
Plugin.registerSourceHandler('iced', handler);

Handle *.iced sources in addition to *.coffee.


$(document).ready(function(){

    //autocomplete for organism search
     $("#search_organism").autocomplete({
        position: {
           my: "right top", at: "right bottom"
        },
        source: function (request, response) {
            var search = request.term;
            $.ajax({
                url: WebRoot.concat("/ajax/listing/Organisms"),
                data: {term:  request.term, limit: 500, search: search},
                dataType: "json",
                success: function (data) {
                    response(data);
                }
            });
        },
        minLength: 3
    });

    $("#search_organism").data("ui-autocomplete")._renderItem = function (ul, item) {
        var li = $("
")
                .append("" + item.scientific_name + "" + item.rank + "")
                .appendTo(ul);
        return li;
    };

    $("#btn_search_organism").click(function(){
        var searchTerm = $("#search_organism").val();
        var resultPage =  WebRoot+"/organism/results/"+searchTerm;
        window.location.href = resultPage;
    });
});

$(document).ready(function(){

    //autocomplete for organism search
     $("#search_organism").autocomplete({
        position: {
           my: "right top", at: "right bottom"
        },
        source: function (request, response) {
            var search = request.term;
            $.ajax({
                url: WebRoot.concat("/ajax/listing/Organisms"),
                data: {term:  request.term, limit: 500, search: search, dbversion: DbVersion},
                dataType: "json",
                success: function (data) {
                    response(data);
                }
            });
        },
        minLength: 3
    });

    $("#search_organism").data("ui-autocomplete")._renderItem = function (ul, item) {
        var li = $("
")
                .append("" + item.scientific_name + "" + item.rank + "")
                .appendTo(ul);
        return li;
    };

    $("#btn_search_organism").click(function(){
        var searchTerm = $("#search_organism").val();
        var resultPage =  WebRoot+"/organism/results/"+searchTerm;
        window.location.href = resultPage;
    });
});

Add dbversion parameter to call of webservice via ajax


var expect = require('expect');

module.exports = function chunk2(callback) {
  var resourcesWithIntegrity;
  function forEachElement(el) {
    var src = el.getAttribute('src') || el.getAttribute('href');
    var integrity = el.getAttribute('integrity');
    var crossorigin = el.getAttribute('crossOrigin');
    var match;
    if (src) {
      match = src.match(/[^/]+\.(js|css)/);
      if (match && crossorigin && integrity && integrity.match(/^sha\d+-/)) {
        resourcesWithIntegrity.push(match[0].toString());
      }
    }
  }
  try {
    resourcesWithIntegrity = [];
    Array.prototype.slice
      .call(document.getElementsByTagName('script'))
      .forEach(forEachElement);
    Array.prototype.slice
      .call(document.getElementsByTagName('link'))
      .forEach(forEachElement);
    expect(resourcesWithIntegrity).toInclude('stylesheet.css');
    expect(resourcesWithIntegrity).toInclude('test.js');
    expect(
      resourcesWithIntegrity.filter(function filter(item) {
        return item.match(/^[12]\.(chunk|bundle).js$/);
      }).length
    ).toBe(2);
    expect(
      window.getComputedStyle(document.getElementsByTagName('body')[0])
        .backgroundColor
    ).toEqual('rgb(200, 201, 202)');
    callback();
  } catch (e) {
    callback(e);
  }
};

var expect = require('expect');

module.exports = function chunk2(callback) {
  var resourcesWithIntegrity;
  function forEachElement(el) {
    var src = el.getAttribute('src') || el.getAttribute('href');
    var integrity = el.getAttribute('integrity');
    var crossorigin = el.getAttribute('crossOrigin');
    var match;
    if (src) {
      match = src.match(/[^/]+\.(js|css)/);
      if (
        match &&
        !['context.js', 'mocha.js', 'adapter.js'].includes(match[0])
      ) {
        expect(
          crossorigin && integrity && integrity.match(/^sha\d+-/)
        ).toBeTruthy();
        resourcesWithIntegrity.push(match[0].toString());
      }
    }
  }
  try {
    resourcesWithIntegrity = [];
    Array.prototype.slice
      .call(document.getElementsByTagName('script'))
      .forEach(forEachElement);
    Array.prototype.slice
      .call(document.getElementsByTagName('link'))
      .forEach(forEachElement);
    expect(resourcesWithIntegrity).toInclude('stylesheet.css');
    expect(resourcesWithIntegrity).toInclude('test.js');
    expect(resourcesWithIntegrity.length).toBeGreaterThanOrEqualTo(4);
    expect(
      window.getComputedStyle(document.getElementsByTagName('body')[0])
        .backgroundColor
    ).toEqual('rgb(200, 201, 202)');
    callback();
  } catch (e) {
    callback(e);
  }
};

Fix Karma tests for Webpack 2 and 3


function NoteApplication (author) {
	this.author = author;
	this.notes = [];

	this.create = function(note_content) {
		if (note_content.length > 0) {
      		this.notes.push(note_content);
      		return "You have created a note";
      	}
    	else {
      		return "You haven't entered a valid note";
      	}

	}

	this.listNotes = function(){
        if(this.noteArray.length < 1){
            console.log("There are no notes in the collection.");
        }
        else{for(let i = 0; i < this.noteArray.length; i++){
                console.log("\nNote ID: " + this.noteArray[i]);
                console.log(this.noteArray[i]);
                console.log("\n\nBy Author " + this.author + "\n");
         }
}

function NoteApplication (author) {
	this.author = author;
	this.notes = [];

	this.create = function(note_content) {
		if (note_content.length > 0) {
      		this.notes.push(note_content);
      		return "You have created a note";
      	}
    	else {
      		return "You haven't entered a valid note";
      	}

	}

	this.listNotes = function(){
        if(this.noteArray.length < 1){
            console.log("There are no notes in the collection.");
        }
        else{for(let i = 0; i < this.notes.length; i++){
                console.log("\nNote ID: " + this.notes[i]);
                console.log(this.notes[i]);
                console.log("\n\nBy Author " + this.author + "\n");
         }

    this.get = function(note_id) {
      return "Note ID: " + this.notes[note_id];
    }

}

Add a get note method


/*
* This file can be used to convey information to other eslint files inside
* Canvas.
*/

module.exports = {
  globals: {
    ENV: true,
    INST: true,
  },
  plugins: [
    "promise",
    "import"
  ],
  // 0 - off, 1 - warning, 2 - error
  rules: {
    "class-methods-use-this": [0],
    "comma-dangle": [2, "only-multiline"],
    "func-names": [0],
    "max-len": [1, {"code": 140}],
    "no-continue": [0],
    "no-plusplus": [0],
    "no-underscore-dangle": [0],
    "no-unused-vars": [2, { "argsIgnorePattern": "^_"}],
    "object-curly-spacing": [0],
    "semi": [0],
    "space-before-function-paren": [2, "always"],

    // allows 'i18n!webzip_exports' and 'compiled/foo/bar'
    "import/no-extraneous-dependencies": [0],
    "import/named": [2],
    "import/no-unresolved": [0],
    "import/no-webpack-loader-syntax": [0],
    "import/no-commonjs": [2],
    "react/jsx-filename-extension": [2, { "extensions": [".js"] }],
    "import/extensions": [1, { "js": "never", "jsx": "never", "json": "always" }],
    "promise/avoid-new": [0],
  }
};

/*
* This file can be used to convey information to other eslint files inside
* Canvas.
*/

module.exports = {
  globals: {
    ENV: true,
    INST: true,
  },
  plugins: [
    "promise",
    "import"
  ],
  // 0 - off, 1 - warning, 2 - error
  rules: {
    "class-methods-use-this": [0],
    "comma-dangle": [2, "only-multiline"],
    "func-names": [0],
    "max-len": [1, {"code": 140}],
    "no-continue": [0],
    "no-else-return": [0],
    "no-plusplus": [0],
    "no-underscore-dangle": [0],
    "no-unused-vars": [2, { "argsIgnorePattern": "^_"}],
    "object-curly-spacing": [0],
    "semi": [0],
    "space-before-function-paren": [2, "always"],

    // allows 'i18n!webzip_exports' and 'compiled/foo/bar'
    "import/no-extraneous-dependencies": [0],
    "import/named": [2],
    "import/no-unresolved": [0],
    "import/no-webpack-loader-syntax": [0],
    "import/no-commonjs": [2],
    "react/jsx-filename-extension": [2, { "extensions": [".js"] }],
    "import/extensions": [1, { "js": "never", "jsx": "never", "json": "always" }],
    "promise/avoid-new": [0],
  }
};

Remove no-else-return from being checked


require('../test_helper');
require('../../app/helpers');

describe('Application helpers', () => {
  describe('#g', () => {
    it('should generate a Glyphicon span', () => {
      var output = Handlebars.helpers.g('foo');

      assert(output instanceof Handlebars.SafeString);
      assert.equal(output.string, '<span class="glyphicon glyphicon-foo"> </span>');
    });
  });

  describe('#t', () => {
    it('should delegate to the translation module', () => {
      I18n.load('en');

      var output = Handlebars.helpers.t('meta.history');

      assert.equal(output, 'History');
    });
  });

  describe('#interpolate', () => {
    it('should delegate to the i18n module passing the current scope', () => {
      I18n.load('en');

      var context = { current: 10, total: 100 };
      var output  = Handlebars.helpers.interpolate('local.feedback.progress', {
        data: { root: context }
      });

      assert.equal(output.string, '10 files processed out of 100.');
    });
  });
});

require('../test_helper');
require('../../app/helpers');

describe('Application helpers', () => {
  before(() => {
    I18n.load('en')
  })

  describe('#g', () => {
    it('should generate a Glyphicon span', () => {
      var output = Handlebars.helpers.g('foo');

      assert(output instanceof Handlebars.SafeString);
      assert.equal(output.string, '<span class="glyphicon glyphicon-foo"> </span>');
    });
  });

  describe('#t', () => {
    it('should delegate to the translation module', () => {
      var output = Handlebars.helpers.t('meta.history');

      assert.equal(output, 'History');
    });
  });

  describe('#interpolate', () => {
    it('should delegate to the i18n module passing the current scope', () => {
      var context = { current: 10, total: 100 };
      var output  = Handlebars.helpers.interpolate('local.feedback.progress', {
        data: { root: context }
      });

      assert.equal(output.string, '10 files processed out of 100.');
    });
  });

  describe('pluralize', () => {
    it('should delegate to the i18n module', () => {
      var output = Handlebars.helpers.pluralize(10, 'album')

      assert.equal(output, '10 albums')
    })
  })

  describe('titleize', () => {
    it('should delegate to the i18n module', () => {
      var output = Handlebars.helpers.titleize('album')

      assert.equal(output, 'Album')
    })
  })
});

Complete a bit the application helpers tests


(function () {

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this;

    // Create a reference to this
    var Instructor = function (fString) {
        var self = this;

        self._fRef = new root.Firebase(fString);

        self._create = function (func, validators) {
            console.log('piepie', func.toString());
        }

        return self._create;
    };

    var setup = function (isNode) {
        if (isNode) {
            root.Firebase = require('firebase');
        }else{
            // Import script tag
        }
    };

    var isNode = false;

    // Export the Instruce object for **CommonJS**, with backwards-compatibility
    // for the old `require()` API. If we're not in CommonJS, add `_` to the
    // global object.
    if (typeof module !== 'undefined' && module.exports) {
            module.exports = Instructor;
            isNode = true;
    } else {
            root.Instructor = Instructor;
    }
    setup(isNode);
})();

/*global console, require, module*/
(function () {
    "use strict";

    // Establish the root object, `window` in the browser, or `global` on the server.
    var root, Instructor, setup, isNode;
    root = this;

    // Create a reference to this
    Instructor = function (fString) {
        var self = this;

        self.fRef = new root.Firebase(fString);

        self.create = function (func, validators) {
            console.log('piepie', func.toString());
        };

        return self.create;
    };

    setup = function (isNode) {
        if (isNode) {
            root.Firebase = require('firebase');
        } else if (!root.Firebase) {
            console.log("Please include Firebase.js");
        }
    };

    isNode = false;

    // Export the Instruce object for **CommonJS**, with backwards-compatibility
    // for the old `require()` API. If we're not in CommonJS, add `_` to the
    // global object.
    if (typeof module !== 'undefined' && module.exports) {
        module.exports = Instructor;
        isNode = true;
    } else {
        root.Instructor = Instructor;
    }
    setup(isNode);
}());

Clean up code for JsHint


'use strict';

// Module dependencies
var DOMReady = require('domready');
var MainView = require('./views/main');
var Me       = require('./models/me');

// The app's entry point. Register global event handlers, etc in here
window.app = {
  init: function() {
    window.me = new Me();
    var self = this;
    // Wait for DOMReady before going wild
    DOMReady(function() {
      self.view = new MainView({ el: document.body });
    });
  }
};

window.app.init();

'use strict';

// Module dependencies
var MainView = require('./views/main');
var Me       = require('./models/me');

// The app's entry point. Register global event handlers, etc in here
window.app = {
  init: function() {

    // Initialize user model
    window.me = new Me();

    document.addEventListener('DOMContentLoaded', function() {
      self.view = new MainView({ el: document.body });
    })
    var self = this;
  }
};

window.app.init();

Use DOMContentLoaded instead of domready


/*
 * Conversion from virtual time streams out to diagram data, and
 * vice-versa, and related functions.
 */

function calculateNotificationContentHash(content) {
  var SOME_PRIME_NUMBER = 877;
  if (typeof content === "string") {
    return content.split("")
      .map(function(x) { return x.charCodeAt(0); })
      .reduce(function(x, y) { return x + y; });
  } else if (typeof content === "number") {
    return content * SOME_PRIME_NUMBER;
  } else if (typeof content === 'boolean') {
    return content ? SOME_PRIME_NUMBER : SOME_PRIME_NUMBER*3;
  }
};

function calculateNotificationHash(marbleData) {
  var SMALL_PRIME = 7;
  var LARGE_PRIME = 1046527;
  var MAX = 100000;
  var contentHash = calculateNotificationContentHash(marbleData.content);
  return ((marbleData.time + contentHash + SMALL_PRIME) * LARGE_PRIME) % MAX;
};

module.exports = {
  calculateNotificationHash: calculateNotificationHash,
  calculateNotificationContentHash: calculateNotificationContentHash
};

/*
 * Conversion from virtual time streams out to diagram data, and
 * vice-versa, and related functions.
 */

function calculateNotificationContentHash(content) {
  var SOME_PRIME_NUMBER = 877;
  if (typeof content === "string") {
    return content.split("")
      .map(function(x) { return x.charCodeAt(0); })
      .reduce(function(x, y) { return x + y; });
  } else if (typeof content === "number") {
    return parseInt(content) * SOME_PRIME_NUMBER;
  } else if (typeof content === 'boolean') {
    return content ? SOME_PRIME_NUMBER : SOME_PRIME_NUMBER*3;
  }
};

function calculateNotificationHash(marbleData) {
  var SMALL_PRIME = 7;
  var LARGE_PRIME = 1046527;
  var MAX = 100000;
  var contentHash = calculateNotificationContentHash(marbleData.content);
  return ((marbleData.time + contentHash + SMALL_PRIME) * LARGE_PRIME) % MAX;
};

module.exports = {
  calculateNotificationHash: calculateNotificationHash,
  calculateNotificationContentHash: calculateNotificationContentHash
};

Make hash method return whole numbers


define([
    "home/models",
    "home/views/application_list_view",
    "jquery"
], function (models, application_list_view, $) {
    "use strict";
    QUnit.module("home.views");
    QUnit.test("rendering", function (assert) {
        assert.expect(2);

        var model = new models.ApplicationListModel();
        var view = new application_list_view.ApplicationListView(
            { model: model }
        );

        assert.ok(model.loading);

        model.update()
            .done(function() {
                view.model = model;
                model.loading = false;
            } )
            .done(function() {
                assert.notOk(model.loading);
            });
    });
});

define([
    "home/models",
    "home/views/application_list_view",
    "components/vue/dist/vue",
    "filters"
], function (models, application_list_view, Vue) {
    "use strict";

    QUnit.module("home.app_list_view");
    QUnit.test("rendering list", function (assert) {
        var done = assert.async();

        var model = new models.ApplicationListModel();
        var app_list_view = new application_list_view.ApplicationListView({
            data: function() { return { model: model }; }
        }).$mount();

        assert.ok(model.loading);
        assert.equal(
            app_list_view.$el.querySelector("#loading-spinner").style.display,
            ""
        )

        model.update().done(function() { Vue.nextTick(function() {
            assert.equal(
                app_list_view.$el.querySelector("#loading-spinner").style.display,
                "none"
            )

            assert.equal(
                app_list_view.$el.querySelector("#applistentries").children.length,
                model.app_list.length + 2
            )

            // Clear the model's application list
            model.app_list = [];

            Vue.nextTick(function() {
                assert.equal(
                    app_list_view.$el.querySelector("#applistentries > li > a").style.display,
                    ""
                )

                assert.equal(
                    app_list_view.$el.querySelector("#applistentries").children.length,
                    2
                )

                done();
            });
        })});
    });

    QUnit.test("search form", function (assert) {
        var done = assert.async();

        var model = new models.ApplicationListModel();
        var app_list_view = new application_list_view.ApplicationListView({
            data: function() { return { model: model }; }
        }).$mount();

        model.update().done(function() { Vue.nextTick(function() {
            assert.notEqual(app_list_view.visible_list.length, 0);

            app_list_view.search_input = "heho"

            Vue.nextTick(function() {
                assert.equal(app_list_view.visible_list.length, 0);

                assert.equal(
                    app_list_view.$el.querySelector("input[name=q]").value,
                    "heho"
                );

                done();
            })
        })});
    });
});

Add tests for the application list view


const CronJob = require('cron').CronJob;
const splatnet = require('./splatnet');

console.info('Starting periodic tasks...');

// Run every day at 2min 30sec after the hour
new CronJob('30 2 * * * *', () => {
    splatnet.update();
}, null, true);

const CronJob = require('cron').CronJob;
const splatnet = require('./splatnet');

console.info('Starting periodic tasks...');

// Run every day at 0min 30sec after the hour
new CronJob('30 0 * * * *', () => {
    splatnet.update();
}, null, true);

Update data closer to the top of the hour


import React from 'react';
import Header from '../app/Header';

const Help = () =>

Help

;

export default Help;

import React from 'react';
import { FormattedMessage } from 'react-intl';
import Header from '../app/Header';

const Help = () =>

<FormattedMessage id="help" />

Report an issue

        If you spot a problem with Busy, please
        {' '}contact us or submit an issue on{' '}

          GitHub
        .

;

export default Help;

Add message for report issue


/* eslint-env jquery */

start();
function start () {
  'use strict';

  $(document).ready(() => {
    $('form').submit(event => {
      event.preventDefault();
      const username = $('#username').val();
      const password = $('#password').val();
      const loginObj = {
        username,
        password
      };
      console.log(loginObj);
      $.post({
        url: '/login',
        data: JSON.stringify(loginObj),
        dataType: 'JSON',
        contentType: "application/json; charset=utf-8",
        sucess: (result) => console.log(result)
      });
    });
  });
}

/* eslint-env jquery */

start();
function start () {
  'use strict';

  $(document).ready(() => {
    $('form').submit(event => {
      event.preventDefault();
      const username = $('#username').val();
      const password = $('#password').val();
      const loginObj = {
        username,
        password
      };
      console.log(loginObj);
      $.post({
        url: '/login',
        data: JSON.stringify(loginObj),
        dataType: 'JSON',
        contentType: "application/json; charset=utf-8",
        success: (result) => console.log(result)
      });
    });
  });
}

Fix typo in POST request


const Type = require('./type').Type;

/*
 * These functions take an entity (npc/player)
 * and return the correct method or property
 * depending on type.
 */

const getName = entity => Type.isPlayer(entity) ?
  entity.getName() :
  entity.getShortDesc('en');

const getSpeed = entity => entity.getAttackSpeed;

const getWeapon = entity => Type.isPlayer(entity) ?
  entity.getEquipped('wield', true) :
  entity.getAttack('en');

const getOffhand = entity => Type.isPlayer(entity) ?
  entity.getEquipped('offhand', true) :
  null; //TODO: allow for dual attacks for npcs

const getBodyParts = entity => Type.isPlayer(entity) ?
  playerBodyParts :
  entity.getBodyParts();

function get(entity) {
  const name      = getName(entity);
  const getSpeed  = getSpeed(entity);
  const weapon    = getWeapon(entity);
  const offhand   = getOffhand(entity);
  const locations = getBodyParts(entity);

  return {
    name,
    getSpeed,
    weapon,
    offhand,
    locations
  };
}

exports.CombatUtil = { get };

const Type = require('./type').Type;

/*
 * These functions take an entity (npc/player)
 * and return the correct method or property
 * depending on type.
 */

const getName = entity => Type.isPlayer(entity) ?
  entity.getName() :
  entity.getShortDesc('en');

const getSpeed = entity => entity.getAttackSpeed;

const getWeapon = entity => Type.isPlayer(entity) ?
  entity.getEquipped('wield', true) :
  entity.getAttack('en');

const getOffhand = entity => Type.isPlayer(entity) ?
  entity.getEquipped('offhand', true) :
  null; //TODO: allow for dual attacks for npcs

const getBodyParts = entity => Type.isPlayer(entity) ?
  playerBodyParts :
  entity.getBodyParts();

function CombatHelper(entity) {
  this.entity      = entity;

  /*
   * Example: { 'berserk': damage => damage * 2 }
   */
  this.speedMods   = {};
  this.damageMods  = {};
  this.toHitMods   = {};

  this.addSpeedMod  = addMod('speedMods');
  this.addDamageMod = addMod('damageMods');
  this.addToHitMod  = addMod('toHitMods');

  function addMod(type) {
    return modifier => this[type][modifier.name] = modifier.effect;
  }

  this.removeSpeedMod  = deleteMod('speedMods');
  this.removeDamageMod = deleteMod('damageMods');
  this.removeToHitMod  = deleteMod('toHitMods');

  function deleteMod(type) {
    return name => delete this[type][name];
  }

  return this;
}

function get(entity) {
  return new CombatHelper(entity);
}

exports.CombatUtil = { get };

Add CombatHelper class and getters/setters for modifiers.


import React, { Component } from 'react';
import { connect } from 'react-redux';
import Chart from '../components/chart';

class WeatherList extends Component {
  renderWeather(cityData) {
    const name = cityData.city.name;
    const temps = cityData.list.map(weather => weather.main.temp);
    const pressures = cityData.list.map(weather => weather.main.pressure);
    const humidities = cityData.list.map(weather => weather.main.humidity);

    return (

        {name}
        <Chart data={temps} color="orange" units="K" />
        <Chart data={pressures} color="green" units="hPa" />
        <Chart data={humidities} color="black" units="%" />

    );
  }

  render() {
    return (

            City
            Temperature (K)
            Pressure (hPa)
            Humidity (%)

          {this.props.weather.map(this.renderWeather)}

    );
  }
}

function mapStateToProps({ weather }) {
  return { weather };
}
export default connect(mapStateToProps)(WeatherList);

import React, { Component } from 'react';
import { connect } from 'react-redux';
import Chart from '../components/chart';
import GoogleMap from '../components/google_map';

class WeatherList extends Component {
  renderWeather(cityData) {
    const name = cityData.city.name;
    const temps = cityData.list.map(weather => weather.main.temp);
    const pressures = cityData.list.map(weather => weather.main.pressure);
    const humidities = cityData.list.map(weather => weather.main.humidity);
    const { lon, lat } = cityData.city.coord;

    return (

        <GoogleMap lon={lon} lat={lat} />
        <Chart data={temps} color="orange" units="K" />
        <Chart data={pressures} color="green" units="hPa" />
        <Chart data={humidities} color="black" units="%" />

    );
  }

  render() {
    return (

            City
            Temperature (K)
            Pressure (hPa)
            Humidity (%)

          {this.props.weather.map(this.renderWeather)}

    );
  }
}

function mapStateToProps({ weather }) {
  return { weather };
}
export default connect(mapStateToProps)(WeatherList);

Add google map component under city heading


RocketChat.Migrations.add({
	version: 107,
	up() {
		const roles = RocketChat.models.Roles.find({
			_id: { $ne: 'guest' },
			scope: 'Users'
		}).fetch().map((role)=>{ return role._id; });
		RocketChat.models.Permissions.createOrUpdate('leave-c', roles);
		RocketChat.models.Permissions.createOrUpdate('leave-d', roles);
	}
});

RocketChat.Migrations.add({
	version: 108,
	up() {
		const roles = RocketChat.models.Roles.find({
			_id: { $ne: 'guest' },
			scope: 'Users'
		}).fetch().map((role)=>{ return role._id; });
		RocketChat.models.Permissions.createOrUpdate('leave-c', roles);
		RocketChat.models.Permissions.createOrUpdate('leave-d', roles);
	}
});

Rename migration name on 108 to match file name


var clipper = require('../lib/clipper');

var SCALE = 100;

var PolygonSet = function(polygons) {
  polygons.__proto__ = PolygonSet.prototype;
  return polygons;
};

PolygonSet.prototype = [];

// Merges the polygons in the polygon set.
PolygonSet.prototype.merge = function() {
  var cpr = new clipper.Clipper(),
      solutionPaths = [];

  var subjectPaths = this.map(function(polygon) {
    var path = polygon.map(function(vertex) {
      return {X: vertex[0], Y: vertex[1]};
    });

    clipper.JS.ScaleUpPath(path, SCALE);

    return path;
  });

  cpr.AddPaths(subjectPaths, clipper.PolyType.ptSubject, true);

  cpr.Execute(clipper.ClipType.ctUnion, solutionPaths, clipper.PolyFillType.pftNonZero, clipper.PolyFillType.pftNonZero);

  return solutionPaths.map(function(path) {
    clipper.JS.ScaleDownPath(path, SCALE);

    return path.map(function(point) {
      return [point.X, point.Y];
    });
  })[0];
};

module.exports = PolygonSet;

var clipper = require('../lib/clipper');

var SCALE = 100;

var PolygonSet = function(polygons) {
  this.polygons = polygons;
};

PolygonSet.prototype.constructor = PolygonSet;

// Merges the polygons in the polygon set.
PolygonSet.prototype.merge = function() {
  var cpr = new clipper.Clipper(),
      solutionPaths = [];

  var subjectPaths = this.polygons.map(function(polygon) {
    var path = polygon.map(function(vertex) {
      return {X: vertex[0], Y: vertex[1]};
    });

    clipper.JS.ScaleUpPath(path, SCALE);

    return path;
  });

  cpr.AddPaths(subjectPaths, clipper.PolyType.ptSubject, true);

  cpr.Execute(clipper.ClipType.ctUnion, solutionPaths, clipper.PolyFillType.pftNonZero, clipper.PolyFillType.pftNonZero);

  return solutionPaths.map(function(path) {
    clipper.JS.ScaleDownPath(path, SCALE);

    return path.map(function(point) {
      return [point.X, point.Y];
    });
  })[0];
};

module.exports = PolygonSet;

Change PolygonSet to not inherit from array.


var utils = require("./lib/utils");

var Box = {
  unbox: function(url, destination) {
    return Promise.resolve()
      .then(function() {
        return utils.downloadBox(url, destination)
      })
      .then(function() {
        return utils.unpackBox(destination);
      })
      .then(function(boxConfig) {
        return boxConfig;
      });
  }
};

module.exports = Box;

var utils = require("./lib/utils");

var Box = {
  unbox: function(url, destination, options) {
    options = options || {};
    options.logger = options.logger || {log: function() {}}

    return Promise.resolve()
      .then(function() {
        options.logger.log("Downloading Box");
        return utils.downloadBox(url, destination)
      })
      .then(function() {
        options.logger.log("Unpacking Box");
        return utils.unpackBox(destination);
      })
      .then(function(boxConfig) {
        if (boxConfig.epilogue) {
          options.logger.log(project_config.epilogue.replace("\n", OS.EOL));
        }

        return boxConfig;
      });
  }
};

module.exports = Box;

Add options to unbox() to support logging


import { createUIStore } from 'redux-webext';
import { resetSettings } from './actions';
import addInputBindings from './input-bindings';
import { initKeybindingTable, initSettings } from './dom';

addInputBindings();

createUIStore().then((store) => {
  initSettings(store);
  initKeybindingTable(store);
  // Fill in current keyboard setting in table
  document.getElementById('reset-defaults').addEventListener('click', () => {
    store.dispatch(resetSettings());
    location.reload(true);
  });
  return store;
}).catch((e) => {
  throw e;
});

import { createUIStore } from 'redux-webext';
import { resetSettings } from './actions';
import addInputBindings from './input-bindings';
import { initKeybindingTable, initSettings } from './dom';

addInputBindings();

const appendOsToStore = store =>
  browser.runtime.getPlatformInfo().then(({ os }) => Object.assign({ os }, store));

createUIStore()
  .then(appendOsToStore)
  .then((store) => {
    initSettings(store);
    initKeybindingTable(store);
    document.getElementById('reset-defaults').addEventListener('click', () => {
      store.dispatch(resetSettings());
      location.reload(true);
    });
    return store;
  }).catch((e) => {
    throw e;
  });

Add os to settings store


jQuery(document).ready(function($) {
  $( '.slick' ).slick();
});

jQuery(document).ready(function($) {
  $( '.slick' ).slick({
    'adaptiveHeight': true,
    'autoplay': true,
    'autoplaySpeed': 2000,
    'dots': true
  });
});

Add options to Slick config


import React from 'react';
import { c } from 'ttag';
import { Alert } from '../../components';

const CatchAllSection = () => {
    return (
        <Alert learnMore="https://protonmail.com/support/knowledge-base/catch-all/">{c('Info')
            .t`Catch-All provides ProtonMail Custom Domain users the option to receive all mail sent to their domain, even if it was sent to an email address that has not been setup within their account. To set a catch-all email address, open the dropdown action menu of your custom domain and click on Set catch-all.`}</Alert>
    );
};

export default CatchAllSection;

import React from 'react';
import { c } from 'ttag';
import { Alert } from '../../components';

const CatchAllSection = () => {
    return (
        <Alert learnMore="https://protonmail.com/support/knowledge-base/catch-all/">{c('Info')
            .t`Catch-All provides ProtonMail Custom Domain users the option to receive all mail sent to their domain, even if it was sent to an email address that has not been set up within their account. To set a catch-all email address, open the dropdown action menu of your custom domain and click on Set catch-all.`}</Alert>
    );
};

export default CatchAllSection;

Copy change for Catch-all section


(function() {

  Discourse.addInitializer(function () {

    var applySpoilers = function($post) {
      // text
      $('.spoiler:not(:has(img))', $post).removeClass('spoiler')
                                         .spoilText();
      // images
      $('.spoiler:has(img)', $post).removeClass('spoiler')
                                   .wrap("

")
                                   .spoilImage();
    };

    Em.run.next(function() {
      applySpoilers();

      Discourse.PostView.prototype.on("postViewInserted", applySpoilers);
      Discourse.ComposerView.prototype.on("previewRefreshed", applySpoilers);
    });

  });

})();

(function() {

  Discourse.addInitializer(function () {

    var applySpoilers = function($post) {
      // text
      $('.spoiler:not(:has(img))', $post).removeClass('spoiler')
                                         .spoilText();
      // images
      $('.spoiler:has(img)', $post).removeClass('spoiler')
                                   .wrap("

")
                                   .spoilImage();
    };

    Em.run.next(function() {
      applySpoilers();

      Discourse.PostView.prototype.on("postViewInserted", applySpoilers);
      Discourse.ComposerView.prototype.on("previewRefreshed", applySpoilers);
      Discourse.UserStreamView.prototype.on("didInsertElement", applySpoilers);
    });

  });

})();

Apply spoilers to the entire user activity stream.


import * as pouchdbService from '../services/pouchdbService';
import {
  NEW_ITEM,
  NEW_CATEGORY,
  EDIT_SALARY,
  NEW_INCOME,
} from '../constants/ActionTypes';

import { updateRev } from '../actionCreators/ebudgie';

const storage = store => next => async action => {
  const result = next(action);

  switch (action.type) {
    case NEW_ITEM:
    case NEW_CATEGORY:
    case EDIT_SALARY:
    case NEW_INCOME:
      const state = store.getState();
      const ebudgie = state.ebudgie;

      const savedData = await pouchdbService.updateDocument(ebudgie);
      next(updateRev(savedData.rev));
      break;
  }

  return result;
};

export default storage;

import * as pouchdbService from '../services/pouchdbService';
import {
  NEW_ITEM,
  NEW_CATEGORY,
  EDIT_SALARY,
  NEW_INCOME,
  NEW_EXPENSE,
} from '../constants/ActionTypes';

import { updateRev } from '../actionCreators/ebudgie';

const storage = store => next => async action => {
  const result = next(action);

  switch (action.type) {
    case NEW_ITEM:
    case NEW_CATEGORY:
    case EDIT_SALARY:
    case NEW_INCOME:
    case NEW_EXPENSE:
      const state = store.getState();
      const ebudgie = state.ebudgie;

      const savedData = await pouchdbService.updateDocument(ebudgie);
      next(updateRev(savedData.rev));
      break;
  }

  return result;
};

export default storage;

Store the expense on pounchdb


//@flow

import React from "react";
import styled, { css } from "styled-components";

const StyledHighlight = styled.rect`

  ${({ theme, isActive }: { theme: Theme, isActive: boolean }) => css`

    fill: ${theme.color.pink};
    will-change: transform;
    transition: transform 0.1s ease-in-out;
    transform: scaleX(0);
    transform-origin: 0px 340px;
    ${isActive && css`transform: scaleX(1);`};

  `}
`;

export const Highlight = ({
  isActive
}: {
  isActive: boolean
}): React$Element<*> => (
  <StyledHighlight isActive={isActive} width="520" height="136" y="270" />
);

//@flow

import React from "react";
import styled, { css } from "styled-components";

const StyledHighlight = styled.rect`

  ${({ theme, isActive }: { theme: Theme, isActive: boolean }) => css`

    fill: ${theme.color.pink};
    opacity: 0.8;
    will-change: transform;
    transition: transform 0.1s ease-in-out;
    transform: scaleX(0);
    transform-origin: 0px 340px;
    ${isActive && css`transform: scaleX(1);`};

  `}
`;

export const Highlight = ({
  isActive
}: {
  isActive: boolean
}): React$Element<*> => (
  <StyledHighlight isActive={isActive} width="520" height="136" y="270" />
);

Reduce opacity on LinkedIn icon highlight


import login from 'plug-login'
import socket from 'plug-socket'
import createDebug from 'debug'

const debug = createDebug('miniplug:connect')

export default function connectPlugin (options = {}) {
  return (mp) => {
      // log in
    const loginOpts = { host: options.host, authToken: true }

    function connect (opts) {
      debug('connecting', opts.email)

      const loginPromise = Promise.resolve(
        opts.email
          ? login.user(opts.email, opts.password, loginOpts)
          : login.guest(loginOpts)
      )

      const ws = socket()
      ws.setMaxListeners(100)

      const connected = loginPromise
        .then((res) => new Promise((resolve, reject) => {
          ws.auth(res.token)
          ws.once('error', reject)

          mp.isConnected = true
          mp.emit('login')

          const me = mp.getMe()
          ws.once('ack', () => {
            resolve({ cookie: res.cookie })
            ws.removeListener('error', reject)

            me.then((user) => mp.emit('connected', user))
          })
        }))
        .catch((err) => {
          mp.emit('error', err)
          throw err
        })

      mp.ws = ws
      mp.connected = connected

      return connected
    }

    mp.connect = connect
  }
}

import login from 'plug-login'
import socket from 'plug-socket'
import createDebug from 'debug'

const debug = createDebug('miniplug:connect')
const debugWs = createDebug('miniplug:ws')

export default function connectPlugin (options = {}) {
  return (mp) => {
      // log in
    const loginOpts = { host: options.host, authToken: true }

    function connect (opts) {
      debug('connecting', opts.email)

      const loginPromise = Promise.resolve(
        opts.email
          ? login.user(opts.email, opts.password, loginOpts)
          : login.guest(loginOpts)
      )

      const ws = socket()
      ws.setMaxListeners(100)
      ws.on('action', (type, payload) => {
        debugWs(type, payload)
      })

      const connected = loginPromise
        .then((res) => new Promise((resolve, reject) => {
          ws.auth(res.token)
          ws.once('error', reject)

          mp.isConnected = true
          mp.emit('login')

          const me = mp.getMe()
          ws.once('ack', () => {
            resolve({ cookie: res.cookie })
            ws.removeListener('error', reject)

            me.then((user) => mp.emit('connected', user))
          })
        }))
        .catch((err) => {
          mp.emit('error', err)
          throw err
        })

      mp.ws = ws
      mp.connected = connected

      return connected
    }

    mp.connect = connect
  }
}

Add `miniplug:ws` debug namespace, logging all incoming events


import assert from 'assert';
import { parse } from 'graphql';
import { validate } from 'graphql/validation';
import { buildASTSchema } from 'graphql/utilities/buildASTSchema';
import { kebabCase } from 'lodash';

const DefaultSchema = `
  # Query root
  type Query {
    # Field
    a: String
  }
`;

export function expectFailsRule(rule, schemaSDL, expectedErrors = []) {
  const ast = parse(`${schemaSDL}${DefaultSchema}`);
  const schema = buildASTSchema(ast);
  const errors = validate(schema, ast, [rule]);

  assert(errors.length > 0, "Expected rule to fail but didn't");

  assert.deepEqual(
    errors,
    expectedErrors.map(expectedError => {
      return Object.assign(expectedError, {
        ruleName: kebabCase(rule.name),
        path: undefined,
      });
    })
  );
}

export function expectPassesRule(rule, schemaSDL, expectedErrors = []) {
  const ast = parse(`${schemaSDL}${DefaultSchema}`);
  const schema = buildASTSchema(ast);
  const errors = validate(schema, ast, [rule]);

  assert(
    errors.length == 0,
    `Expected rule to pass but didn't got these errors:\n\n${errors.join('\n')}`
  );
}

import assert from 'assert';
import { parse } from 'graphql';
import { validate } from 'graphql/validation';
import { buildASTSchema } from 'graphql/utilities/buildASTSchema';
import { kebabCase } from 'lodash';
import { validateSchemaDefinition } from '../src/validator.js';
import { Configuration } from '../src/configuration.js';

const DefaultSchema = `
  "Query root"
  type Query {
    "Field"
    a: String
  }
`;

export function expectFailsRule(rule, schemaSDL, expectedErrors = []) {
  return expectFailsRuleWithConfiguration(rule, schemaSDL, {}, expectedErrors);
}

export function expectFailsRuleWithConfiguration(
  rule,
  schemaSDL,
  configurationOptions,
  expectedErrors = []
) {
  const errors = validateSchemaWithRule(rule, schemaSDL, configurationOptions);

  assert(errors.length > 0, "Expected rule to fail but didn't");

  assert.deepEqual(
    errors,
    expectedErrors.map(expectedError => {
      return Object.assign(expectedError, {
        ruleName: kebabCase(rule.name),
        path: undefined,
      });
    })
  );
}

export function expectPassesRule(rule, schemaSDL) {
  expectPassesRuleWithConfiguration(rule, schemaSDL, {});
}

export function expectPassesRuleWithConfiguration(
  rule,
  schemaSDL,
  configurationOptions
) {
  const errors = validateSchemaWithRule(rule, schemaSDL, configurationOptions);

  assert(
    errors.length == 0,
    `Expected rule to pass but didn't got these errors:\n\n${errors.join('\n')}`
  );
}

function validateSchemaWithRule(rule, schemaSDL, configurationOptions) {
  const fullSchemaSDL = `${schemaSDL}${DefaultSchema}`;
  const rules = [rule];
  const configuration = new Configuration(configurationOptions, null);
  const errors = validateSchemaDefinition(fullSchemaSDL, rules, configuration);

  return errors;
}

Add support for specifying configurations in rule test helper


const request = require('request-promise');
const cheerio = require('cheerio');

const BASE_URL = 'https://play.google.com/store/apps/details?hl=en&id=';
const HEADERS = { 'Accept-Language': 'en-US,en;q=0.8' };

function scan(packageName) {
    const cleanPackageName = clean(packageName);
    const config = {
        url: BASE_URL + cleanPackageName,
        headers: HEADERS
    };
    return request(config)
        .then(html => {
            const $ = cheerio.load(html);
            changesList = $('.recent-change')
                .map((i, elem) => $(elem).text())
                .get();
            return result = {
                packageName: cleanPackageName,
                changes: changesList
            };
        });
}

function clean(packageName) {
    const MAX_PACKAGE_LENGTH = 100;
    const NON_ALLOWED_CHARS = /[^\w\.]/g;
    return packageName
        .substr(0, MAX_PACKAGE_LENGTH)
        .replace(NON_ALLOWED_CHARS, '');
}

module.exports = { scan };

const request = require('request-promise');
const cheerio = require('cheerio');
const crypto = require('crypto');

const BASE_URL = 'https://play.google.com/store/apps/details?hl=en&id=';
const HEADERS = { 'Accept-Language': 'en-US,en;q=0.8' };

function scan(packageName) {
    const cleanPackageName = clean(packageName);
    const config = {
        url: BASE_URL + cleanPackageName,
        headers: HEADERS
    };
    return request(config)
        .then(html => {
            const $ = cheerio.load(html);
            changesList = $('.recent-change')
                .map((i, elem) => $(elem).text())
                .get();
            return result = {
                packageName: cleanPackageName,
                changes: changesList,
                changesHash: hash(changesList.join())
            };
        });
}

function clean(packageName) {
    const MAX_PACKAGE_LENGTH = 100;
    const NON_ALLOWED_CHARS = /[^\w\.]/g;
    return packageName
        .substr(0, MAX_PACKAGE_LENGTH)
        .replace(NON_ALLOWED_CHARS, '');
}

function hash(payload) {
    return crypto.createHash('md5')
        .update(payload, 'utf8')
        .digest('base64');
}

module.exports = { scan };

Add hash of the changes to the response to facilitate comparison


/*jshint node:true,laxcomma:true*/
/* global describe, it */
'use strict';
var assert = require('assert')
  , JBJ = require('jbj');

JBJ.use(require('..'));

describe('asynchronous error', function () {

  var input = {
    "a" : {
      "b" : {
        "c" : "1234"
      },
      "d" : null
    }
  };

  it('error #1', function(done) {
    var stylesheet = {
      "$a" : {
        "set" : "\"xxxx",
        "parseJSON" : true
      }
    };
    JBJ.render(stylesheet, input, function (err, output) {
      assert.equal(err.name, 'SyntaxError');
      done();
    });

  });

});

/*jshint node:true,laxcomma:true*/
/* global describe, it */
'use strict';
var assert = require('assert')
  , JBJ = require('jbj');

JBJ.use(require('..'));

describe('asynchronous error', function () {

  var input = {
    "a" : {
      "b" : {
        "c" : "1234"
      },
      "d" : null
    }
  };

  it('error #1', function(done) {
    var stylesheet = {
      "$a" : {
        "set" : "\"xxxx",
        "parseJSON" : true
      }
    };
    JBJ.render(stylesheet, input, function (err, output) {
      assert.equal(err.name, 'SyntaxError');
      done();
    });
  });

  it('error #2', function(done) {
    var stylesheet = {
      "assert" : "a == 'X'"
    };
    JBJ.render(stylesheet, input, function (err, output) {
      assert.equal(err.name, 'Error');
      done();
    });
  });

});

Add a long ago written test


define([], function () {
  return {
    hasLoggedInUser: function() {
        return !!this.profile.get('username');
    },
    profile: null
  }
});

define([], function () {
  return {
    hasLoggedInUser: function() {
        return !!(this.profile && this.profile.get('username'));
    },
    profile: null
  }
});

Change boolean check to utilize shortciruit


/*global angular*/
angular.module('post')
	/**
    * @ngdoc controller
    * @name post.controller:PostMainController
    *
    * @description
    * # main post controller
    *
    * The main post controller
    *
    */
    .controller('PostMainController', ["PostManager", function (PostManager) {
		"use strict";
		var scope = this;
		scope.text = "Hello world !";

		scope.init = function () {
	        scope.getPosts();
	    };

		scope.getPosts = function () {
			return PostManager.getPosts()
				.then(function (posts) {
					return posts;
				});
		};

	}]);

Indent code after changing editor to netbeans.


module.exports = require('proof')(function () {
    var register = require('../../register')
    var stream = require('stream')
    var path = require('path')
    return {
        once: function (step, directory, argv, stdin) {
            step(function () {
                register.once(__dirname, directory, argv, stdin, step())
            }, function (request, server) {
                var stdout = new stream.PassThrough
                stdout.setEncoding('utf8')
                step(function () {
                    request.pipe(stdout)
                    request.on('end', step(-1))
                    if (!server.closed) server.on('close', step(-1))
                }, function () {
                    return {
                        statusCode: request.statusCode,
                        headers: request.headers,
                        body: stdout.read()
                    }
                })
            })
        }
    }
})

module.exports = require('proof')(function () {
    var register = require('../../register')
    var stream = require('stream')
    var path = require('path')
    var once = require('../../once')
    return {
        once: function (step, path, parameters, stdin) {
            return once(__dirname + '/' + path, parameters, stdin, step())
        }
    }
})

Use module `once` method in test harness.


import Ember from 'ember';
import config from './config/environment';

const Router = Ember.Router.extend({
  location: config.locationType,
  rootURL: config.rootURL
});

Router.map(function() {
  this.route('about');
  this.route('top-picks');
  this.route('trending');
  this.route('food',{path:'food/:params.location'});
  this.route('coffee');
  this.route('breakfast');
  this.route('nightlife');
  this.route('shopping');
  this.route('fun');
  this.route('view-venue');
  this.route('events');
});

export default Router;

import Ember from 'ember';
import config from './config/environment';

const Router = Ember.Router.extend({
  location: config.locationType,
  rootURL: config.rootURL
});

Router.map(function() {
  this.route('about');

  this.route('top-picks');

  this.route('trending');

  this.route('food', {
    path: 'food/:params.location'
  });

  this.route('coffee');

  this.route('breakfast');

  this.route('nightlife', {
    path: 'nightlife/:params.location'
  });

  this.route('shopping');

  this.route('fun');

  this.route('view-venue');

  this.route('events');
});

export default Router;

Add dynamic segment to nightlife route


module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: '<json:package.json>',
    test: {
      files: ['test/**/*.js']
    },
    lint: {
      files: ['grunt.js', 'tasks/**/*.js', 'test/**/*.js']
    },
    watch: {
      files: '<config:lint.files>',
      tasks: 'default'
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        node: true,
        trailing: true
      },
      globals: {
        exports: true
      }
    },
    csslint: {
      valid: 'test/valid.css',
      empty: 'test/empty.css',
      all: 'test/*.css'
    }
  });

  // Load local tasks.
  grunt.loadTasks('tasks');

  // Default task. csslint:all will fail, that's okay until there's unit tests
  grunt.registerTask('default', 'lint csslint');

};

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: '<json:package.json>',
    test: {
      files: ['test/**/*.js']
    },
    lint: {
      files: ['grunt.js', 'tasks/**/*.js', 'test/**/*.js']
    },
    watch: {
      files: '<config:lint.files>',
      tasks: 'default'
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        node: true,
        trailing: true
      },
      globals: {
        exports: true
      }
    },
    csslint: {
      valid: 'test/valid.css',
      empty: 'test/empty.css',
      all: 'test/*.css'
    },
    banner: '/*my awesome css banner */',
    cssmin: {
      plain: {
        src: 'test/valid.css',
        dest: 'valid.min.css'
      },
      banner: {
        src: ['<banner:banner>', 'test/valid.css' ],
        dest: 'valid.min.banner.css'
      }
    }
  });

  // Load local tasks.
  grunt.loadTasks('tasks');

  // Default task. csslint:all will fail, that's okay until there's unit tests
  grunt.registerTask('default', 'lint csslint');

};

Add test files for cssmin with and without banner


'use strict';

angular.module('myApp.view1', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view1', {
    templateUrl: 'view1/view1.html',
    controller: 'View1Ctrl'
  });
}])

.controller('View1Ctrl', ['$scope', function(sc) {

	sc.timeSlotOptions = [
    { label: '06:30am', value: '06:30' },
    { label: '07:00am', value: '07:00' }
  ];

	sc.timeSlotSelected = sc.timeSlotOptions[0];

	//this.slots = ["06:00am", "06:30am", "07:00am"];

	// create and initialise function that is called on page load

	// generate an array of time slots and bind to a model

}]);

//var slots = ["06:00am", "06:30am", "07:00am"];

'use strict';

angular.module('myApp.view1', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/view1', {
    templateUrl: 'view1/view1.html',
    controller: 'View1Ctrl'
  });
}])

.controller('View1Ctrl', ['$scope', 'timeSlotService', function($scope, timeSlotService) {

	// inject time object?

	// test output? Against scope?

	$scope.timeSlotOptions = [
    { label: '06:30am', value: '06:30' },
    { label: '07:00am', value: '07:00' }
  ];

	$scope.timeSlotSelected = $scope.timeSlotOptions[0];

}])

.factory('timeSlotService', ['$window', 'currentTimeService', function(win, currentTimeService) {
  var timeSlotServiceInstance;

  // factory function body that constructs shinyNewServiceInstance

  win.console.log(currentTimeService);

  return timeSlotServiceInstance;
}])

.factory('currentTimeService', ['$window', function(win) {
  return new Date(); // easier way to inject in a date?
}])

;

Set up services to contain logic and inject in date wrapper


'use strict';

var octet = require('octet');
var merge = require('merge');
var Promise = require('promise');

exports.name = 'octet';
exports.outputFormat = 'html';

exports.render = function (str, options, locals) {
  var result = octet(str, merge(options, locals));
  if (result.err) {
    throw new Error(result.err);
  }
  else {
    return result.res;
  }
};

exports.renderAsync = function (str, options, locals) {
  return new Promise(function (fulfill, reject) {
    octet(str, merge(options, locals), function (err, output) {
      if (err) {
        return reject(err);
      }
      else {
        return fulfill(output);
      }
    });
  });
};

Remove renderAsync() since it's sync anyway


/* jshint node: true */
'use strict';

var path = require('path'),
  path_join = function () {
  // fix path with windows back slash with path_join
  return path.join.apply(this, arguments).replace(/\\/g, '/');
};

module.exports = {
  name: 'ember-cli-chartist',

  included: function included(app) {
    this.app = app;

    var options = app.options['ember-cli-chartist'] || {},
      modulePath = path.relative(app.project.root, __dirname),
      chartistPath = 'vendor/chartist';

    if (options.useDefaultCSS) {
      app.import('vendor/chartist/chartist.css');
    } else {
      // NOTE: This is not working currently. apps are not recognizing the
      // includePaths set here.
      app.options.sassOptions = app.options.sassOptions || {};
      app.options.sassOptions.includePaths = app.options.sassOptions.includePaths || [];

      app.options.sassOptions.includePaths.push(path_join(modulePath,
        chartistPath, 'scss'));

      app.options.sassOptions.includePaths.push(path_join(modulePath,
        chartistPath, 'scss/settings'));
    }

    app.import('vendor/chartist/chartist.js');
  }
};

/* jshint node: true */
'use strict';

var path = require('path'),
  path_join = function () {
  // fix path with windows back slash with path_join
  return path.join.apply(this, arguments).replace(/\\/g, '/');
};

module.exports = {
  name: 'ember-cli-chartist',

  included: function included(app) {
    this.app = app;

    var options = app.options['ember-cli-chartist'] || {},
      modulePath = path.relative(app.project.root, __dirname),
      chartistPath = 'vendor/chartist';

    if (options.useCustomCSS) {
      app.options.sassOptions = app.options.sassOptions || {};
      app.options.sassOptions.includePaths = app.options.sassOptions.includePaths || [];

      app.options.sassOptions.includePaths.push(path_join(modulePath,
        chartistPath, 'scss'));

      app.options.sassOptions.includePaths.push(path_join(modulePath,
        chartistPath, 'scss/settings'));
    } else {
      app.import('vendor/chartist/chartist.css');
    }

    app.import('vendor/chartist/chartist.js');
  }
};

Use the precompiled css by default, allow an option to use scss


const { send } = require('micro')

const errorHandler = next => async (req, res) => {
  try {
    return await next(req, res)
  } catch (err) {
    const code = err.statusCode || 500
    const message = err.message || 'Unknown Error'
    const payload = {
     error: {
       code,
       message,
     }
    }
    if (process.env.NODE_ENV === 'development') {
      payload.error.stack = err.stack;
    }
    send(res, code, payload)
  }
}

module.exports = {
  errorHandler,
}

const { send } = require('micro')

const errorHandler = next => (req, res) => {
  try {
    return next(req, res)
  } catch (err) {
    const code = err.statusCode || 500
    const message = err.message || 'Unknown Error'
    const payload = {
      error: {
        code,
        message,
      },
    }
    if (process.env.NODE_ENV === 'development') {
      console.error(err)
      payload.error.stack = err.stack
    }
    return send(res, code, payload)
  }
}

module.exports = {
  errorHandler,
}

Clean up and print error in dev mode


var app = require('./server/server.js');

var port = process.env.port || 3000;
app.listen(port, function() {
  console.log('Server is listening on ' + port);
});

var app = require('./server/server.js');

var port = process.env.PORT || 3000;
app.listen(port, function() {
  console.log('Server is listening on ' + port);
});

Change port syntax to fit deployment


'use strict';
const execBuffer = require('exec-buffer');
const isPng = require('is-png');
const optipng = require('optipng-bin');

module.exports = opts => buf => {
	opts = Object.assign({optimizationLevel: 3}, opts);

	if (!Buffer.isBuffer(buf)) {
		return Promise.reject(new TypeError('Expected a buffer'));
	}

	if (!isPng(buf)) {
		return Promise.resolve(buf);
	}

	const args = [
		'-strip', 'all',
		'-clobber',
		'-force',
		'-fix',
		'-o', opts.optimizationLevel,
		'-out', execBuffer.output,
		execBuffer.input
	];

	return execBuffer({
		input: buf,
		bin: optipng,
		args
	}).catch(err => {
		err.message = err.stderr || err.message;
		throw err;
	});
};

'use strict';
const execBuffer = require('exec-buffer');
const isPng = require('is-png');
const optipng = require('optipng-bin');

module.exports = opts => buf => {
	opts = Object.assign({optimizationLevel: 3}, opts);

	if (!Buffer.isBuffer(buf)) {
		return Promise.reject(new TypeError('Expected a buffer'));
	}

	if (!isPng(buf)) {
		return Promise.resolve(buf);
	}

	const args = [
		'-strip', 'all',
		'-clobber',
		'-fix',
		'-o', opts.optimizationLevel,
		'-out', execBuffer.output,
		execBuffer.input
	];

	return execBuffer({
		input: buf,
		bin: optipng,
		args
	}).catch(err => {
		err.message = err.stderr || err.message;
		throw err;
	});
};

Fix misuse of `-force` flag


var helpers = require('./lib/helpers.js');

/**
 Gets helpers in the provided location?
 */
module.exports.getHelpers = function (location) {
    if (location === 'Intl') {
        return helpers;
    } else {
        return {};
    }
};

/**
 Registers the helper on the provided handlebars engine
 @method registerHelpers
 @param {Object} engine
 */
module.exports.registerHelpers = function (engine) {
    helpers.register(engine);
};

var helpers = require('./lib/helpers.js');

/**
 Gets helpers in the provided location?
 */
module.exports.getHelpers = function (location) {
    return helpers.helpers;
};

/**
 Registers the helper on the provided handlebars engine
 @method registerHelpers
 @param {Object} engine
 */
module.exports.registerHelpers = function (engine) {
    helpers.register(engine);
};

Remove unnecessary complexity from getHelpers.


module.exports.onWindow = browserWindow => browserWindow.setVibrancy('dark');

const foregroundColor = '#fff';
const backgroundColor = 'rgba(31, 43, 49, .96)';
const darkerBackgroundColor = 'rgba(28, 40, 46, .30)';
const red = '#ff5c57';
const green = '#5af78e';
const yellow = '#fefe7a';
const blue = '#57b7ff';
const magenta = '#ff6ac1';
const cyan = '#98edff';
const white = '#fff';

exports.decorateConfig = (config) => Object.assign({}, config, {
  backgroundColor,
  foregroundColor,
  borderColor: darkerBackgroundColor,
  cursorColor: white,
  colors: {
    black: backgroundColor,
    red,
    green,
    yellow,
    blue,
    magenta,
    cyan,
    white,
    lightBlack: '#686868',
    lightRed: red,
    lightGreen: green,
    lightYellow: yellow,
    lightBlue: blue,
    lightMagenta: magenta,
    lightCyan: cyan,
    lightWhite: foregroundColor
  },
  css: `
    ${config.css}
    .hyper_main {
      border: none !important;
    }
    .header_header {
      background-color: ${darkerBackgroundColor} !important;
    }
    .tabs_borderShim {
      border-color: transparent !important;
    }
    .tab_tab {
      border: 0;
    }
    .tab_textActive {
      border-bottom: 2px solid ${green};
    }
  `
});

module.exports.onWindow = browserWindow => browserWindow.setVibrancy('dark');

const foregroundColor = '#fff';
const backgroundColor = 'rgba(31, 43, 49, .40)';
const overlap = 'rgba(28, 40, 46, .20)';
const red = '#ff5c57';
const green = '#5af78e';
const yellow = '#fefe7a';
const blue = '#57b7ff';
const magenta = '#ff6ac1';
const cyan = '#98edff';
const white = '#fff';

exports.decorateConfig = (config) => Object.assign({}, config, {
  backgroundColor,
  foregroundColor,
  borderColor: overlap,
  cursorColor: white,
  colors: {
    black: backgroundColor,
    red,
    green,
    yellow,
    blue,
    magenta,
    cyan,
    white,
    lightBlack: '#686868',
    lightRed: red,
    lightGreen: green,
    lightYellow: yellow,
    lightBlue: blue,
    lightMagenta: magenta,
    lightCyan: cyan,
    lightWhite: foregroundColor
  },
  css: `
    ${config.css}
    .hyper_main {
      border: none !important;
    }
    .header_header {
      background-color: ${overlap} !important;
    }
    .tabs_borderShim {
      border-color: transparent !important;
    }
    .tab_tab {
      border: 0;
    }
    .tab_textActive {
      border-bottom: 2px solid ${green};
    }
  `
});

Fix background color transparencies to match new vibrancy behaviour


var fs               = require('fs')
  , findExec         = require('find-exec')
  , child_process    = require('child_process')
  , players          = [
                        'mplayer',
                        'afplay',
                        'mpg123',
                        'mpg321',
                        'play'
                       ]

function Play(opts){
  opts               = opts               || {}

  this.players       = opts.players       || players
  this.player        = opts.player        || findExec(this.players)

  var exec           = child_process.exec

  this.play = function(what, next){
    next = next || function(){}

    if (!what) return next(new Error("No audio file specified"));

    try {
      if (!fs.statSync(what).isFile()){
        return next(new Error(what + " is not a file"));
      }
    } catch (err){
      return next(new Error("File doesn't exist: " + what));
    }

    if (!this.player){
      return next(new Error("Couldn't find a suitable audio player"))
    }

    exec(this.player + ' ' + what, function(err, stdout, stderr){
      return next(err);
    })
  }

  this.test = function(next) { this.play('./assets/test.mp3', next) }
}

module.exports = function(opts){
  return new Play(opts)
}

var fs               = require('fs')
  , findExec         = require('find-exec')
  , child_process    = require('child_process')
  , players          = [
                        'mplayer',
                        'afplay',
                        'mpg123',
                        'mpg321',
                        'play'
                       ]

function Play(opts){
  opts               = opts               || {}

  this.players       = opts.players       || players
  this.player        = opts.player        || findExec(this.players)

  var exec           = child_process.exec

  this.play = function(what, next){
    next = next || function(){}

    if (!what) return next(new Error("No audio file specified"));

    try {
      if (!fs.statSync(what).isFile()){
        return next(new Error(what + " is not a file"));
      }
    } catch (err){
      return next(new Error("File doesn't exist: " + what));
    }

    if (!this.player){
      return next(new Error("Couldn't find a suitable audio player"))
    }

    exec(this.player + ' ' + what, function(err, stdout, stderr){
      next(err);
    })
  }

  this.test = function(next) { this.play('./assets/test.mp3', next) }
}

module.exports = function(opts){
  return new Play(opts)
}

Remove useless return in exec() callback


'use strict';

const compose = require('compose-middleware').compose;
const merge = require('lodash.merge');
const standardFs = require('./lib/fs/standardFs');
const memoryFs = require('./lib/fs/memoryFs');
const mainMiddleware = require('./lib/mainMiddleware');
const devMiddleware = require('./lib/devMiddleware');
const renderErrorMiddleware = require('./lib/renderErrorMiddleware');

function middleware(compiler, options) {
    options = merge({
        memoryFs: true,  // Enable memory fs
        watchOptions: { report: { stats: 'once' } },  // Options to pass to .watch()
        headers: null,  // Headers to set when serving compiled files, see https://github.com/webpack/webpack-dev-middleware
    }, options);

    // Set output filesystems
    compiler.client.webpackCompiler.outputFileSystem = options.memoryFs ? memoryFs() : standardFs();
    compiler.server.webpackCompiler.outputFileSystem = options.memoryFs ? memoryFs() : standardFs();

    // Create middleware by composing our parts
    const middleware = compose([
        mainMiddleware(compiler, options),
        devMiddleware(compiler, options),
        renderErrorMiddleware,
    ]);

    // Start watching
    options.watchOptions !== false && compiler.watch(options.watchOptions);

    return middleware;
}

module.exports = middleware;

'use strict';

const compose = require('compose-middleware').compose;
const merge = require('lodash.merge');
const standardFs = require('./lib/fs/standardFs');
const memoryFs = require('./lib/fs/memoryFs');
const mainMiddleware = require('./lib/mainMiddleware');
const devMiddleware = require('./lib/devMiddleware');
const renderErrorMiddleware = require('./lib/renderErrorMiddleware');

function middleware(compiler, options) {
    options = merge({
        memoryFs: true,  // Enable memory fs
        watchOptions: { report: { stats: 'once' } },  // Options to pass to .watch()
        headers: null,  // Headers to set when serving compiled files, see https://github.com/webpack/webpack-dev-middleware
    }, options);

    // Set output filesystems
    const fs = options.memoryFs ? memoryFs() : standardFs();

    compiler.client.webpackCompiler.outputFileSystem = fs;
    compiler.server.webpackCompiler.outputFileSystem = fs;

    // Create middleware by composing our parts
    const middleware = compose([
        mainMiddleware(compiler, options),
        devMiddleware(compiler, options),
        renderErrorMiddleware,
    ]);

    // Start watching
    options.watchOptions !== false && compiler.watch(options.watchOptions);

    return middleware;
}

module.exports = middleware;

Use same fs for client & server.


'use strict';

module.exports = [
    'admin.cgi',
    'administrator.cgi',
    'backup.cgi',
    'cgi-bin/common/attr', // open proxy test
    'cgi-bin/printenv',
    'concept.cgi',
    'count.cgi',
    'counter.cgi',
    'firewall.cgi',
    'formmail.cgi',
    'getheaders2.php',
    'getheaders9.php',
    'helpdesk.cgi',
    'index.cgi',
    'index2.cgi',
    'info.cgi',
    'kontakt.cgi',
    'main.cgi',
    'muieblackcat', // Muieblackcat http://eromang.zataz.com/2011/08/14/suc027-muieblackcat-setup-php-web-scanner-robot/
    'zmap.io', // https://zmap.io/
    'query.cgi',
    'reboot.cgi',
    'report.cgi',
    'scripts/setup.php', // phpMyAdmin setup path
    'supply.cgi',
    'test.sh',
    'testproxy.php', // open proxy test
    'tmunblock.cgi',
    'webmap.cgi',
    'whois.cgi'
];

'use strict';

module.exports = [
    'admin.cgi',
    'administrator.cgi',
    'backup.cgi',
    'cgi-bin/bash',
    'cgi-bin/common/attr', // open proxy test
    'cgi-bin/printenv',
    'concept.cgi',
    'contact.cgi',
    'count.cgi',
    'counter.cgi',
    'defaultwebpage.cgi',
    'env.cgi',
    'fire.cgi',
    'firewall.cgi',
    'formmail.cgi',
    'getheaders2.php',
    'getheaders9.php',
    'hello.cgi',
    'helpdesk.cgi',
    'index.cgi',
    'index2.cgi',
    'info.cgi',
    'kontakt.cgi',
    'login.cgi',
    'main.cgi',
    'meme.cgi',
    'muieblackcat', // Muieblackcat http://eromang.zataz.com/2011/08/14/suc027-muieblackcat-setup-php-web-scanner-robot/
    'query.cgi',
    'reboot.cgi',
    'report.cgi',
    'scripts/setup.php', // phpMyAdmin setup path
    'supply.cgi',
    'test.sh',
    'testproxy.php', // open proxy test
    'tmunblock.cgi',
    'user/soapcaller.bs',
    'webmap.cgi',
    'whois.cgi',
    'zmap.io' // https://zmap.io/
];

Add a few more cgi paths


'use strict';

const EventEmitter = require('events');

const devtools = require('./lib/devtools');
const Chrome = require('./lib/chrome');

module.exports = function (options, callback) {
    if (typeof options === 'function') {
        callback = options;
        options = undefined;
    }
    const notifier = new EventEmitter();
    if (typeof callback === 'function') {
        // allow to register the error callback later
        process.nextTick(function () {
            new Chrome(options, notifier);
        });
        return notifier.on('connect', callback);
    } else {
        return new Promise(function (fulfill, reject) {
            notifier.on('connect', fulfill);
            notifier.on('error', reject);
            new Chrome(options, notifier);
        });
    }
};

// for backward compatibility
module.exports.listTabs = devtools.List;
module.exports.spawnTab = devtools.New;
module.exports.closeTab = devtools.Close;

module.exports.Protocol = devtools.Protocol;
module.exports.List = devtools.List;
module.exports.New = devtools.New;
module.exports.Activate = devtools.Activate;
module.exports.Close = devtools.Close;
module.exports.Version = devtools.Version;

'use strict';

const EventEmitter = require('events');

const devtools = require('./lib/devtools');
const Chrome = require('./lib/chrome');

module.exports = function (options, callback) {
    if (typeof options === 'function') {
        callback = options;
        options = undefined;
    }
    const notifier = new EventEmitter();
    if (typeof callback === 'function') {
        // allow to register the error callback later
        process.nextTick(function () {
            new Chrome(options, notifier);
        });
        return notifier.once('connect', callback);
    } else {
        return new Promise(function (fulfill, reject) {
            notifier.once('connect', fulfill);
            notifier.once('error', reject);
            new Chrome(options, notifier);
        });
    }
};

// for backward compatibility
module.exports.listTabs = devtools.List;
module.exports.spawnTab = devtools.New;
module.exports.closeTab = devtools.Close;

module.exports.Protocol = devtools.Protocol;
module.exports.List = devtools.List;
module.exports.New = devtools.New;
module.exports.Activate = devtools.Activate;
module.exports.Close = devtools.Close;
module.exports.Version = devtools.Version;

Emphasize that events fire just once


var util = require('util');

var DECLARATION = 'window.__env__ = window.__env__ || {};\n',
    TEMPLATE = function(name) {
      var tmpl = 'window.__env__[\'%s\'] = \'%s\';\n'
      return util.format(tmpl, name, process.env[name]);
    };

var createEnvPreprocessor = function(args, config, logger, helper) {
  var log = logger.create('preprocessor.env'),
      names = config.envPreprocessor || [];
  log.info('Publishing variables: ', names);

  return function(content, file, done) {
    var envContent = DECLARATION;

    for (var i in names) {
      envContent += TEMPLATE(names[i]);
    }

    done(envContent + '\n' + content);
  };

};

module.exports = {
  'preprocessor:env': ['factory', createEnvPreprocessor]
};

var util = require('util');

var DECLARATION = 'window.__env__ = window.__env__ || {};\n',
    TEMPLATE = function(name) {
      if (typeof process.env[name] !== 'undefined') {
        var tmpl = 'window.__env__[\'%s\'] = %s;\n';
        return util.format(tmpl, name, process.env[name]);
      } else {
        return '';
      }
    };

var createEnvPreprocessor = function(args, config, logger, helper) {
  var log = logger.create('preprocessor.env'),
      names = config.envPreprocessor || [];
  log.info('Publishing variables: ', names);

  return function(content, file, done) {
    var envContent = DECLARATION;

    for (var i in names) {
      envContent += TEMPLATE(names[i]);
    }

    done(envContent + '\n' + content);
  };

};

module.exports = {
  'preprocessor:env': ['factory', createEnvPreprocessor]
};

Exclude environment variables which are not defined


'use strict';

module.exports = {
  name: require('./package').name,

  config(environment, appConfig) {
    const addonConfig = appConfig['emberKeyboard'] || {};

    if ('disableInputsInitializer' in addonConfig) {
      this.ui.writeDeprecateLine(
        '[ember-keyboard] The `emberKeyboard.disableInputsInitializer` option is obsolete. ' +
        'You can remove it from your `config/environment.js` file.', false
      );
    }
  },
};

'use strict';

module.exports = {
  name: require('./package').name,

  config(environment, appConfig) {
    const addonConfig = appConfig['emberKeyboard'] || {};

    if ('disableInputsInitializer' in addonConfig && !this.deprecationPrinted) {
      // Do not print deprecation message multiple times
      // as this hook may be invoked more than once.
      this.deprecationPrinted = true;

      this.ui.writeDeprecateLine(
        '[ember-keyboard] The `emberKeyboard.disableInputsInitializer` option is obsolete. ' +
        'You can remove it from your `config/environment.js` file.', false
      );
    }
  },
};

Make sure disableInputsInitializer deprecation printed only once


'use strict';

import { NativeAppEventEmitter, NativeModules } from 'react-native';
const ReactNativeBluetooth = NativeModules.ReactNativeBluetooth;

const didChangeState = (callback) => {
  var subscription = NativeAppEventEmitter.addListener(
    ReactNativeBluetooth.StateChanged,
    callback
  );

  ReactNativeBluetooth.notifyCurrentState();

  return function() {
    subscription.remove();
  };
};

const DefaultScanOptions = {
  uuids: [],
  timeout: 10000,
};

const Scan = {
  stopAfter: (timeout) => {
    return new Promise(resolve => {
      setTimeout(() => {
        ReactNativeBluetooth.stopScan()
          .then(resolve)
          .catch(console.log.bind(console));
      }, timeout);
    })
  }
}

const startScan = (customOptions = {}) => {
  let options = Object.assign({}, DefaultScanOptions, customOptions);

  return ReactNativeBluetooth.startScan(options.uuids).then(() => Scan);
}

const didDiscoverDevice = (callback) => {
  var subscription = NativeAppEventEmitter.addListener(
    ReactNativeBluetooth.DeviceDiscovered,
    callback
  );

  return function() {
    subscription.remove();
  };
};

export default {
  didChangeState,
  startScan,
  didDiscoverDevice,
};

'use strict';

import { NativeAppEventEmitter, NativeModules } from 'react-native';
const ReactNativeBluetooth = NativeModules.ReactNativeBluetooth;

const didChangeState = (callback) => {
  var subscription = NativeAppEventEmitter.addListener(
    ReactNativeBluetooth.StateChanged,
    callback
  );

  ReactNativeBluetooth.notifyCurrentState();

  return function() {
    subscription.remove();
  };
};

const DefaultScanOptions = {
  uuids: [],
};

const Scan = {
  stopAfter: (timeout) => {
    return new Promise(resolve => {
      setTimeout(() => {
        ReactNativeBluetooth.stopScan()
          .then(resolve)
          .catch(console.log.bind(console));
      }, timeout);
    })
  }
}

const startScan = (customOptions = {}) => {
  let options = Object.assign({}, DefaultScanOptions, customOptions);

  return ReactNativeBluetooth.startScan(options.uuids).then(() => Scan);
}

const didDiscoverDevice = (callback) => {
  var subscription = NativeAppEventEmitter.addListener(
    ReactNativeBluetooth.DeviceDiscovered,
    callback
  );

  return function() {
    subscription.remove();
  };
};

export default {
  didChangeState,
  startScan,
  didDiscoverDevice,
};

Remove useless timeout from DefaultScanOptions


import { timer as d3Timer } from 'd3-timer';

export default function PeriodicJS(opts) {

	const { duration, displaySelector, callback } = opts;
	let timer;

	function displayTimeLeft(time) {

		// find the current displayed time
		let element = document.querySelector(displaySelector);
		const currentDisplayedTime = element.innerHTML;

		// format incoming time
		const formattedTime = Math.ceil(time/1000);

		// don't update dom element with same string
		if (formattedTime.toString() !== currentDisplayedTime) {
			element.innerHTML = 'update in ' + formattedTime;
		}

	}

	function run() {

		timer = d3Timer((elapsed, time) => {

			// tell user how much time is left
			displayTimeLeft(duration - elapsed);

			// are we done?
			if (elapsed > duration) {
				timer.stop();

				// call user-provided callback, and pass along run,
				// so they can resume the timer, if so desired
				callback(run);
			}

		});

	}

	run();
}

import { timer as d3Timer } from 'd3-timer';

export default function PeriodicJS(opts) {

	const { duration, displaySelector, callback, runImmediately } = opts;
	let timer;

	function displayTimeLeft(time) {

		// find the current displayed time
		let element = document.querySelector(displaySelector);
		const currentDisplayedTime = element.innerHTML;

		// format incoming time
		const formattedTime = Math.ceil(time/1000);

		// don't update dom element with same string
		if (formattedTime.toString() !== currentDisplayedTime) {
			element.innerHTML = 'Update in ' + formattedTime;
		}

	}

	function run() {

		timer = d3Timer((elapsed, time) => {

			// tell user how much time is left
			displayTimeLeft(duration - elapsed);

			// are we done?
			if (elapsed > duration) {
				timer.stop();

				// call user-provided callback, and pass along run,
				// so they can resume the timer, if so desired
				callback(run);
			}

		});

	}

	if (runImmediately) {
		callback(run);
	} else {
		run();
	}

}

Support running the callback immediately


Feature('Render The Map');

Scenario('CartoDB loads the leaflet map', function* (I) {

  I.amOnPage('/test/examples/leaflet.html');

  I.seeInTitle('CartoDB.js example');

  let cartodbType = yield I.executeScript(function () {
    return typeof CartoDB;
  });

  let assert = require('assert');

  // CartoDB library is loaded
  assert.equal(cartodbType, 'function');

  // Map is initalized
  I.seeElement('#map.leaflet-container');

  // It draws 3 layers
  I.waitNumberOfVisibleElements('#map .leaflet-layer', 3);
});

Feature('Render The Map');

Scenario('CartoDB loads the leaflet map', function* (I) {

  I.amOnPage('/test/examples/leaflet.html');

  I.seeInTitle('CartoDB.js example');

  let cartodbType = yield I.executeScript(function () {
    return typeof CartoDB;
  });

  let assert = require('assert');

  // CartoDB library is loaded
  assert.equal(cartodbType, 'function');

  // Map is initalized
  I.seeElement('#map.leaflet-container');

  // It draws 3 layers
  I.waitNumberOfVisibleElements('#map .leaflet-layer', 3, 5);
});

Increase wait time in acceptance test


#! /usr/bin/env node

var fs = require('fs-promise');
var compiler = require('./compiler');

fs.lstat('tomahawk/resolver.js').then(function(stats) {
    if(!stats.isFile()) {
        throw new Error();
    }
}, function () {
    throw new Error('tomahawk/resolver.js not a file, probably not in tomahawk-resolvers main dir');
}).then(function() {
    var args = process.argv.slice(2);
     return compiler(args[0]);
}).then(function(output) {
    console.log(output.code);
}, function(err) {
    console.error(err);
});

#! /usr/bin/env node

var fs = require('fs-promise');
var compiler = require('./compiler');

fs.lstat('tomahawk/resolver.js').then(function(stats) {
    if(!stats.isFile()) {
        throw new Error();
    }
}, function () {
    throw new Error('tomahawk/resolver.js not a file, probably not in tomahawk-resolvers main dir');
}).then(function() {
    var args = process.argv;
     return compiler(args[args.length-1]);
}).then(function(output) {
    console.log(output.code);
}, function(err) {
    console.error(err);
});

Fix argv usage for uncompiled and for jxcore bundled package usage


const path = require("path");
const rootDir = path.normalize(path.join(__dirname, ".."));
const tester = path.join(rootDir, "node_modules", "vscode", "bin", "test");
const cp = require("child_process");
let tests = process.argv.slice(2);
let failed = 0;

tests.forEach((test) => {
    let [ testName, wsName ] = test.split("@", 2);
    if (wsName == null) {
        wsName = testName;
    }
    let testRoot = path.join(rootDir, "out", "test", testName);
    let workspace = path.join(rootDir, "test", "workspace", wsName);
    console.log("#".repeat(100));
    console.log(`# [${test}] Started at ${new Date().toString()}`);
    console.log("");
    let result = cp.spawnSync("node", [tester], {
        env: {
            CODE_TESTS_PATH: testRoot,
            CODE_TESTS_WORKSPACE: workspace
        },
        stdio: "inherit"
    });
    console.log(`# [${test}] Finished at ${new Date().toString()} (result=${result.status})`);
    if (result.status !== 0) {
        console.error(`${result.error}`);
        ++failed;
    }
    console.log("");
});

if (failed > 0) {
    process.exitCode = 1;
}

const path = require("path");
const rootDir = path.normalize(path.join(__dirname, ".."));
const tester = path.join(rootDir, "node_modules", "vscode", "bin", "test");
const cp = require("child_process");
let tests = process.argv.slice(2);
let failed = 0;

tests.forEach((test) => {
    let [ testName, wsName ] = test.split("@", 2);
    if (wsName == null) {
        wsName = testName;
    }
    let testRoot = path.join(rootDir, "out", "test", testName);
    let workspace = path.join(rootDir, "test", "workspace", wsName);
    console.log("#".repeat(100));
    console.log(`# [${test}] Started at ${new Date().toString()}`);
    console.log("");
    let result = cp.spawnSync(process.argv0, [tester], {
        env: {
            CODE_TESTS_PATH: testRoot,
            CODE_TESTS_WORKSPACE: workspace
        },
        stdio: "inherit"
    });
    console.log(`# [${test}] Finished at ${new Date().toString()} (result=${result.status})`);
    if (result.status !== 0) {
        console.error(`# ${result.error}`);
        ++failed;
    }
    console.log("");
});

if (failed > 0) {
    process.exitCode = 1;
}

Use argv0 instead of node (for Travis CI)


/*jshint node:true*/
module.exports = {
  description: ''

  // locals: function(options) {
  //   // Return custom template variables here.
  //   return {
  //     foo: options.entity.options.foo
  //   };
  // }

  beforeInstall: function(options) {
    return this.addPackageToProject('ember-simple-auth', '~1.0');
  }
};

/*jshint node:true*/
module.exports = {
  description: '',

  // locals: function(options) {
  //   // Return custom template variables here.
  //   return {
  //     foo: options.entity.options.foo
  //   };
  // }

  beforeInstall: function(options) {
    return this.addPackageToProject('ember-simple-auth', '~1.0');
  }
};

Fix syntax error in addon blueprint


import React, { Component } from 'react';
import { connect } from 'react-redux';
import store from '../store.js';
import { restart } from '../actions/name-actions';
import { selectGender } from '../actions/gender-actions';
import MdBack from 'react-icons/lib/md/keyboard-arrow-left';
import { withRouter } from 'react-router';

class Restart extends Component {

    constructor(props) {
        super(props);
    }

    restart() {
        store.dispatch(restart());
        store.dispatch(selectGender(null));
        localStorage.clear();
        this.props.history.push('/');
    }

    render() {
        return (

                <MdBack></MdBack> Byrja av nýggjum

        );
    }
}

const RestartWithRouter = withRouter(Restart);
const mapStateToProps = function (store) {
    return {
        names: store.names,
        gender: store.gender
    };
}
export default connect(mapStateToProps)(RestartWithRouter);

import React, { Component } from 'react';
import { connect } from 'react-redux';
import store from '../store.js';
import { restart } from '../actions/name-actions';
import { selectGender } from '../actions/gender-actions';
import MdBack from 'react-icons/lib/md/keyboard-arrow-left';
import { withRouter } from 'react-router';

class Restart extends Component {

    constructor(props) {
        super(props);
    }

    restart() {
        store.dispatch(restart());
        store.dispatch(selectGender(null));
        localStorage.clear();
        this.props.history.push('/');
    }

    shouldDisplayRestart() {
        return window.location.pathname == "/" ? "hide" : "";
    }

    render() {
        return (

                <MdBack></MdBack> Byrja av nýggjum

        );
    }
}

const RestartWithRouter = withRouter(Restart);
const mapStateToProps = function (store) {
    return {
        names: store.names,
        gender: store.gender
    };
}
export default connect(mapStateToProps)(RestartWithRouter);

Hide restart on start page


define(function () {
  // Dutch
  return {
    errorLoading: function () {
      return 'De resultaten konden niet worden geladen.';
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = 'Gelieve ' + overChars + ' karakters te verwijderen';

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'Gelieve ' + remainingChars +
        ' of meer karakters in te voeren';

      return message;
    },
    loadingMore: function () {
      return 'Meer resultaten laden…';
    },
    maximumSelected: function (args) {
      var message = 'Er kunnen maar ' + args.maximum + ' item';

      if (args.maximum != 1) {
        message += 's';
      }
      message += ' worden geselecteerd';

      return message;
    },
    noResults: function () {
      return 'Geen resultaten gevonden…';
    },
    searching: function () {
      return 'Zoeken…';
    }
  };
});

define(function () {
  // Dutch
  return {
    errorLoading: function () {
      return 'De resultaten konden niet worden geladen.';
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = 'Gelieve ' + overChars + ' karakters te verwijderen';

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'Gelieve ' + remainingChars +
        ' of meer karakters in te voeren';

      return message;
    },
    loadingMore: function () {
      return 'Meer resultaten laden…';
    },
    maximumSelected: function (args) {
      var verb = args.maximum == 1 ? 'kan' : 'kunnen';
      var message = 'Er ' + verb + ' maar ' + args.maximum + ' item';

      if (args.maximum != 1) {
        message += 's';
      }
      message += ' worden geselecteerd';

      return message;
    },
    noResults: function () {
      return 'Geen resultaten gevonden…';
    },
    searching: function () {
      return 'Zoeken…';
    }
  };
});

Fix improper grammar in Dutch i18n file


var _ = require('underscore');

// Load .env for development environments
require('dotenv').load();

exports.initLocals = function(req, res, next) {

  var locals = res.locals;

  locals.user = req.user;
  locals.buy = {
    ticket: req.query.ticket,
    discount: req.query.discount,
  };
  locals.twoco_seller_id = process.env.TWOCO_SELLER_ID;
  locals.twoco_public_key = process.env.TWOCO_PUBLIC_KEY;
  locals.gold = req.query.g == '' ? 'gold' : '';

  next();

};

exports.flashMessages = function(req, res, next) {

  var flashMessages = {
    info: req.flash('info'),
    success: req.flash('success'),
    warning: req.flash('warning'),
    error: req.flash('error')
  };

  res.locals.messages = _.any(flashMessages, function(msgs) { return msgs.length; }) ? flashMessages : false;

  next();

};

exports.requireUser = function(req, res, next) {

  if (!req.user) {
    req.flash('error', 'Please sign in to access this page.');
    res.redirect('/keystone/signin');
  } else {
    next();
  }

};

var _ = require('underscore');

// Load .env for development environments
require('dotenv').load();

exports.initLocals = function(req, res, next) {

  var locals = res.locals;

  locals.user = req.user;
  locals.buy = {
    ticket: req.query.ticket,
    discount: req.query.discount,
  };
  locals.twoco_seller_id = process.env.TWOCO_SELLER_ID;
  locals.twoco_public_key = process.env.TWOCO_PUBLIC_KEY;
  console.log(Math.random());
  locals.gold = req.query.g == '' ? (Math.random() > 0.5 ? 'gold' : '') : '';

  next();

};

exports.flashMessages = function(req, res, next) {

  var flashMessages = {
    info: req.flash('info'),
    success: req.flash('success'),
    warning: req.flash('warning'),
    error: req.flash('error')
  };

  res.locals.messages = _.any(flashMessages, function(msgs) { return msgs.length; }) ? flashMessages : false;

  next();

};

exports.requireUser = function(req, res, next) {

  if (!req.user) {
    req.flash('error', 'Please sign in to access this page.');
    res.redirect('/keystone/signin');
  } else {
    next();
  }

};

Add random gold or blue