'use strict';

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

const TeamModel = new Schema({
  project: {
    type: Schema.Types.ObjectId,
    required: false,
    ref: 'Project'
  },
  submission: {
    type: Schema.Types.ObjectId,
    required: false,
    ref: 'Submission'
  },
  owner: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'User'
  },
  manager: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }],
  frontend: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }],
  backend: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }]
});

module.exports = mongoose.model('Team', TeamModel, 'teams');

'use strict';

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

const TeamModel = new Schema({
  project: {
    type: Schema.Types.ObjectId,
    required: false,
    ref: 'Project',
    dafault: null
  },
  submission: {
    type: Schema.Types.ObjectId,
    required: false,
    ref: 'Submission',
    dafault: null
  },
  owner: {
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'User'
  },
  manager: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }],
  frontend: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }],
  backend: [{
    role: Number,
    user: {
      type: Schema.Types.ObjectId,
      required: true,
      ref: 'User'
    }
  }],
  meta: {
    created: {type: Date, default: Date.now()},
    disband: Date,
    members: [{
      id: Schema.Types.ObjectId,
      date: {
        joined: {type: Date, default: Date.now()},
        leave: Date
      }
    }]
  }
});

module.exports = mongoose.model('Team', TeamModel, 'teams');

Add meta data to team model


"use strict";

/* global it describe */

const expect = require('expect.js');

//const pickIn  = require('../array/pickIn');
//const reindex = require('../array/reindex');
const sum     = require('../array/sum');

describe("Array functions", function() {

  it("should test sum", function() {
    expect(sum([1,2,3,4])).to.be(10);
  });

  it("should test sum of empty array", function() {
    expect(sum([])).to.be(0);
  });

});

"use strict";

/* global it describe */

const expect = require('expect.js');

const pickIn  = require('../array/pickIn');
const reindex = require('../array/reindex');
const sum     = require('../array/sum');

describe("Array functions", function() {

  it("should test sum", function() {
    expect(sum([1, 2, 3, 4])).to.be(10);
  });

  it("should test sum of empty array", function() {
    expect(sum([])).to.be(0);
  });

  it("should test pickIn", function() {
    expect(pickIn('b', ['a', 'b', 'c', 'd'])).to.be('b');
  });

  it("should test pickIn with wrong value", function() {
    expect(pickIn('melon', ['a', 'b', 'c', 'd'])).to.be('a');
  });

  it("should test reindex", function() {
    var people = [
      {name : 'Jean Lebon',   age : 12, town : 'Paris'},
      {name : 'John TheGood', age : 22, town : 'Dallas'},
      {name : 'Juan ElBueno', age : 35, town : 'Madrid'},
    ];

    var target = {
      'Jean Lebon'   : {name : 'Jean Lebon',   age : 12, town : 'Paris'},
      'John TheGood' : {name : 'John TheGood', age : 22, town : 'Dallas'},
      'Juan ElBueno' : {name : 'Juan ElBueno', age : 35, town : 'Madrid'}
    };

    expect(reindex(people, 'name')).to.eql(target);
  });

});

Add tests for Array/PickIn & Array/reindex


import CoreObject from './metal/core-object';

function wrapConsole(logCommand) {
  let logMethod;

  /* eslint-disable no-console */
  try {
    logMethod = Function.prototype.bind.call(console[logCommand], console);
  } catch (e) {
    logMethod = Function.prototype.bind.call(console.log, console);
  }
  /* eslint-enable no-console */

  return function () {
    const args = Array.prototype.slice.call(arguments);

    args.unshift('[JS-BUY-SDK]: ');
    logMethod.apply(console, args);
  };
}

const Logger = CoreObject.extend({
  /**
   * Wrapper around the console log so in the future we can have better dev output.
   * Also allows us to disable output in production.
   * @class Logger
   * @constructor
   */
  constructor() { },
  debug: wrapConsole('debug'),
  info: wrapConsole('info'),
  warn: wrapConsole('warn'),
  error: wrapConsole('error')
});

export { wrapConsole };
export default new Logger();

import CoreObject from './metal/core-object';

function wrapConsole(logCommand) {
  const logMethod = function () {
    /* eslint-disable no-console */
    if (console[logCommand]) {
      console[logCommand](...arguments);
    } else {
      console.log(...arguments);
    }
    /* eslint-enable no-console */
  };

  return function () {
    const args = [...arguments];

    args.unshift('[JS-BUY-SDK]: ');
    logMethod(...args);
  };
}

const Logger = CoreObject.extend({
  /**
   * Wrapper around the console log so in the future we can have better dev output.
   * Also allows us to disable output in production.
   * @class Logger
   * @constructor
   */
  constructor() { },
  debug: wrapConsole('debug'),
  info: wrapConsole('info'),
  warn: wrapConsole('warn'),
  error: wrapConsole('error')
});

export { wrapConsole };
export default new Logger();

Use if/else and direct function calls over try/catch + bind


import axios from 'axios';

export const FETCH_POSTS = 'fetch_posts';

const ROOT_URL ='https://reduxblog.herokuapp.com/api';
const API_KEY = '?key=unhommequidort';

export function fetchPosts() {
  const request = axios.get(`${ROOT_URL}/posts${API_KEY}`);

  return {
    type: FETCH_POSTS,
    payload: request
  };
}

import axios from 'axios';

export const FETCH_POSTS = 'fetch_posts';
export const CREATE_POST = 'create_post';

const ROOT_URL ='https://reduxblog.herokuapp.com/api';
const API_KEY = '?key=unhommequidort';

export function fetchPosts() {
  const request = axios.get(`${ROOT_URL}/posts${API_KEY}`);

  return {
    type: FETCH_POSTS,
    payload: request
  };
}

export function createPost(values) {
  const request = axios.post(`${ROOT_URL}/posts${API_KEY}`, values);

  return {
    type: CREATE_POST,
    payload: request
  };
}

Create createPost action creator function


Template["afSelect2_bootstrap3"].helpers({
  optionAtts: function afSelectOptionAtts() {
    var item = this
    var atts = {
      value: item.value
    };
    if (item.selected) {
      atts.selected = "";
    }
    return atts;
  },
  atts: function addFormControlAtts() {
    var atts = _.clone(this.atts);
    // Add bootstrap class
    atts = AutoForm.Utility.addClass(atts, "form-control");
    delete atts.select2Options;
    return atts;
  }
});

Template["afSelect2_bootstrap3"].rendered = function () {
  // instanciate select2
  var select2Options = this.data.atts.select2Options || {};
  if (!select2Options.width) {
    select2Options.width = "element";
  }
  this.$('select').select2(select2Options);
};

Template["afSelect2_bootstrap3"].destroyed = function () {
  this.$('select').select2('destroy');
};

Template["afSelect2_bootstrap3"].helpers({
  optionAtts: function afSelectOptionAtts() {
    var item = this
    var atts = {
      value: item.value
    };
    if (item.selected) {
      atts.selected = "";
    }
    return atts;
  },
  atts: function addFormControlAtts() {
    var atts = _.clone(this.atts);
    // Add bootstrap class
    atts = AutoForm.Utility.addClass(atts, "form-control");
    delete atts.select2Options;
    return atts;
  }
});

Template["afSelect2_bootstrap3"].rendered = function () {
  // instanciate select2
  this.$('select').select2(this.data.atts.select2Options || {});
};

Template["afSelect2_bootstrap3"].destroyed = function () {
  this.$('select').select2('destroy');
};

Revert "select2Options.width = "element" as default"


//
// script.js
//

'use strict';

chrome.runtime.onInstalled.addListener(() => {
    chrome.contextMenus.create({
        contexts: ['page', 'frame', 'selection', 'link', 'editable',  'image', 'video', 'audio'],
        id: 'background_img',
        title: chrome.i18n.getMessage('title')
    });
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
    chrome.tabs.sendMessage(tab.id, '', response => {
        if (response) {
            response.split(' ').map(image => {
                chrome.tabs.create({
                    index: tab.index + 1,
                    url: image
                });
            });
        } else if(confirm(chrome.i18n.getMessage('failure'))) {
            const url = encodeURIComponent(info.frameUrl || info.pageUrl);
            const xhr = new XMLHttpRequest();
            xhr.open('GET', 'https://script.google.com/macros/s/AKfycbwtacVYsZHc_n4qkVdfvjJE_3__rKwfeqTNNgZKPhH00VoKTAA/exec?url=' + url);
            xhr.send();
        }
    });
});

//
// script.js
//

'use strict';

chrome.runtime.onInstalled.addListener(() => {
    chrome.contextMenus.create({
        contexts: ['page', 'frame', 'selection', 'link', 'editable',  'image', 'video', 'audio'],
        id: 'background_img',
        title: chrome.i18n.getMessage('title')
    });
});

chrome.contextMenus.onClicked.addListener((info, tab) => {
    chrome.tabs.sendMessage(tab.id, '', response => {
        if (response) {
            response.split(' ').map(image => {
                chrome.tabs.create({
                    index: tab.index + 1,
                    url: image
                });
            });
        } else if(confirm(chrome.i18n.getMessage('failure'))) {
            chrome.tabs.create({
                index: tab.index + 1,
                url: 'https://chrome.google.com/webstore/detail/cegndknljaapfbnmfnagomhhgbajjibd/support'
            });
        }
    });
});

Change the way to report bugs


import React from "react";
import toJson from "enzyme-to-json";
import { shallow, mount, render } from "enzyme";

import Foo from "../Foo";

describe("A suite", function() {
  it("should render without throwing an error", function() {
    const info = "Bar";
    expect(
      shallow(<Foo loading info={info} />).contains(

{info}

      )
    ).toBe(true);
  });

  it('should be selectable by class "foo"', function() {
    expect(shallow(<Foo loading />).is(".foo")).toBe(true);
  });

  it("should mount in a full DOM", function() {
    expect(mount(<Foo loading />).find(".foo").length).toBe(1);
  });

  it("should render to static HTML", function() {
    const info = "Bar";
    expect(render(<Foo loading info={info} />).text()).toEqual(info);
  });

  it("snapshot check", () => {
    const wrapper = shallow(<Foo loading />);
    expect(toJson(wrapper)).toMatchSnapshot();
  });
});

import React from "react";
import toJson from "enzyme-to-json";
import { shallow, mount, render } from "enzyme";

import Foo from "../Foo";

describe("A suite", function() {
  it("should render without throwing an error", function() {
    const info = "Bar";
    expect(
      shallow(<Foo loading info={info} />).contains(

{info}

      )
    ).toBe(true);
  });

  it('should be selectable by class "foo"', function() {
    expect(shallow(<Foo loading />).is(".foo")).toBe(true);
  });

  it("should mount in a full DOM", function() {
    expect(mount(<Foo loading />).find(".foo").length).toBe(1);
  });

  it("should render to static HTML", function() {
    const info = "Bar";
    expect(render(<Foo loading info={info} />).text()).toEqual(info);
  });

  it("snapshot check", () => {
    const wrapper = shallow(<Foo loading />);
    expect(toJson(wrapper)).toMatchSnapshot();
  });

  it("Should update Foo props", () => {
    const info = "Foo";
    const wrapper = mount(<Foo loading info="Bar" />);
    expect(wrapper.setState({ info }).text()).toEqual(info);
  });
});

Add prop test to Foo


'use strict';

const { DEFAULT_COMPRESS } = require('./merger');

// Normalize `compress` name
const normalizeCompress = function ({
  compressResponse: { name: compressResponse } = DEFAULT_COMPRESS,
  compressRequest: { name: compressRequest } = DEFAULT_COMPRESS,
}) {
  const compress = `${compressResponse},${compressRequest}`;
  return compress;
};

// Using query variable ?compress=REQUEST_COMPRESSION[,RESPONSE_COMPRESSION]
const denormalizeCompress = function ({ compress }) {
  if (compress === undefined) { return {}; }

  const [compressResponse, compressRequest] = compress.split(',');
  return { compressResponse, compressRequest };
};

module.exports = {
  normalizeCompress,
  denormalizeCompress,
};

'use strict';

const { DEFAULT_COMPRESS } = require('./merger');

// Normalize `compress` name
const normalizeCompress = function ({ compressResponse, compressRequest }) {
  const compressResponseName = getName({ compress: compressResponse });
  const compressRequestName = getName({ compress: compressRequest });

  const compress = `${compressResponseName},${compressRequestName}`;
  return compress;
};

const getName = function ({ compress }) {
  if (typeof compress === 'string' || compress == null) {
    return DEFAULT_COMPRESS.name;
  }

  return compress.name;
};

// Using query variable ?compress=REQUEST_COMPRESSION[,RESPONSE_COMPRESSION]
const denormalizeCompress = function ({ compress }) {
  if (compress === undefined) { return {}; }

  const [compressResponse, compressRequest] = compress.split(',');
  return { compressResponse, compressRequest };
};

module.exports = {
  normalizeCompress,
  denormalizeCompress,
};

Fix error.data.compress being undefined when compress is a string


/**
 * a class that is used to store each test device so we can send data back to them
 */

'use strict';

function TestDevice(deviceSocket,name,platform,testType,bluetoothAddress) {
    this.socket = deviceSocket;
    this.deviceName = name;
    this.os = platform;
    this.type = testType;
    this.btAddress = bluetoothAddress;
}

TestDevice.prototype.getBluetoothAddress= function(){
    return this.btAddress;
};

TestDevice.prototype.getTestType = function(){
    return this.type;
};

TestDevice.prototype.getName = function(){
    return this.deviceName;
};

TestDevice.prototype.compareSocket = function (socket) {
    return (socket.id === this.socket.id);
};

TestDevice.prototype.getPlatform = function(){
    return this.os;
};

TestDevice.prototype.start_tests = function(data){
    this.socket.emit('start_tests', JSON.stringify({data:data}));
};

TestDevice.prototype.SendCommand = function(command,test,data,dev,btAddresList){
    var self = this;
    var filteredList = [];

    if(btAddresList && this.btAddress){
        btAddresList.forEach(function(item) {
             if(item.address != self.btAddress){
                filteredList.push(item);
            }
        });
    }

    this.socket.emit('command', JSON.stringify({command: command, testName: test, testData:data,devices:dev,addressList:filteredList}));
};

TestDevice.prototype.SendEndUnitTest = function(data){
    this.socket.emit('end_unit_test', JSON.stringify({data:data}));
};

TestDevice.prototype.SendStartUnitTest = function(data){
    this.socket.emit('start_unit_test', JSON.stringify({data:data}));
};

module.exports = TestDevice;

/**
 * a class that is used to store each test device so we can send data back to them
 */

'use strict';

function TestDevice(deviceSocket, name, platform, testType, tests, bluetoothAddress) {
    this.socket = deviceSocket;
    this.deviceName = name;
    this.platform = platform;
    this.type = testType;
    this.btAddress = bluetoothAddress;
    this.tests = tests;
}

TestDevice.prototype.SendCommand = function(command,test,data,dev,btAddresList){
  var self = this;
  var filteredList = [];

  if(btAddresList && this.btAddress) {
    btAddresList.forEach(function(item) {
    if(item.address != self.btAddress) {
      filteredList.push(item);
    }});
  }

  this.socket.emit('command', JSON.stringify({command: command, testName: test, testData:data,devices:dev,addressList:filteredList}));
};

module.exports = TestDevice;

Move most of device handling to the frameworks


module.exports = function(config) {
    var commonConfig = (require("./karma-common.conf"))(config);
    var customLaunchers = {
        sl_chrome: {
            base: "SauceLabs",
            browserName: "chrome",
            platform: "Windows 8.1"
        },
        //sl_firefox: {
        //    base: "SauceLabs",
        //    browserName: "firefox",
        //    platform: "Windows 8.1"
        //},
        sl_safari: {
            base: "SauceLabs",
            browserName: "safari",
            platform: "OS X 10.10"
        },
        sl_ie_11: {
            base: "SauceLabs",
            browserName: "internet explorer",
            platform: "Windows 8.1"
        }
    };

    var options = {
        reporters: ["verbose", "saucelabs"],
        sauceLabs: {
            testName: "Vivliostyle.js",
            recordScreenshots: false,
            startConnect: false, // Sauce Connect is started by Travis CI
            tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
        },
        captureTimeout: 120000,
        customLaunchers: customLaunchers,
        browsers: Object.keys(customLaunchers),
        singleRun: true
    };
    for (var key in commonConfig) {
        if (commonConfig.hasOwnProperty(key)) {
            options[key] = commonConfig[key];
        }
    }

    config.set(options);
};

module.exports = function(config) {
    var commonConfig = (require("./karma-common.conf"))(config);
    var customLaunchers = {
        sl_chrome: {
            base: "SauceLabs",
            browserName: "chrome",
            platform: "Windows 8.1"
        },
        //sl_firefox: {
        //    base: "SauceLabs",
        //    browserName: "firefox",
        //    platform: "Windows 8.1"
        //},
        sl_safari: {
            base: "SauceLabs",
            browserName: "safari",
            platform: "OS X 10.10"
        },
        sl_ie_11: {
            base: "SauceLabs",
            browserName: "internet explorer",
            platform: "Windows 8.1"
        }
    };

    var options = {
        reporters: ["verbose", "saucelabs"],
        sauceLabs: {
            build: process.env.TRAVIS_BUILD_NUMBER,
            testName: "Vivliostyle.js",
            recordScreenshots: false,
            startConnect: false, // Sauce Connect is started by Travis CI
            tunnelIdentifier: process.env.TRAVIS_JOB_NUMBER
        },
        captureTimeout: 120000,
        customLaunchers: customLaunchers,
        browsers: Object.keys(customLaunchers),
        singleRun: true
    };
    for (var key in commonConfig) {
        if (commonConfig.hasOwnProperty(key)) {
            options[key] = commonConfig[key];
        }
    }

    config.set(options);
};

Add Travis CI build number to Sauce Labs jobs


import Ember from 'ember';
import GetController from 'ember-cli-mirage/controllers/get';
import PostController from 'ember-cli-mirage/controllers/post';
import PutController from 'ember-cli-mirage/controllers/put';
import DeleteController from 'ember-cli-mirage/controllers/delete';

export default {

  getController: GetController.create(),
  postController: PostController.create(),
  putController: PutController.create(),
  deleteController: DeleteController.create(),

  handle: function(verb, handler, db, request, code) {
    var controller = verb + 'Controller';
    code = code ? code : this.getDefaultCode(verb);

    var type = typeof handler;
    var handlerType = Ember.isArray(handler) ? 'array' : type;

    var handlerMethod = handlerType + 'Handler';

    var handlerExists = this[controller][handlerMethod];
    if (!handlerExists) { console.error('Mirage: You passed a ' + handlerType + ' as a handler to the ' + controller + ' but no ' + handlerMethod + ' was implemented.'); return;}

    var data = this[controller][handlerMethod](handler, db, request, code);

    if (data) {
      return [code, {"Content-Type": "application/json"}, data];
    } else {
      return [code, {}, undefined];
    }
  },

  getDefaultCode: function(verb) {
    var code = 200;
    switch (verb) {
      case 'put':
        code = 204;
        break;
      case 'post':
        code = 201;
        break;
      case 'delete':
        code = 204;
        break;
      default:
        code = 200;
        break;
    }

    return code;
  }

};

import Ember from 'ember';
import GetController from 'ember-cli-mirage/controllers/get';
import PostController from 'ember-cli-mirage/controllers/post';
import PutController from 'ember-cli-mirage/controllers/put';
import DeleteController from 'ember-cli-mirage/controllers/delete';

var defaultCodes = {
  put: 204,
  post: 201,
  delete: 204
};

export default {

  getController: GetController.create(),
  postController: PostController.create(),
  putController: PutController.create(),
  deleteController: DeleteController.create(),

  handle: function(verb, handler, db, request, code) {
    var controller = verb + 'Controller';
    code = code ? code : (defaultCodes[verb] || 200);

    var type = typeof handler;
    var handlerType = Ember.isArray(handler) ? 'array' : type;

    var handlerMethod = handlerType + 'Handler';

    var handlerExists = this[controller][handlerMethod];
    if (!handlerExists) { console.error('Mirage: You passed a ' + handlerType + ' as a handler to the ' + controller + ' but no ' + handlerMethod + ' was implemented.'); return;}

    var data = this[controller][handlerMethod](handler, db, request, code);

    if (data) {
      return [code, {"Content-Type": "application/json"}, data];
    } else {
      return [code, {}, undefined];
    }
  }
};

Determine status code in constant linear time


var expect = require('referee/lib/expect');
var should = require('should');
var assert = require('assert');

function consumeMessage(messageData) {
  var sender = messageData.source;
  var specCode = messageData.data;

  // Reset mocha env
  document.getElementById('mocha').innerHTML = '';
  var mocha = new Mocha({reporter: 'html', ui: 'bdd'});
  mocha.suite.emit('pre-require', this, null, this);

  // Run the spec source code, this calls describe, it, etc. and "fills"
  // the test runner suites which are executed later in `mocha.run()`.
  eval(specCode);

  // Let mocha run and report the stats back to the actual sender.
  mocha.checkLeaks();
  var runner = mocha.run();
  function onRan() {
    var stats = runner.stats;
    sender.postMessage(stats, '*');
  }
  runner.on('end', onRan);
}

window.addEventListener('message', consumeMessage, false);

var expect = require('referee/lib/expect');
var should = require('should');
var assert = require('assert');

function consumeMessage(messageData) {
  var sender = messageData.source;
  var specCode = messageData.data;

  // Reset mocha env
  document.getElementById('mocha').innerHTML = '';
  var mocha = new Mocha({reporter: 'html', ui: 'bdd'});
  mocha.suite.emit('pre-require', this, null, this);

  // Run the spec source code, this calls describe, it, etc. and "fills"
  // the test runner suites which are executed later in `mocha.run()`.
  eval(specCode);

  // Let mocha run and report the stats back to the actual sender.
  mocha.checkLeaks();
  var runner = mocha.run(function() {}); // if there is no callback given mocha will fail and not work again :(
  function onRan() {
    var stats = runner.stats;
    sender.postMessage(stats, '*');
  }
  runner.on('end', onRan);
}

window.addEventListener('message', consumeMessage, false);

Make mocha run not only once, seems something has changed.


'use strict';

import gulp from 'gulp';
import size from 'gulp-size';
import vulcanize from 'gulp-vulcanize';

import {config, browserSync} from './_config.babel.js';

let sourceFiles = `${config.path.source.elements}/elements.html`;

gulp.task('vulcanize', () => {
  return gulp.src(sourceFiles)
    .pipe(vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe(gulp.dest(config.path.destination.elements))
    .pipe(size({title: 'vulcanize'}));
});

gulp.task('vulcanize:watch', ['browser-sync'], () => {
  let watcher = gulp.watch(sourceFiles, ['vulcanize']);

  watcher.on('change', (event) => {
    browserSync.reload();

    if (event.type === 'deleted') { // if a file is deleted, forget about it
      delete cache.caches.vulcanize[event.path];
      remember.forget('vulcanize', event.path);
    }
  });
});

'use strict';

import cache from 'gulp-cached';
import gulp from 'gulp';
import remember from 'gulp-remember';
import size from 'gulp-size';
import vulcanize from 'gulp-vulcanize';

import {config, browserSync} from './_config.babel.js';

let sourceFiles = `${config.path.source.elements}/elements.html`;
sourceFiles = sourceFiles.concat(config.files.source.elements);

gulp.task('vulcanize', () => {
  return gulp.src(`${config.path.source.elements}/elements.html`)
    .pipe(vulcanize({
      stripComments: true,
      inlineCss: true,
      inlineScripts: true
    }))
    .pipe(gulp.dest(config.path.destination.elements))
    .pipe(size({title: 'vulcanize'}));
});

gulp.task('vulcanize:watch', ['browser-sync'], () => {
  let watcher = gulp.watch(sourceFiles, ['vulcanize']);

  watcher.on('change', (event) => {
    browserSync.reload();

    if (event.type === 'deleted') { // if a file is deleted, forget about it
      delete cache.caches.vulcanize[event.path];
      remember.forget('vulcanize', event.path);
    }
  });
});

Watch element files in Vulcanize watch task


var _ = require('underscore');

var dirtyAdapter = require('waterline-dirty');

dirtyAdapter = _.extend(dirtyAdapter,{
	config: _.extend(dirtyAdapter.config, {
		inMemory: false
	})
});

exports = _.extend(exports,dirtyAdapter);

var _ = require('underscore');

var dirtyAdapter = require('waterline-dirty');

dirtyAdapter = _.extend(dirtyAdapter,{
	config: _.extend(dirtyAdapter.config, {
		inMemory: true
	})
});

exports = _.extend(exports,dirtyAdapter);

Set tests to run w/ memoryadapter by default just to prevent slowdowns (the on-disk implementation is excruciatingly slow-- this is only for development/testing)


Ensembl.Panel.ZMenu.prototype.populateAjax = function(url, expand) {
	var timeout = this.timeout;
	url     = url || this.href;
    if(url && url.match('www.wormbase.org')) {
      this.populateNoAjax();
    } else if (url && url.match('/ZMenu/')) {
      $.extend($.ajax({
        url:      url,
        data:     this.coords.clickStart ? { click_chr: this.coords.clickChr || Ensembl.location.name, click_start: this.coords.clickStart, click_end: this.coords.clickEnd } : {},
        dataType: this.crossOrigin ? 'jsonp' : 'json',
        context:  this,
        success:  $.proxy(this.buildMenuAjax,  this),
        error:    $.proxy(this.populateNoAjax, this)
      }), { timeout: timeout, expand: expand });
    } else {
      this.populateNoAjax();
    }
};

Ensembl.Panel.ZMenu.prototype.populateAjax = function(url, expand) {
	var timeout = this.timeout;
	url     = url || this.href;

    this.crossOrigin = url && url.match(/^http/) ? url.split('/').slice(0,3).join('/') : false;

    if (url && window.location.pathname.match(/\/Gene\/Variation_Gene/) && !url.match(/\/ZMenu\//)) {
      url = url.replace(/\/(\w+\/\w+)\?/, '/ZMenu/$1?');
    }

    if(url && url.match('www.wormbase.org')) {
      this.populateNoAjax();
    } else if (url && url.match('/ZMenu/')) {
      $.extend($.ajax({
        url:      url,
        data:     this.coords.clickStart ? { click_chr: this.coords.clickChr || Ensembl.location.name, click_start: this.coords.clickStart, click_end: this.coords.clickEnd } : {},
        dataType: this.crossOrigin ? 'jsonp' : 'json',
        context:  this,
        success:  $.proxy(this.buildMenuAjax,  this),
        error:    $.proxy(this.populateNoAjax, this)
      }), { timeout: timeout, expand: expand });
    } else {
      this.populateNoAjax();
    }

};

Fix cross linking to EG problem in compara trees


import Ember from 'ember';
import DepartureFetcher from 'bus-detective/utils/departure-fetcher';
let { run, computed } = Ember;
const MAXIMUM_DURATION_IN_HOURS = 12;

export default Ember.Component.extend({
  stop: null,
  departures: null,
  fetcher: null,
  canLoadMore: computed.lt('fetcher.duration', MAXIMUM_DURATION_IN_HOURS),
  hasFetched: computed.alias('fetcher.hasFetched'),

  init() {
    this._super(...arguments);
    this.set('departures', Ember.ArrayProxy.create({ content: [] }));
    this.set('fetcher', DepartureFetcher.create({ stopId: this.get('stop.id') }));
    this.get('fetcher').on('didFetch', run.bind(this, 'updateDepartures'))
  },

  didInsertElement() {
    this.get('fetcher').startFetching();
  },

  willDestroyElement() {
    this.get('fetcher').stopFetching();
  },

  updateDepartures(departures) {
    this.get('departures').clear().pushObjects(departures);
    this.sendAction('onLoad', this.get('departures'))
  },

  actions: {
    loadMore() {
      this.get('fetcher').increaseDuration();
    }
  }
});

import Ember from 'ember';
import DepartureFetcher from 'bus-detective/utils/departure-fetcher';
let { run, computed } = Ember;
const MAXIMUM_DURATION_IN_HOURS = 12;

export default Ember.Component.extend({
  stop: null,
  departures: null,
  fetcher: null,
  canLoadMore: computed.lt('fetcher.duration', MAXIMUM_DURATION_IN_HOURS),
  hasFetched: computed.alias('fetcher.hasFetched'),

  init() {
    this._super(...arguments);
    this.set('fetcher', DepartureFetcher.create({ stopId: this.get('stop.id') }));
    this.get('fetcher').on('didFetch', run.bind(this, 'updateDepartures'))
  },

  didInsertElement() {
    this.get('fetcher').startFetching();
  },

  willDestroyElement() {
    this.get('fetcher').stopFetching();
  },

  updateDepartures(departures) {
    this.set('departures', departures);
    this.sendAction('onLoad', departures);
  },

  actions: {
    loadMore() {
      this.get('fetcher').increaseDuration();
    }
  }
});

Make departures a plain array


import fetch from 'isomorphic-fetch'

export const REQUEST_ENTITIES = 'REQUEST_ENTITIES'
export const RECEIVE_ENTITIES = 'RECEIVE_ENTITIES'

function requestEntities() {
  return {
    type: REQUEST_ENTITIES
  }
}

function receiveEntities(json) {
  return {
    type: RECEIVE_ENTITIES,
    data: json.data,
    receivedAt: Date.now()
  }
}

export function fetchEntities(model, searchTerm, delay = 0) {
  return (dispatch, getState) => {
    const request = () => {
      dispatch(requestEntities())
      fetch(`http://localhost:8080/nice2/rest/entities/${model}?_search=${searchTerm}`)
        .then(response => response.json())
        .then(json => dispatch(receiveEntities(json)))
    }
    if (delay > 0) {
      setTimeout(() => {
        if (getState().list.searchTerm === searchTerm) {
          request()
        }
      }, delay)
    } else {
      request()
    }
  }
}

const ACTION_HANDLERS = {
  [RECEIVE_ENTITIES]: (state, { data }) => {
    return [].concat(data);
  }
}

const initialState = []

export default function listReducer(state = initialState, action: Action) {
  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}

import fetch from 'isomorphic-fetch'

export const REQUEST_ENTITIES = 'REQUEST_ENTITIES'
export const RECEIVE_ENTITIES = 'RECEIVE_ENTITIES'

function requestEntities() {
  return {
    type: REQUEST_ENTITIES
  }
}

function receiveEntities(json) {
  return {
    type: RECEIVE_ENTITIES,
    data: json.data,
    receivedAt: Date.now()
  }
}

export function fetchEntities(model, searchTerm, delay = 0) {
  return (dispatch, getState) => {
    const request = () => {
      dispatch(requestEntities())
      fetch(`http://localhost:8080/nice2/rest/entities/${model}?_search=${searchTerm}`, {
        credentials: 'include'
      })
        .then(response => response.json())
        .then(json => dispatch(receiveEntities(json)))
    }
    if (delay > 0) {
      setTimeout(() => {
        if (getState().list.searchTerm === searchTerm) {
          request()
        }
      }, delay)
    } else {
      request()
    }
  }
}

const ACTION_HANDLERS = {
  [RECEIVE_ENTITIES]: (state, { data }) => {
    return [].concat(data);
  }
}

const initialState = []

export default function listReducer(state = initialState, action: Action) {
  const handler = ACTION_HANDLERS[action.type]
  return handler ? handler(state, action) : state
}

Include credentials when entity search request is sent


"use strict";

const EventEmitter = require('events');
const evts = new EventEmitter();

const env = require('../../env');
let dht;
if (env.inDevMode) {
	dht = require('gpio-peripherals-test').dht;
} else {
	dht = require('rpi-dht-sensor');
}

let lastValues = {
	temperature: NaN,
	humidity: NaN
};

let dhtInstance = new dht.DHT22(env.dhtSensor.pin);

function update () {
	let data = dhtInstance.read();
	lastValues.temperature = data.temperature;
	lastValues.humidity = data.humidity;

	evts.emit('change', lastValues);
}
setInterval(() => {
	update();
}, 60 * 1000);
update();

exports.get = function () {
	return lastValues;
};

exports.evts = evts;

"use strict";

const EventEmitter = require('events');
const evts = new EventEmitter();

const env = require('../../env');
let dht;
if (env.inDevMode) {
	dht = require('gpio-peripherals-test').dht;
} else {
	dht = require('rpi-dht-sensor');
}

let lastValues = {
	temperature: NaN,
	humidity: NaN
};

let dhtInstance = new dht.DHT22(env.dhtSensor.pin);

function update () {
	let data = dhtInstance.read();
	lastValues.temperature = data.temperature.toFixed(1);
	lastValues.humidity = parseInt(data.humidity, 10);

	evts.emit('change', lastValues);
}
setInterval(() => {
	update();
}, 60 * 1000);
update();

exports.get = function () {
	return lastValues;
};

exports.evts = evts;

Normalize the data read from the sensors.


// import node packages
import React from 'react';

function Flashcard(props) {
  return (

      Question: {this.props.question}

      Answer: {this.props.answer}

  );
}

export default Flashcard;

// import node packages
import React from 'react';

function Flashcard(props) {
  return (

      Question: {props.question}

      Answer: {props.answer}

  );
}

export default Flashcard;

Fix props usage for function vs class


import {
    createUser,
    updateUser
} from '../../../api/db/user'
import userMutations from './mutations'
import authMutations from '../auth/mutations'
import { getCurrentUserObject } from './getters'
import { ValueChangedObserver } from '../../../services/observers'
import * as paths from '../../../api/db/paths'

const observers = {
    user: new ValueChangedObserver()
}

const subscriptions = {
    [userMutations.CHANGED]: ({state}) => {
        const user = getCurrentUserObject(state)
        createUser(user.uid, user).then(() => {
            updateUser(user.uid, user)
        }).catch(error => {
            console.log(`Error while creating/updating user on ${userMutations.CHANGED}: ${error.message}`)
        })
    },
    [authMutations.USER_CHANGED]: ({dispatch}, mutation) => {
        const user = mutation.payload[0]
        if (user) {
            const path = paths.user(user.uid)
            observers.user.start(path, data => {
                if (data) {
                    dispatch(userMutations.CHANGED, data)
                } else {
                    createUser(user.uid, user)
                }
            })
        } else {
            observers.user.stop()
        }
    }
}

export default function createPlugin(store) {
    store.subscribe((mutation, state) => {
        const type = mutation.type
        if (type in subscriptions) {
            subscriptions[type](store, mutation)
        }
    })
}

import {
    createUser,
    updateUser
} from '../../../api/db/user'
import userMutations from './mutations'
import authMutations from '../auth/mutations'
import { getCurrentUserObject } from './getters'
import { ValueChangedObserver } from '../../../services/observers'
import * as paths from '../../../api/db/paths'

const observers = {
    user: new ValueChangedObserver()
}

const subscriptions = {
    [userMutations.CHANGED]: ({state}) => {
        const user = getCurrentUserObject(state)
        createUser(user.uid, user).then(() => {
            updateUser(user.uid, user)
        }).catch(error => {
            console.log(`Error while creating/updating user on ${userMutations.CHANGED}: ${error.message}`)
        })
    },
    [authMutations.USER_CHANGED]: ({dispatch}, mutation) => {
        const user = mutation.payload[0]
        if (user) {
            const path = paths.user(user.uid)
            observers.user.start(path, data => {
                if (data) {
                    dispatch(userMutations.CHANGED, data)
                } else {
                    createUser(user.uid, user)
                }
            })
        } else {
            observers.user.stop()
            dispatch(userMutations.RESET)
        }
    }
}

export default function createPlugin(store) {
    store.subscribe((mutation, state) => {
        const type = mutation.type
        if (type in subscriptions) {
            subscriptions[type](store, mutation)
        }
    })
}

Reset user data when signed out.


'use strict';

var mainApp = angular.module('mainApp', ['ngResource']);
var indexApp = angular.module('indexApp', ['ngResource']);

'use strict';

var indexApp = angular.module('indexApp', ['ngResource', 'ngRoute']).
    config(function ($routeProvider) {
        $routeProvider.when('/protocol/:protocolId', {
            templateUrl: '/templates/protocol.jsp',
            controller: 'ProtocolController'
        });
        $routeProvider.when('/protocols', {
            templateUrl: '/templates/protocolList.jsp',
            controller: 'IndexController'
        });

    });

Add routing for list and single protocol views


exports.default = {
  app: {
    orphanRecordsAdopter: process.env.ORPHAN_OWNER,
    latKilometersPerDegree: 111.195,
    lonKilometersPerDegree: 82.445,
    location: {
      // max distance to consider a point belonging to a city
      maxDistance: 50000,
      // max records per task
      maxRecords: 10
    }
  }
}

exports.test = {
  app: {
    orphanRecordsAdopter: 'adopt@smartbirds.com'
  }
}

exports.default = {
  app: {
    orphanRecordsAdopter: process.env.ORPHAN_OWNER,
    location: {
      // max distance to consider a point belonging to a city
      maxDistance: process.env.AUTO_LOCATION_MAX_DISTANCE || 100000,
      // max records per task
      maxRecords: process.env.AUTO_LOCATION_MAX_RECORDS || 10
    }
  }
}

exports.test = {
  app: {
    orphanRecordsAdopter: 'adopt@smartbirds.com'
  }
}

Allow env override of autoLocation parameters and increase max distance to 100km


/**
 *
 *  form-serializer#loadForm
 *
 *  This is the server operation that reads the content of
 *  the HTML file that must be loaded and sends it back to the
 *  client.
 *
 */
exports.loadForm = function (link) {
    link.send(200, {
        html: "Foo"
    });
};

// dependencies
var fs = require("fs");

/**
 *
 *  form-serializer#loadForm
 *
 *  This is the server operation that reads the content of
 *  the HTML file that must be loaded and sends it back to the
 *  client.
 *
 */
exports.loadForm = function (link) {

    // get data, params
    var data = Object(link.data)
      , params = link.params
      ;

    // missing form id
    if (!data.formId) {
        return link.send(400, "Missing formId");
    }

    // html path
    var htmlPath = params[data.formId];

    // invalid form id
    if (!htmlPath) {
        return link.send(400, "Wrong form id.");
    }

    // set the absolute path to the html file
    htmlPath = M.app.getPath() + htmlPath;

    // read the file
    fs.readFile(htmlPath, function (err, buffer) {

        // handle error
        if (err) {
            return link.send(400, err);
        }

        // send success response
        link.send(200, {
            html: buffer.toString()
        });
    });
};

Read the file content and send it to client


import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import UnitList from '../components/UnitList';
import * as UnitActions from '../actions';
import { UnitStates } from '../constants/ActionTypes';

export default class App extends Component {
  render() {
    const { visibleUnits, actions } = this.props;
    return (
      <div>
        <UnitList
          units={this.props.visibleUnits}
          actions={actions}
          />
      </div>
    );
  }
}

App.propTypes = {
  visibleUnits: PropTypes.arrayOf(
    PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.number.isRequired,
        state: PropTypes.string.isRequired
      }).isRequired
    ).isRequired
  ).isRequired
}

function select(state) {
  return {
    visibleUnits: state.unitList.units,
  }
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(UnitActions, dispatch)
  }
}

export default connect(select, mapDispatchToProps)(App);

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import UnitList from '../components/UnitList';
import * as UnitActions from '../actions';
import { UnitStates } from '../constants/ActionTypes';

export default class App extends Component {
  render() {
    const { visibleUnits, actions } = this.props;
    return (
      <div>
        <UnitList
          units={visibleUnits}
          actions={actions}
          />
      </div>
    );
  }
}

App.propTypes = {
  visibleUnits: PropTypes.arrayOf(
    PropTypes.arrayOf(
      PropTypes.shape({
        id: PropTypes.number.isRequired,
        state: PropTypes.string.isRequired
      }).isRequired
    ).isRequired
  ).isRequired
}

function select(state) {
  return {
    visibleUnits: state.unitList.units,
  }
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(UnitActions, dispatch)
  }
}

export default connect(select, mapDispatchToProps)(App);

Replace this.props.visibleUnits with const visibleUnits.


// apikey module validates the apikey argument used in the call. It
// caches the list of users to make lookups faster.
var http = require('http');
module.exports = function(apikeyCache) {
    'use strict';
    // validateAPIKey Looks up the apikey. If none is specified, or a
    // bad key is passed then abort the calls and send back an 401.
    return function* validateAPIKey(next) {
        let apikey = this.query.apikey || this.throw(401, 'Invalid apikey');
        let user = yield apikeyCache.find(apikey);
        if (! user) {
            this.throw(401, 'Invalid apikey');
        }
        this.mcapp = {
            user: user
        };
        yield next;
    };
};

// apikey module validates the apikey argument used in the call. It
// caches the list of users to make lookups faster.
var http = require('http');
var httpStatus = require('http-status');
module.exports = function(apikeyCache) {
    'use strict';
    // validateAPIKey Looks up the apikey. If none is specified, or a
    // bad key is passed then abort the calls and send back an 401.
    return function* validateAPIKey(next) {
        let UNAUTHORIZED = httpStatus.UNAUTHORIZED;
        let apikey = this.query.apikey || this.throw(UNAUTHORIZED, 'Invalid apikey');
        let user = yield apikeyCache.find(apikey);
        if (! user) {
            this.throw(UNAUTHORIZED, 'Invalid apikey');
        }
        this.mcapp = {
            user: user
        };
        yield next;
    };
};

Remove hard coding the 401 and instead give it a readable name.


import test from 'ava';
import mergeImages from '../';

test('mergeImages is a function', t => {
	t.is(typeof mergeImages, 'function');
});

import test from 'ava';
import Canvas from 'canvas';
import mergeImages from '../';

test('mergeImages is a function', t => {
	t.is(typeof mergeImages, 'function');
});

test('mergeImages returns a Promise', t => {
	t.true(mergeImages([], {Canvas}) instanceof Promise);
});

Check mergeImages returns a Promise


App.flashQueueController = Ember.ArrayController.extend({
  // 15s
  destroyTimeout: 15 * 1e3,
  flash: function(type, message){
    var flash = App.FlashMessage.create({
      type: type,
      message: message,
      scheduledToDestroy: true
    });

    this.pushObject(flash);
    if (flash.get('scheduledToDestroy')) {
      this.scheduleDestroy(flash);
    }
  },
  scheduleDestroy: function(flash){
    var self = this;
    setTimeout(function(){
      self.removeObject(flash);
    }, this.destroyTimeout);
  }
}).create();

App.flashQueueController = Ember.ArrayController.extend({
  destroyTimeout: 15 * 1e3, // 15s
  flash: function(type, message){
    var flash = App.FlashMessage.create({
      type: type,
      message: message,
      scheduledToDestroy: true
    });
    this.pushObject(flash);

    if (flash.get('scheduledToDestroy')) {
      Ember.run.later(this, function(){
        this.removeObject(flash);
      }, this.destroyTimeout)
      this.scheduleDestroy(flash);
    }
  }
}).create();

Use Ember.run.later instead of setTimeout


/*---------------------------------------------------------------------------/
 *
 *  textselect.js
 *
 *  Author: Declan de Wet <declandewet@me.com>
 *
 *  This script will trigger an event `textselect` when text is highlighted
 *  on the page. It's only dependency is jQuery.
 *
 *--------------------------------------------------------------------------*/

// enclose code in top-level function scope to prevent creation of globals
(function() {

  /**
   * @function getSelectedTextContent
   * @return {String} Content within a highlighted selection, if any present.
   *
   * Immediately-invoked self-modifying function.
   * Executes instantly and uses feature detection to determine the text
   * selection method the browser supports, then modifies itself to return
   * the value returned by that method any time it is manually called.
   */
  var getSelectedTextContent = (function() {
    if (window.getSelection) {
      return function() {
        return window.getSelection.toString();
      };
    } else if (document.getSelection) {
      return function() {
        return document.getSelection();
      };
    } else if (document.selection) {
      return function() {
        return document.selection.createRange().text;
      };
    }
  }).apply(this);

}).call(this);

/*---------------------------------------------------------------------------/
 *
 *  textselect.js
 *
 *  Author: Declan de Wet <declandewet@me.com>
 *
 *  This script will trigger an event `textselect` when text is highlighted
 *  on the page. It's only dependency is jQuery.
 *
 *--------------------------------------------------------------------------*/

// enclose code in top-level function scope to prevent creation of globals
(function() {

  /**
   * @function getSelectedTextContent
   * @return {String} Content within a highlighted selection, if any present.
   *
   * Immediately-invoked self-modifying function.
   * Executes instantly and uses feature detection to determine the text
   * selection method the browser supports, then modifies itself to return
   * the value returned by that method any time it is manually called.
   */
  var getSelectedTextContent = (function() {
    if (window.getSelection) {
      return function() {
        return window.getSelection.toString();
      };
    } else if (document.getSelection) {
      return function() {
        return document.getSelection();
      };
    } else if (document.selection) {
      return function() {
        return document.selection.createRange().text;
      };
    }
  }).apply(this);

  /**
   * @function getSelectionInformation
   * @return {Object} Contains coordinate and size properties of selection.
   *
   * Immediately-invoked self-modifying function.
   * Executes instantly and uses feature detection to determine the
   * method to use to get location and size information about the current
   * selection, if any - then modifes itself to return the output of
   * that method.
   *
   * N.B. - Temporary implementation until more research is done on
   * supporting more browsers.
   */
  var getSelectionInformation = (function(){
    if (window.getSelection) {
      return function() {
        return window.getSelection().getRangeAt(0).getBoundingClientRect();
      };
    } else {
      return function() {
        var message = "Selection coordinates are not supported in this browser";
        throw new Error(message);
      };
    }
  }).apply(this);

}).call(this);

Add function to fetch size and location of selection


import { moduleForModel, test } from 'ember-qunit';

moduleForModel('skill', 'Unit | Model | skill', {
  // Specify the other units that are required for this test.
  needs: []
});

test('it exists', function(assert) {
  let model = this.subject();
  // let store = this.store();
  assert.ok(!!model);
});

test('it should have all of its attributes', function(assert) {
   let model = this.subject();
   let actualAttributes = Object.keys(model.toJSON());
   let expectedAttributes = [
     "description",
     "matched",
     "title",
   ];

   assert.hasAttributes(actualAttributes, expectedAttributes);
});

Update skill model unit tests


//general ContactManager app code (defining regions, the start handler, etc.):
var HospitalCheckup = new Marionette.Application();

HospitalCheckup.navigate = function(route, options){
  options || (options = {});
  Backbone.history.navigate(route, options);
};

HospitalCheckup.getCurrentRoute = function(){
  return Backbone.history.fragment
};

HospitalCheckup.on("before:start", function(){
  var RegionContainer = Marionette.LayoutView.extend({
    el: "#app-container",

    regions: {
      header: "#header-region",
      main: "#main-region"
    }
  });

  HospitalCheckup.regions = new RegionContainer();
});

HospitalCheckup.on("start", function(){
  window.localStorage.clear(); //we want fresh data which we will persist during this session
  if(Backbone.history){
    Backbone.history.start();

    /*if(this.getCurrentRoute() === ""){
      HospitalCheckup.trigger("infections:list");
    }*/
  }
});

//general ContactManager app code (defining regions, the start handler, etc.):
var HospitalCheckup = new Marionette.Application();

HospitalCheckup.navigate = function(route, options){
  options || (options = {});
  Backbone.history.navigate(route, options);
};

HospitalCheckup.getCurrentRoute = function(){
  return Backbone.history.fragment
};

HospitalCheckup.on("before:start", function(){
  var RegionContainer = Marionette.LayoutView.extend({
    el: "#app-container",

    regions: {
      header: "#header-region",
      main: "#main-region"
    }
  });

  HospitalCheckup.regions = new RegionContainer();
});

HospitalCheckup.on("start", function(){
  window.localStorage.clear(); //we want fresh data which we will persist during this session
  if(Backbone.history){
    Backbone.history.start();

    /*if(this.getCurrentRoute() === ""){
      HospitalCheckup.trigger("infections:list");
    }*/
  }

  $(document).on('click', 'a[href^="#benchmark"]', function (e) { //TODO this doesn't belong here
    e.preventDefault();
    element = document.getElementById("benchmark")
    element.scrollIntoView(true); //parameter = "alignToTop"
  });
});

Add named anchor to benchmark text explainer


import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import auth from './userSignUp';
import login from './login';
import book from './book';
import favorites from './favorites';
import profile from './profile';
import borrowRequests from './borrowrequests';
import { books, mostUpvotedBooks } from './books';

const rootReducer = combineReducers({
  form: formReducer,
  auth,
  login,
  books,
  book,
  mostUpvotedBooks,
  favorites,
  borrowRequests,
  profile,
  routing: routerReducer,
});

export default rootReducer;

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import auth from './userSignUp';
import login from './login';
import book from './book';
import favorites from './favorites';
import profile from './profile';
import borrowRequests from './borrowrequests';
import returnRequests from './returnrequests';
import { books, mostUpvotedBooks } from './books';

const rootReducer = combineReducers({
  form: formReducer,
  auth,
  login,
  books,
  book,
  mostUpvotedBooks,
  favorites,
  borrowRequests,
  returnRequests,
  profile,
  routing: routerReducer,
});

export default rootReducer;

Add return requests reducer in root reducer


(function() {

	var modules = {}, cache = {};

	if (typeof __fhtagn__ == "undefined") {
		window.__fhtagn__ = {};
		__fhtagn__ = window.__fhtagn__;
	}

	__fhtagn__.exp = function(paths, mod) {
		for (var i in paths) modules[paths[i]] = mod;
	};

	__fhtagn__.req = function(path,relative) {

		var mod_relative;

		if (relative=="__index__") relative = null;

		mod_relative = relative+'/node_modules/'+path;

		if (relative) path = relative+'/'+path;

		if (cache[path]) return cache[path];

		function grab(p) {
			cache[p] = modules[p](function(mod) {
				return __fhtagn__.req(mod, p);
			});
			return cache[p];
		}

		for (var mod in modules) {
			if (mod==path+'.js'
				|| mod==path.replace(/^\.\//, '')+'.js'
				|| mod==path
				|| mod.replace(/node_modules\//g, '')==path
				|| mod_relative==mod
			) return grab(mod);
		}

		console.error("Cannot find module", path);

	}

	__fhtagn__ = __fhtagn__;

})();

(function(ns) {

	var modules = {}, cache = {}, canon = {};

	if (typeof ns.__fhtagn__ == "undefined") {
		ns.__fhtagn__ = {};
	}

	ns.__fhtagn__.exp = function(paths,cpath,mod) {
		for (var i in paths) {
			modules[paths[i]] = mod;
			canon[paths[i]]   = cpath;
		}
	};

	ns.__fhtagn__.req = function(path,rel) {

		if (cache[path]) return cache[path];

		path = path.replace("/client", '');
		path = path.replace(/^\.\//, '');
		if (rel) rel = rel.replace("/client", '');

		function grab(p) {
			if (!cache[p]) {
				cache[p] = modules[p](function(mod) {
					return ns.__fhtagn__.req(mod, canon[p]);
				});
			} return cache[p];
		}

		for (var mod in modules) {
			if (mod==path+'.js'
				|| mod==path+'.js'
				|| rel+'/'+path+'.js'==mod
				|| mod==path
				|| mod.replace(/node_modules\//g, '')==path
				|| rel+'/'+path==mod
			) return grab(mod);
		}

		throw "Cannot find module "+path+" (called from "+(rel||"root")+")";

	};

})(this);

Revert "Added module path to require lookup tree."


import React from 'react';
import './HomePage.css';
import {connect} from 'react-redux';
import logo from './svg/manny_wave.svg';
import {getQuicklinks} from './selectors';
import Card from './components/Card';

const HomePage = ({quickLinks}) => (

Mannequin Pattern Library

        {quickLinks.length > 0 &&

Quick Links

                {quickLinks.map(pattern => (
                    <Card title={pattern.name} subtitle={pattern.tags['category']} to={`pattern/${pattern.id}`} />
                ))}

        }

)

const mapStateToProps = (state) => {
  return {
    quickLinks: getQuicklinks(state)
  }
}

export default connect(mapStateToProps)(HomePage)

import React from 'react';
import './HomePage.css';
import {connect} from 'react-redux';
import logo from './svg/manny_wave.svg';
import {getQuicklinks} from './selectors';
import Card from './components/Card';

const HomePage = ({quickLinks}) => (

Mannequin Pattern Library

        {quickLinks.length > 0 &&

Quick Links

                {quickLinks.map(pattern => (
                    <Card key={pattern.id} title={pattern.name} subtitle={pattern.tags['category']} to={`pattern/${pattern.id}`} />
                ))}

        }

)

const mapStateToProps = (state) => {
  return {
    quickLinks: getQuicklinks(state)
  }
}

export default connect(mapStateToProps)(HomePage)

Add missing key in Homepage quicklinks


function createCommitResult(attrs = {}) {
  return {
    commit: {
      status: {
        contexts: [ {state: 'PASSED'} ]
      }
    }
  };
}

export function createPullRequestResult(attrs = {}) {
  const o = {
    number: 0,
    repositoryID: 'repository0',
    states: null,
    headRefName: 'master',
    ...attrs,
  };

  const commit = {
    id: 'commit0',
  };

  if (o.states === null) {
    commit.status = null;
  } else {
    commit.status = {
      contexts: o.states.map((state, id) => ({state, id: `state${id}`})),
    };
  }

  return {
    id: `pullrequest${o.number}`,
    number: o.number,
    title: `Pull Request ${o.number}`,
    url: `https://github.com/owner/repo/pulls/${o.number}`,
    author: {
      __typename: 'User',
      login: 'me',
      avatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=4',
      id: 'user0'
    },
    createdAt: '2018-06-12T14:50:08Z',
    headRefName: o.headRefName,

    repository: {
      id: o.repositoryID,
    },

    commits: {nodes: [{commit, id: 'node0'}]},
  }
}

function createCommitResult(attrs = {}) {
  return {
    commit: {
      status: {
        contexts: [ {state: 'PASSED'} ]
      }
    }
  };
}

export function createPullRequestResult(attrs = {}) {
  const o = {
    number: 0,
    repositoryID: 'repository0',
    states: null,
    headRefName: 'master',
    ...attrs,
  };

  const commit = {
    id: 'commit0',
  };

  if (o.states === null) {
    commit.status = null;
  } else {
    commit.status = {
      contexts: o.states.map((state, id) => ({state, id: `state${id}`})),
    };
  }

  return {
    __typename: 'PullRequest',
    id: `pullrequest${o.number}`,
    number: o.number,
    title: `Pull Request ${o.number}`,
    url: `https://github.com/owner/repo/pulls/${o.number}`,
    author: {
      __typename: 'User',
      login: 'me',
      avatarUrl: 'https://avatars3.githubusercontent.com/u/000?v=4',
      id: 'user0'
    },
    createdAt: '2018-06-12T14:50:08Z',
    headRefName: o.headRefName,

    repository: {
      id: o.repositoryID,
    },

    commits: {nodes: [{commit, id: 'node0'}]},
  }
}

Include a __typename in the pull request result fixture


define([
    'js-whatever/js/base-page',
    'text!about-page/templates/about-page.html',
    'datatables.net-bs'
], function(BasePage, template) {

    return BasePage.extend({
        template: _.template(template),

        initialize: function(options) {
            this.options = options;

            this.options.icon = this.options.icon || 'fa fa-cog';
        },

        render: function() {
            this.$el.html(this.template(this.options));

            this.$('table.table').dataTable({
                autoWidth: false,
                language: {
                    search: ''
                }
            });

            this.$('.dataTables_filter input')
                .prop('placeholder', this.options.strings.search);
        },

        getTemplateParameters: $.noop
    });
});

define([
    'js-whatever/js/base-page',
    'text!about-page/templates/about-page.html',
    'datatables.net-bs'
], function(BasePage, template) {

    return BasePage.extend({
        template: _.template(template),

        initialize: function(options) {
            this.options = options;

            this.options.icon = this.options.icon || 'fa fa-cog';
        },

        render: function() {
            this.$el.html(this.template(this.options));

            this.$('table.table').dataTable({
                autoWidth: false,
                language: {
                    search: ''
                }
            });

            this.$('.dataTables_filter input')
                .prop('placeholder', this.options.strings.search);
        }

    });
});

Remove unused function. [rev: matthew.gordon]


const RESPONSE_PUBLIC  = 'in_channel';
const RESPONSE_PRIVATE = 'ephemeral';

// Required names for slack
/*eslint-disable camelcase */
const baseResponse = {
	parse:         'full',
	text:          '',
	unfurl_media:  true
};
/*eslint-enable camelcase */

function getImageAttachment(image) {
	// Required names for slack
	/*eslint-disable camelcase */
	return [{
		fallback: 'Image failed to load',
		image_url: encodeURI(image)
	}];
	/*eslint-enable camelcase */
}

module.exports = function create(data) {
	let responseObject = Object.assign({}, baseResponse);

	responseObject.text = data.text;

	if(data.image) {
		responseObject.attachments = getImageAttachment(data.image);
	}

	// Required names for slack
	/*eslint-disable camelcase */
	responseObject.response_type = (!data.isPrivate ? RESPONSE_PUBLIC : RESPONSE_PRIVATE);
	/*eslint-enable camelcase */

	return responseObject;
};

const RESPONSE_PUBLIC  = 'in_channel';
const RESPONSE_PRIVATE = 'ephemeral';

const baseResponse = {
	// Required names for slack
	/*eslint-disable camelcase */
	parse:         'full',
	text:          '',
	unfurl_media:  true
	/*eslint-enable camelcase */
};

function getImageAttachment(image) {
	// Required names for slack
	/*eslint-disable camelcase */
	return [{
		fallback: 'Image failed to load',
		image_url: encodeURI(image)
	}];
	/*eslint-enable camelcase */
}

module.exports = function create(data) {
	let responseObject = Object.assign({}, baseResponse);

	responseObject.text = data.text;

	if(data.image) {
		responseObject.attachments = getImageAttachment(data.image);
	}

	// Required names for slack
	/*eslint-disable camelcase */
	responseObject.response_type = (!data.isPrivate ? RESPONSE_PUBLIC : RESPONSE_PRIVATE);
	/*eslint-enable camelcase */

	return responseObject;
};

Tidy up the eslint excludes


import React from 'react';

export const tidyString = string => (
	{string.split(/\n/).map(s =>
{s}
)}
);

import React from 'react';

export const tidyString = string => (
	string && {string.split(/\n/).map(s =>
{s}
)}
);

Fix issue with undefined strings


Template.videobackground.onRendered(function () {
  renderVideo(this.firstNode, _.extend(
    {
      loop: 1,
      type: 'vimeo',
      volume: 0,
      aspectRatio: 1.8,
      autoSize: 1
    },
    this.data)
  )
})

Template.videobackground.onRendered(function () {
  renderVideo(this.firstNode, _.extend(
    {
      loop: 1,
      type: 'vimeo',
      volume: 0,
      aspectRatio: 1.785,
      autoSize: 1
    },
    this.data)
  )
})

Set a smarter default for the aspectRatio setting


/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/* global module, test, ok */

define(function (require) {
    "use strict";

    var adapter = require("adapter");

    module("version");

    test("adapter.version is set to a string", function () {
        ok(typeof adapter.version === "string", "type of adapter version is a string");
    });
});

/*
 * Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/* global module, test, ok */

define(function (require) {
    "use strict";

    var adapter = require("adapter");

    module("version");

    test("adapter.version is defined", function () {
        var version = adapter.version;

        ok(typeof version.major === "number", "type of adapter major version is a number");
        ok(typeof version.minor === "number", "type of adapter minor version is a number");
        ok(typeof version.patch === "number", "type of adapter patch version is a number");
    });
});

Fix the version test spec


import { injectGlobal } from 'styled-components';

injectGlobal`
  html {
    box-sizing: border-box;
  }

  *,
  *::before,
  *::after {
    box-sizing: inherit;
  }

  body {
    font-family:
      'Avenir Next',
      -apple-system,
      BlinkMacSystemFont,
      'Segoe UI',
      'Roboto',
      'Helvetica Neue',
      Helvetica,
      sans-serif;
    line-height: 1.5;
    margin: 0;
  }

  img {
    height: auto;
    max-width: 100%;
  }

  svg {
    max-height: 100%;
  }
`;

import { injectGlobal } from 'styled-components';

injectGlobal`
  html {
    box-sizing: border-box;
  }

  *,
  *::before,
  *::after {
    box-sizing: inherit;
  }

  body {
    background-color: #F7F7F7;
    font-family:
      'Avenir Next',
      -apple-system,
      BlinkMacSystemFont,
      'Segoe UI',
      'Roboto',
      'Helvetica Neue',
      Helvetica,
      sans-serif;
    line-height: 1.5;
    margin: 0;
  }

  img {
    height: auto;
    max-width: 100%;
  }

  svg {
    max-height: 100%;
  }
`;

Set the background color of the body element


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

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.resource('posts', function() {});
  this.route('about');
  this.route('team');
  this.resource('friendship-status', function() {});
});

export default Router;

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

var Router = Ember.Router.extend({
  location: config.locationType
});

Router.map(function() {
  this.route('posts', function() {});
  this.route('about');
  this.route('team');
  this.route('friendship-status', function() {});
});

export default Router;

Fix deprecation in tests regarding resources


var express = require('express');
var routes = function(Book) {
  var bookRouter = express.Router();
  bookRouter.route('/')
    .post(function(req, res) {
      var book = new Book(req.body);

      book.save();
      res.status(201).send(book);
    })
    .get(function(req, res) {
      var query = {};
      if (req.query.genre) {
        query.genre = req.query.genre;
      }
      Book.find(query, function(err, books) {
        if(err)
          res.status(500).send(err);
        else
          res.json(books);
    });
  });

  bookRouter.route(' /:bookId')
    .get(function(req, res) {
      Book.findById(req.params.bookId, function(err, book) {
        if(err)
          res.status(500).send(err);
        else
          res.json(book);
    });
  });

  return bookRouter;
};

module.exports = routes;

var express = require('express');
var routes = function(Book) {
  var bookRouter = express.Router();
  bookRouter.route('/')
    .post(function(req, res) {
      var book = new Book(req.body);

      book.save();
      res.status(201).send(book);
    })
    .get(function(req, res) {
      var query = {};
      if (req.query.genre) {
        query.genre = req.query.genre;
      }
      Book.find(query, function(err, books) {
        if(err)
          res.status(500).send(err);
        else
          res.json(books);
      });
    });

  bookRouter.route('/:bookId')
    .get(function(req, res) {
      Book.findById(req.params.bookId, function(err, book) {
        if(err)
          res.status(500).send(err);
        else
          res.json(book);
      });
    })
    .put(function(req, res) {
      Book.findById(req.params.bookId, function(err, book) {
        if(err) {
          res.status(500).send(err);
        } else {
          book.title = req.body.title;
          book.author = req.body.author;
          book.genre = req.body.genre;
          book.read = req.body.read;
          book.save();
          res.json(book);
        }
      });
    })
    .patch(function(req, res) {
      Book.findById(req.params.bookId, function(err, book) {
        if(err) {
          res.status(500).send(err);
        } else {
          if(req.body.title != undefined)
            book.title = req.body.title;
          if(req.body.author != undefined)
            book.author = req.body.author;
          if(req.body.genre != undefined)
            book.genre = req.body.genre;
          if(req.body.read != undefined)
            book.read = req.body.read;
          book.save();
          res.json(book);
        }
      });
    });

  return bookRouter;
};

module.exports = routes;

Create PUT and PATCH requests to handle updating a book


import { makeArray } from '@ember/array';
import { computed } from '@ember/object';
import filterByQuery from 'ember-cli-filter-by-query/util/filter';

var computedFilterByQuery = function(dependentKey, propertyKeys, queryKey, options) {
  propertyKeys = makeArray(propertyKeys);

  return computed( queryKey, '' + dependentKey + '.@each.{' + propertyKeys.join(',') + '}', function() {

    var array = this.get(dependentKey);
    var query = this.get(queryKey) || '';

    return filterByQuery(array, propertyKeys, query, options);

  });
};

export default computedFilterByQuery;

import { makeArray } from '@ember/array';
import { computed, get } from '@ember/object';
import filterByQuery from 'ember-cli-filter-by-query/util/filter';

var computedFilterByQuery = function(dependentKey, propertyKeys, queryKey, options) {
  propertyKeys = makeArray(propertyKeys);

  return computed( queryKey, '' + dependentKey + '.@each.{' + propertyKeys.join(',') + '}', function() {

    var array = get(this, dependentKey);
    var query = get(this, queryKey) || '';

    return filterByQuery(array, propertyKeys, query, options);

  });
};

export default computedFilterByQuery;

Make get compatible with @glimmer/component


var express = require('express');
var router = express.Router();
var JsonDB = require('node-json-db');

// Tags listing
router.get('/', function (req, res, next) {
  var db = new JsonDB('db', false, false);
  var tags = db.getData('/tags');
  res.json(tags);
});

module.exports = router;

var express = require('express');
var router = express.Router();
var JsonDB = require('node-json-db');
var _ = require('lodash');

// Tags listing
router.get('/', function (req, res, next) {
  var db = new JsonDB('db', false, false);

  // Get the total number of tags used in recipes
  var recipetags = db.getData('/recipetags');
  var totals = _(recipetags)
    .countBy(function(tag) {
      return _(tag).values().first();
    })
    .value();

  // Map tags to their totals
  var tags = db.getData('/tags');
  res.json(_(tags).map(function(tag) {
    tag.total = totals[tag.id] || 0;
    return tag;
  }).value());
});

module.exports = router;

Add section 2.3 code to get tag totals


'use strict';

const path = require('path');

// Allows for environment variables to be set using a .env file
require('dotenv').config({
  silent: true,
  path: path.join(__dirname, '.env')
});
// If no NODE_ENV was specified, we are in development
if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = 'development';
}

console.log('Loading ' + process.env.NODE_ENV + ' configuration');
module.exports = require('./config/env/' + process.env.NODE_ENV);

Add a newline for readability


'use strict'

var express = require('express')
var mysql = require('mysql')
var crypto = require('crypto')
var config = require('./config.json')

var connection = mysql.createConnection(config.mysql)

connection.connect(function(err) {
  if (err) throw new Error(err)
})

var app = express()
app.use(express.static(__dirname + '/public/', { index: 'index.htm' }))

app.get('/get', function(req, res) {
  var md5 = req.query.md5
  connection.query('SELECT * FROM md5 WHERE ?', { md5: md5 }, function(err, result) {
    if (err) throw new Error(err)
    res.send(result[0] && result[0].str)
  })
})

app.get('/set', function(req, res) {
  var str = req.query.str || ''
  var md5 = crypto.createHash('md5').update(str).digest('hex')
  connection.query('INSERT IGNORE INTO md5 set ?', { str: str, md5: md5 }, function(err, result) {
    if (err) throw new Error(err)
    res.send(md5)
  })
})

app.listen(config.port)
console.log('now listening to port', config.port)

'use strict'

var express = require('express')
var mysql = require('mysql')
var crypto = require('crypto')
var config = require('./config.json')

var connection = mysql.createConnection(config.mysql)

var app = express()
app.use(express.static(__dirname + '/public/', { index: 'index.htm' }))

app.get('/get', function(req, res) {
  var md5 = req.query.md5
  connection.query('SELECT * FROM md5 WHERE ?', { md5: md5 }, function(err, result) {
    if (err) throw new Error(err)
    res.send(result[0] && result[0].str)
  })
})

app.get('/set', function(req, res) {
  var str = req.query.str || ''
  var md5 = crypto.createHash('md5').update(str).digest('hex')
  connection.query('INSERT IGNORE INTO md5 set ?', { str: str, md5: md5 }, function(err, result) {
    if (err) throw new Error(err)
    res.send(md5)
  })
})

app.listen(config.port)
console.log('now listening to port', config.port)

Use lazy connection for mysql


import columnAccessor from './columnAccessor';

describe('Util:columnAccessor', () => {
    it('should access the value of a column', () => {
        const accessor = columnAccessor({ column: 'foo' });
        const d = { foo: 5 };
        expect(accessor(d)).toEqual(5);
    });
    it('should apply a number formatter', () => {
        const accessor = columnAccessor({ column: 'foo', format: '.0s' });
        const d = { foo: 10000 };
        expect(accessor(d)).toEqual('10k');
    });
});

import columnAccessor from './columnAccessor';

describe('Util:columnAccessor', () => {
    it('should access the value of a column', () => {
        const accessor = columnAccessor({ column: 'foo' });
        const d = { foo: 5 };
        expect(accessor(d)).toEqual(5);
    });
    it('should apply a number formatter', () => {
        const accessor = columnAccessor({ column: 'foo', format: '.0s' });
        const d = { foo: 10000 };
        expect(accessor(d)).toEqual('10k');
    });
    it('should apply a date formatter', () => {
        const accessor = columnAccessor({ column: 'foo', timeFormat: '%x' });
        const d = { foo: 1479465567343 };
        expect(accessor(d)).toEqual('11/18/2016');
    });
});

Add test for date formatter


(function() {
    'use strict';

    angular
        .module('app', ['ngMaterial', 'ngMessages'])
        .config(['$mdThemingProvider', '$mdIconProvider', '$httpProvider', function($mdThemingProvider, $mdIconProvider, $httpProvider) {
            $mdThemingProvider.theme('default')
                .primaryPalette('green')
                .accentPalette('grey')
                .warnPalette('red',  {'default': '700'});
            $httpProvider.defaults.transformRequest = function(data) {
                if (data === undefined) {
                    return data;
                }
                return $.param(data);
            };
            $httpProvider.defaults.headers.post['Content-Type'] =
                'application/x-www-form-urlencoded; charset=UTF-8';
            $httpProvider.defaults.headers.common['X-Requested-With'] =
                'XMLHttpRequest';
        }]);
})();

(function() {
    'use strict';

    angular
        .module('app', ['ngMaterial', 'ngMessages'])
        .config(['$mdThemingProvider', '$mdIconProvider', '$httpProvider', function($mdThemingProvider, $mdIconProvider, $httpProvider) {
            $mdThemingProvider.theme('default')
                .primaryPalette('green')
                .accentPalette('grey')
                .warnPalette('red',  {'default': '700'});
            $httpProvider.defaults.transformRequest = function(data) {
                if (data === undefined) {
                    return data;
                }
                return $.param(data);
            };
            $httpProvider.defaults.headers.post['Content-Type'] =
                'application/x-www-form-urlencoded; charset=UTF-8';
            $httpProvider.defaults.headers.common['X-Requested-With'] =
                'XMLHttpRequest';
            $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token';
            $httpProvider.defaults.xsrfCookieName = 'csrfToken';
        }]);
})();

Set csrf header in AngularJS’ $http requests


import React from 'react';
import PropTypes from 'prop-types';
import Link from 'gatsby-link';
import Helmet from 'react-helmet';
import Container from '../components/Container';
import Header from '../components/Header';
import Footer from '../components/Footer';
import './index.css';

const propTypes = {
  children: PropTypes.func
};

const TemplateWrapper = ({ children }) =>
  <div>
    <Helmet
      title="Colson Donohue"
      meta={[
        { name: 'description', content: 'Sample' },
        { name: 'keywords', content: 'sample, something' }
      ]}
    />
    <Header path={window.location.pathname} />
    <Container>
      {children()}
    </Container>
    <Footer />
  </div>;

TemplateWrapper.propTypes = propTypes;

export default TemplateWrapper;

import React from 'react';
import PropTypes from 'prop-types';
import Link from 'gatsby-link';
import Helmet from 'react-helmet';
import Container from '../components/Container';
import Header from '../components/Header';
import Footer from '../components/Footer';
import './index.css';

const propTypes = {
  children: PropTypes.func
};

const path = typeof window != 'undefined' ? window.location.pathname : '';

const TemplateWrapper = ({ children }) =>
  <div>
    <Helmet
      title="Colson Donohue"
      meta={[
        { name: 'description', content: 'Sample' },
        { name: 'keywords', content: 'sample, something' }
      ]}
    />
    <Header path={path} />
    <Container>
      {children()}
    </Container>
    <Footer />
  </div>;

TemplateWrapper.propTypes = propTypes;

export default TemplateWrapper;

Fix window is not defined error


/* globals module */

module.exports = {
    afterInstall: function() {
        var self = this;

        return this.addBowerPackageToProject( 'bootstrap-datepicker' )
            .then( function() {
                return self.addBowerPackageToProject( 'momentjs' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'fontawesome' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'highcharts' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'moment' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'moment-timezone' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'select2' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'typeahead.js' );
            });
    },

    normalizeEntityName: function() {}
};

/* globals module */

module.exports = {
    afterInstall: function() {
        var self = this;

        return this.addBowerPackageToProject( 'bootstrap-datepicker' )
            .then( function() {
                return self.addBowerPackageToProject( 'momentjs' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'fontawesome' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'highcharts' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'moment' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'moment-timezone' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'select2' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'typeahead.js' );
            })
            .then( function() {
                return self.addBowerPackageToProject( 'git@gitlab.softlayer.local:interface/sl-bootstrap#0.6.1' );
            });
    },

    normalizeEntityName: function() {}
};

Add sl-bootstrap to blueprint bower includes


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

function WebService(currentUser) {
	this._currentUser = currentUser;
	this._dependencies = {};
}

WebService.prototype.run = function (name, allowedTypeAccount, params) {
	var self = this;
	var permissionsInit = new PermissionConstructor(allowedTypeAccount, this._currentUser);
	var webServices = require('../ServiceDirectories/Web/Public');

	if (permissionsInit.check()) {
		webServices[name].call(undefined, self._dependencies, params);
	} else {
		webServices['accessDenied'].call(undefined, self._dependencies, params);
	}
};

WebService.prototype.addDependency = function (name, value) {
	this._dependencies[name] = value;
};

module.exports.WebService = WebService;

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

function WebService(currentUser) {
	this._currentUser = currentUser;
	this._dependencies = {};
	this.runRef = undefined;
}

WebService.prototype.runWrapper = function () {
	var self = this;

	return function (name, allowedTypeAccount, params) {
		return function (req, res) {
			params.req = req;
			params.res = res;
			self.runRef(name, allowedTypeAccount, params);
		};
	};
};

WebService.prototype.run = function (name, allowedTypeAccount, params) {
	var self = this;
	var permissionsInit = new PermissionConstructor(allowedTypeAccount, this._currentUser);
	var webServices = require('../ServiceDirectories/Web/Public');

	if (permissionsInit.check()) {
		webServices[name].call(undefined, self._dependencies, params);
	} else {
		webServices['accessDenied'].call(undefined, self._dependencies, params);
	}
};

WebService.prototype.addDependency = function (name, value) {
	this._dependencies[name] = value;
};

module.exports.WebService = WebService;

Add wrapper for service run function.


'use strict';

const tickerGenerator = require('./functions/ticker');
const fetch = require('node-fetch');
const AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies
const _ = require('lodash');

const s3 = new AWS.S3();

module.exports.ticker = (event, context, callback) => {
  tickerGenerator()
    .then(files => {
      return Promise.all(_.map(files, (contents, filename) => {
        return s3.putObject({
          Bucket: process.env.BUCKET,
          Key: filename,
          Body: contents,
          ContentType: 'application/json',
          ACL: 'public-read',
          CacheControl: 'public, max-age=30',
        }).promise()
      }))
    })
    .then(v => callback(null, v), callback);
};

'use strict';

const tickerGenerator = require('./functions/ticker');
const fetch = require('node-fetch');
const AWS = require('aws-sdk'); // eslint-disable-line import/no-extraneous-dependencies
const _ = require('lodash');

const s3 = new AWS.S3();

module.exports.ticker = (event, context, callback) => {
  tickerGenerator()
    .then(files => {
      return Promise.all(_.map(files, (contents, filename) => {
        return s3.putObject({
          Bucket: process.env.BUCKET,
          Key: filename,
          Body: contents,
          ContentType: 'application/json',
          ACL: 'public-read',
          CacheControl: 'public, max-age=5',
        }).promise()
      }))
    })
    .then(v => callback(null, v), callback);
};

Reduce cache time to reduce cors problems


#!/usr/bin/env node

var Iterator = require('kld-array-iterators').Iterator,
    CrossProductIterator = require('kld-array-iterators').CrossProductIterator,
    RandomIterator = require('kld-array-iterators').RandomIterator;

// create an order deck of cards
var deck = [];

new CrossProductIterator(
    new Iterator('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'),
    new Iterator('♠', '♣', '♥', '♦')
).forEach(function(card) {
    deck.push(card.join(""));
});

// shuffle the deck and print it
new RandomIterator(deck).forEach(function(card) {
    console.log(card);
});

#!/usr/bin/env node

var Iterator = require('kld-array-iterators').Iterator,
    CrossProductIterator = require('kld-array-iterators').CrossProductIterator,
    RandomIterator = require('kld-array-iterators').RandomIterator;

// create an order deck of cards
var deck = [];

new CrossProductIterator(
    new Iterator('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'),
    new Iterator('♠', '♣', '♥', '♦')
).forEach(function(card) {
    deck.push(card.join(""));
});

// shuffle the deck and print it
console.log(
    new RandomIterator(deck).takeAll().join("\n")
);

Use takeAll in place of forEach, because we can


#!/usr/bin/env node

const currentNodeVersion = process.versions.node;
const semver = currentNodeVersion.split('.');
const major = semver[0];

console.error('[neo-mfs] You are running Node ' + currentNodeVersion + '.');

if (major < 6) {
    console.error('[neo-mfs] Please update your version of Node to 6 or higher.');
    process.exit(1);
}

const task = process.argv.length > 1 ? process.argv[2] : undefined;
console.log('[neo-mfs] Starting task: ' + task);

const gtasks = require('./index');
gtasks.series(task, function (done) {
    console.log('[neo-mfs] Finished task: ' + task);
    done();
})();

#!/usr/bin/env node

const currentNodeVersion = process.versions.node;
const semver = currentNodeVersion.split('.');
const major = semver[0];

console.error('[neo-mfs] You are running Node ' + currentNodeVersion + '.');

if (major < 6) {
    console.error('[neo-mfs] Please update your version of Node to 6 or higher.');
    process.exit(1);
}

const task = process.argv.length > 1 ? process.argv[2] : undefined;
console.info('[neo-mfs] Starting task: ' + task);

const gtasks = require('./index');
gtasks.series(task, function (done) {
    console.info('[neo-mfs] Finished task: ' + task);
    done();
})();

Switch to LF-ending, change console.log to make it commitable


var _currentRetryTime = 0
var currentRetryTimeDep = new Deps.Dependency

currentRetryTime = function () {
  currentRetryTimeDep.depend()

  return _currentRetryTime
}

Meteor.setInterval(function () {
  var retryTime = Math.round((Meteor.status().retryTime - (new Date()).getTime()) / 1000)

  if (isFinite(retryTime) && retryTime !== _currentRetryTime) {
    _currentRetryTime = retryTime
    currentRetryTimeDep.changed()
  }
}, 500)

var _currentRetryTime = 0
var currentRetryTimeDep = new Tracker.Dependency

currentRetryTime = function () {
  currentRetryTimeDep.depend()

  return _currentRetryTime
}

Meteor.setInterval(function () {
  var retryTime = Math.round((Meteor.status().retryTime - (new Date()).getTime()) / 1000)

  if (isFinite(retryTime) && retryTime !== _currentRetryTime) {
    _currentRetryTime = retryTime
    currentRetryTimeDep.changed()
  }
}, 500)

Use the new Tracker API


export default {
  today: 'วันนี้',
  now: 'ตอนนี้',
  backToToday: 'กลับไปยังวันนี้',
  ok: 'ตกลง',
  clear: 'ลบล้าง',
  month: 'เดือน',
  year: 'ปี',
  timeSelect: 'เลือกเวลา',
  dateSelect: 'เลือกวัน',
  monthSelect: 'เลือกเดือน',
  yearSelect: 'เลือกปี',
  decadeSelect: 'เลือกทศวรรษ',
  yearFormat: 'YYYY',
  dateFormat: 'D/M/YYYY',
  dayFormat: 'D',
  dateTimeFormat: 'D/M/YYYY HH:mm:ss',
  monthFormat: 'MMMM',
  monthBeforeYear: false,
  previousMonth: 'เดือนก่อนหน้า (PageUp)',
  nextMonth: 'เดือนถัดไป (PageDown)',
  previousYear: 'ปีก่อนหน้า (Control + left)',
  nextYear: 'ปีถัดไป (Control + right)',
  previousDecade: 'ทศวรรษก่อนหน้า',
  nextDecade: 'ทศวรรษถัดไป',
  previousCentury: 'ศตวรรษก่อนหน้า',
  nextCentury: 'ศตวรรษถัดไป',
};

export default {
  today: 'วันนี้',
  now: 'ตอนนี้',
  backToToday: 'กลับไปยังวันนี้',
  ok: 'ตกลง',
  clear: 'ลบล้าง',
  month: 'เดือน',
  year: 'ปี',
  timeSelect: 'เลือกเวลา',
  dateSelect: 'เลือกวัน',
  monthSelect: 'เลือกเดือน',
  yearSelect: 'เลือกปี',
  decadeSelect: 'เลือกทศวรรษ',
  yearFormat: 'YYYY',
  dateFormat: 'D/M/YYYY',
  dayFormat: 'D',
  dateTimeFormat: 'D/M/YYYY HH:mm:ss',
  monthFormat: 'MMMM',
  monthBeforeYear: true,
  previousMonth: 'เดือนก่อนหน้า (PageUp)',
  nextMonth: 'เดือนถัดไป (PageDown)',
  previousYear: 'ปีก่อนหน้า (Control + left)',
  nextYear: 'ปีถัดไป (Control + right)',
  previousDecade: 'ทศวรรษก่อนหน้า',
  nextDecade: 'ทศวรรษถัดไป',
  previousCentury: 'ศตวรรษก่อนหน้า',
  nextCentury: 'ศตวรรษถัดไป',
};

Update wrong value of monthBeforeYear


var jsonfile = require('jsonfile');

// Read in the file to be patched
var file = process.argv[2]; // e.g. '../src/MyProject/project.json'
if (!file)
    console.log("No filename provided");
console.log("File: " + file);

// Read in the build version (this is provided by the CI server)
var version = process.argv[3]; // e.g. '1.0.0-master-10'
var tag = process.argv[4]; // e.g. '', or '1.0.0-rc1'

if (!version)
    console.log("No version provided");

var lastDash = version.lastIndexOf("-");
var buildNumber = version.substring(lastDash + 1, version.length);
var num = "00000000" + parseInt(buildNumber);
buildNumber = num.substr(num.length-5);

if (tag) {
    // Turn version into tag + '-' + buildnumber
    version = tag + '-' + buildNumber;
} else {
    version = version.substring(0, lastDash) + '-' + buildNumber;
}

jsonfile.readFile(file, function (err, project) {

    console.log("Version: " + version);

    // Patch the project.version
    project.version = version;
    jsonfile.writeFile(file, project, {spaces: 2}, function(err) {
        if (err)
            console.error(err);
    });
})

var jsonfile = require('jsonfile');

// Read in the file to be patched
var file = process.argv[2]; // e.g. '../src/MyProject/project.json'
if (!file)
    console.log("No filename provided");
console.log("File: " + file);

// Read in the build version (this is provided by the CI server)
var version = process.argv[3]; // e.g. '1.0.0-master-10'
var tag = process.argv[4]; // e.g. '', or '1.0.0-rc1'

if (!version)
    console.log("No version provided");

var lastDash = version.lastIndexOf("-");
var buildNumber = version.substring(lastDash + 1, version.length);
var num = "00000000" + parseInt(buildNumber);
buildNumber = num.substr(num.length-5);

if (tag) {
    // Turn version into tag
    version = tag;
} else {
    version = version.substring(0, lastDash) + '-' + buildNumber;
}

jsonfile.readFile(file, function (err, project) {

    console.log("Version: " + version);

    // Patch the project.version
    project.version = version;
    jsonfile.writeFile(file, project, {spaces: 2}, function(err) {
        if (err)
            console.error(err);
    });
})

Remove buildnumber from version when tag


var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name:'Dribbble',
    version:'0.1',
    prepareImgLinks:function (callback) {
        var res = [];
        $('img[src*="_teaser."]').each(function () {
            var img = $(this),
                aZoom = img.parents('a.zoom'),
                aOver = img.parents('.dribbble-img').find('a.dribbble-over'),
                link = aOver.length ? aOver : aZoom;
            if (link.length) {
                link.data().hoverZoomSrc = [img.attr('src').replace('_teaser', '')];
                res.push(link);
            }
        });
        callback($(res));
    }
});

var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name:'Dribbble',
    version:'0.2',
    prepareImgLinks:function (callback) {
        var res = [];

        $('img[src*="_teaser."]').each(function () {
            var img = $(this),
                aZoom = img.parents('a.zoom'),
                aOver = img.parents('.dribbble-img').find('a.dribbble-over'),
                link = aOver.length ? aOver : aZoom;
            if (link.length) {
                link.data().hoverZoomSrc = [img.attr('src').replace('_teaser', '')];
                res.push(link);
            }
        });

        //sample url: https://cdn.dribbble.com/users/112047/screenshots/11090258/pat_drib_4x.jpg?compress=1&resize=1200x900
        // _4x.jpg?compress=1&resize=1200x900 -> .jpg
        $('img[src], [style*=url]').each(function() {

            var url;
            if ($(this).is('img')) {
                url = this.src;
            } else {
                let backgroundImage = this.style.backgroundImage;
                let reUrl = /.*url\s*\(\s*(.*)\s*\).*/i
                backgroundImage = backgroundImage.replace(reUrl, '$1');
                // remove leading & trailing quotes
                url = backgroundImage.replace(/^['"]/,"").replace(/['"]+$/,"");
            }

            var fullsizeUrl = url.replace('/thumbnail/','/').replace(/(mini|small|normal)/,'original').replace(/(_teaser|_1x|_2x|_3x|_4x)/, '').replace(/\?.*/, '');
            if (fullsizeUrl != url) {
                var link = $(this);
                if (link.data().hoverZoomSrc == undefined) { link.data().hoverZoomSrc = [] }
                if (link.data().hoverZoomSrc.indexOf(fullsizeUrl) == -1) {
                    link.data().hoverZoomSrc.unshift(fullsizeUrl);
                    res.push(link);
                }
            }
        });

        callback($(res), this.name);
    }
});

Fix for plug-in : Dribbble


$(document).ready(function() {
    $("#search-lots").autocomplete({
        minLength: 2,
        source: "/lots/search-ajax/",
        focus: function( event, ui ) {
            $("#search-lots").val( ui.item.name );
            return false;
        },
        select: function( event, ui ) {
            window.location.href = "/revenue/receipt/add/" + ui.item.name;
            return false;
        }
    }).autocomplete("instance")._renderItem = function(ul, item) {
        return $( "
" )
            .append( "
" + item.name + " " + item.address + "
" + item.owner__name + "
" )
            .appendTo( ul );
    };
});

function parse_decimal(str) {
    return str !== '' ? new BigNumber(str.replace(/[^0-9\.]+/g,"")) : new BigNumber('0.00');
}

$(document).ready(function() {
    $("#search-lots").autocomplete({
        minLength: 2,
        source: "/lots/search-ajax/",
        focus: function( event, ui ) {
            $("#search-lots").val( ui.item.name );
            return false;
        },
        select: function( event, ui ) {
            window.location.href = "/revenue/receipt/add/" + ui.item.name;
            return false;
        }
    }).autocomplete("instance")._renderItem = function(ul, item) {
        return $( "
" )
            .append( "
" + item.name + " " + item.address + "
" + item.owner__name + "
" )
            .appendTo( ul );
    };
});

function parse_decimal(str) {
    try {
        return new BigNumber(str.replace(/[^0-9\.]+/g,""));
    } catch (e) {
        return new BigNumber('0.00');
    }
}

Fix error when empty string


/**
 * ReactFashionWatch - a carefully crafted Fashion Watch component for React.
 * https://github.com/virtyaluk/react-fashion-watch
 *
 * Copyright (c) 2016 Bohdan Shtepan
 * http://modern-dev.com/
 *
 * Licensed under the MIT license.
 */

import cfg from './dist.config.babel';
import ExtractTextPlugin from 'extract-text-webpack-plugin';

cfg.output.filename = 'react-fashion-watch.min.js';
cfg.plugins[0] = new ExtractTextPlugin('styles.min.css');

export default cfg;

/**
 * ReactFashionWatch - a carefully crafted Fashion Watch component for React.
 * https://github.com/virtyaluk/react-fashion-watch
 *
 * Copyright (c) 2016 Bohdan Shtepan
 * http://modern-dev.com/
 *
 * Licensed under the MIT license.
 */

import cfg from './dist.config.babel';
import ExtractTextPlugin from 'extract-text-webpack-plugin';

cfg.output.filename = 'react-fashion-watch.min.js';
cfg.plugins[0] = new ExtractTextPlugin('react-fashion-watch.min.css');

export default cfg;

Fix output css file name


const {createConfig} = require('@webpack-blocks/webpack2')
const babel = require('@webpack-blocks/babel6')
const path = require('path')

const webpackConfig = createConfig([
  babel()
])

webpackConfig.resolve.alias = {}
webpackConfig.resolve.alias['rsg-components/Wrapper'] = path.join(__dirname, 'src/styleguide/Wrapper')

module.exports = {
  skipComponentsWithoutExample: true,
  components: 'src/components/**/[A-Z]*.js',
  webpackConfig
}

const {createConfig} = require('@webpack-blocks/webpack2')
const babel = require('@webpack-blocks/babel6')
const path = require('path')

const webpackConfig = createConfig([
  babel()
])

webpackConfig.resolve.alias = {}
webpackConfig.resolve.alias['rsg-components/Wrapper'] = path.join(__dirname, 'src/styleguide/Wrapper')

module.exports = {
  skipComponentsWithoutExample: true,
  components: 'src/components/**/[A-Z]*.js',
  webpackConfig,
  getComponentPathLine: (componentPath) => {
    const name = path.basename(componentPath, '.js')
    return `import { ${name} } from 'material-ui-bottom-sheet';`
  }
}

Fix the component path line in the styleguide.


annotationApp.service('morphRetriever', function($http) {
  this.getAnalyses = function(callback) {
    return $http.get('./js/controllers/analyses.json').then(callback);
  };
});

annotationApp.service('morphRetriever', function($http) {
  this.getAnalyses = function(callback) {
    return $http.get('./static/analyses.json').then(callback);
  };
});

Use static path in morphRetriever