import {HttpClient} from 'aurelia-http-client';
import {ContactModel} from 'src/models/contact-model';

var CONTACT_MANAGER_API_HOST = 'http://api-contact-manager.herokuapp.com';
var CONTACTS_URL = CONTACT_MANAGER_API_HOST + '/contacts';
var CONTACT_URL = CONTACT_MANAGER_API_HOST + '/contacts/${id}';

export class ContactService {
  static inject() { return [HttpClient]; }
  constructor(http){
    this.http = http;
  }

  getAll(){
    return this.http.get(CONTACTS_URL).then(response => {
      return response.content.map(data => {
        return new ContactModel(data);
      });
    });
  }

  getById(id){
    var contactUrl = CONTACT_URL.replace('${id}', id);
    return this.http.get(contactUrl).then(response => {
      return new ContactModel(response.content);
    });
  }

  create(contact){
    return this.http.post(CONTACTS_URL, contact).then(response => {
      return new ContactModel(response.content);
    });
  }

  update(contact){
    var contactUrl = CONTACT_URL.replace('${id}', contact.id);
    return this.http.put(contactUrl, contact).then(response => {
      return new ContactModel(response.content);
    });
  }

  delete(contact){
    var contactUrl = CONTACT_URL.replace('${id}', contact.id);
    return this.http.delete(contactUrl).then(response => {
      return true;
    });
  }
}

import {HttpClient} from 'aurelia-http-client';
import {ContactModel} from 'src/models/contact-model';

var CONTACT_MANAGER_API_HOST = 'http://api-contact-manager.herokuapp.com';
var CONTACTS_URL = CONTACT_MANAGER_API_HOST + '/contacts';
var CONTACT_URL = CONTACT_MANAGER_API_HOST + '/contacts/${id}';

export class ContactService {
  static inject() { return [HttpClient]; }
  constructor(http){
    this.http = http;
    this.http.configure((requestBuilder) => {
      requestBuilder.withCredentials(true);
    })
  }

  getAll(){
    return this.http.get(CONTACTS_URL).then(response => {
      return response.content.map(data => {
        return new ContactModel(data);
      });
    });
  }

  getById(id){
    var contactUrl = CONTACT_URL.replace('${id}', id);
    return this.http.get(contactUrl).then(response => {
      return new ContactModel(response.content);
    });
  }

  create(contact){
    return this.http.post(CONTACTS_URL, contact).then(response => {
      return new ContactModel(response.content);
    });
  }

  update(contact){
    var contactUrl = CONTACT_URL.replace('${id}', contact.id);
    return this.http.put(contactUrl, contact).then(response => {
      return new ContactModel(response.content);
    });
  }

  delete(contact){
    var contactUrl = CONTACT_URL.replace('${id}', contact.id);
    return this.http.delete(contactUrl).then(response => {
      return true;
    });
  }
}

Send requests with credentials to use session


'use strict';

let gulp = require('gulp');
let server = require('gulp-express');
let paths = {
	scripts: ['app.js', 'routes/**/*.js', 'public/**/*.js', 'gulpfile.js']
};

gulp.task('run', () => {
	server.run(['bin/www']);
});

gulp.task('watch', () => {
    gulp.watch([paths.scripts, ['run']]);
});

gulp.task('default', ['watch', 'run']);

'use strict';

let gulp = require('gulp');
let server = require('gulp-express');
let shell = require('gulp-shell');
let del = require('del');

let paths = {
	scripts: ['app.js', 'routes/**/*.js', 'public/**/*.js', 'gulpfile.js']
};

gulp.task('clean', () => {
	return del(['build']);
});

gulp.task('run', () => {
	server.run(['bin/www']);
});

gulp.task('watch', () => {
    gulp.watch([paths.scripts, ['run']]);
});

gulp.task('default', ['watch', 'run']);

gulp.task('electron', ['clean'], () => {
	return gulp.src(['main.js', './views/**/**', './public/**/**'])
		.pipe(gulp.dest('build/electron'));
});

Add gulp electron and gulp clean


var gulp = require('gulp'),
    tsc = require('gulp-tsc'),
    tape = require('gulp-tape'),
    tapSpec = require('tap-spec'),
    del = require('del'),
    runSequence = require('run-sequence'),
    istanbul = require('gulp-istanbul');

gulp.task("test:clean", function(done) {
  del(['build-test/**']).then(function(paths) {
    console.log("=====\nDeleted the following files:\n" + paths.join('\n')+ "\n=====");
    done();
  });
});

gulp.task("test:build", function (done) {
  gulp.src('test/**/*.ts')
    .pipe(tsc())
    .pipe(gulp.dest('build-test/'))
    .on('end', done);
});

gulp.task("test:istanbul-hook", function () {
  return gulp.src('build-test/src/**/*.js')
    .pipe(istanbul())
    .pipe(istanbul.hookRequire());
});

gulp.task("test:run", function (done) {
  gulp.src('build-test/test/**/*.test.js')
    .pipe(tape({
      reporter: tapSpec()
    }))
    .pipe(istanbul.writeReports())
    .on('end', done);
});

gulp.task("test", function (done) {
  runSequence('test:clean', 'test:build', 'test:istanbul-hook', 'test:run', done);
});

var gulp = require('gulp'),
    tsc = require('gulp-tsc'),
    tape = require('gulp-tape'),
    tapSpec = require('tap-spec'),
    del = require('del'),
    runSequence = require('run-sequence'),
    istanbul = require('gulp-istanbul');

gulp.task("test:clean", function(done) {
  del(['build-test/**']).then(function(paths) {
    console.log("=====\nDeleted the following files:\n" + paths.join('\n')+ "\n=====");
    done();
  });
});

gulp.task("test:build", function (done) {
  gulp.src('test/**/*.ts')
    .pipe(tsc())
    .pipe(gulp.dest('build-test/'))
    .on('end', done);
});

gulp.task("test:istanbul-hook", function () {
  return gulp.src('build-test/src/**/*.js')
    .pipe(istanbul())
    .pipe(istanbul.hookRequire());
});

gulp.task("test:run", function (done) {
  gulp.src('build-test/test/**/*.test.js')
    .pipe(tape({
      reporter: tapSpec()
    }))
    .pipe(istanbul.writeReports({
      reporters: [ 'lcov', 'json', 'text-summary' ]
    }))
    .on('end', done);
});

gulp.task("test", function (done) {
  runSequence('test:clean', 'test:build', 'test:istanbul-hook', 'test:run', done);
});

Use coverage summary rather than full coverage breakdown


import _ from 'lodash';
import {API_PATH} from 'power-ui/conf';
import {urlToRequestObjectWithHeaders, isTruthy} from 'power-ui/utils';

// Handle all HTTP networking logic of this page
function PeoplePageHTTP(sources) {
  const PEOPLE_URL = `${API_PATH}/people/`;

  const atomicResponse$ = sources.HTTP
    .filter(response$ => _.startsWith(response$.request.url, PEOPLE_URL))
    .mergeAll()
    .filter(response => isTruthy(response.body))
    .shareReplay(1);

  const request$ = atomicResponse$
    .filter(response => response.body.next)
    .map(response => response.body.next.replace('limit=5', 'limit=40'))
    .startWith(PEOPLE_URL + '?limit=5')
    .map(urlToRequestObjectWithHeaders);

  const response$ = atomicResponse$
    .map(response => response.body.results)
    .scan((acc, curr) => acc.concat(curr));

  return {request$, response$}; // sink
}

export default PeoplePageHTTP;

import _ from 'lodash';
import {API_PATH} from 'power-ui/conf';
import {urlToRequestObjectWithHeaders, isTruthy} from 'power-ui/utils';

// Handle all HTTP networking logic of this page
function PeoplePageHTTP(sources) {
  const PEOPLE_URL = `${API_PATH}/people/`;

  const atomicResponse$ = sources.HTTP
    .filter(response$ => _.startsWith(response$.request.url, PEOPLE_URL))
    .mergeAll()
    .filter(response => isTruthy(response.body))
    .shareReplay(1);

  const request$ = atomicResponse$
    .filter(response => response.body.next)
    .map(response => response.body.next.replace('limit=5', 'limit=40'))
    // TODO get real time range from sources somehow
    .startWith(PEOPLE_URL + '?limit=5&range_start=2015-09-01&range_end=2015-11-30')
    .map(urlToRequestObjectWithHeaders);

  const response$ = atomicResponse$
    .map(response => response.body.results)
    .scan((acc, curr) => acc.concat(curr));

  return {request$, response$}; // sink
}

export default PeoplePageHTTP;

Add temporary selection of time range


import { createSelector } from 'reselect';

import * as dataSelectors from '../../../selectors/dataSelectors';

export const positionSettingsSelector = state => state.get('positionSettings');

export const getRenderedDataSelector = state => state.get('renderedData');

/** Gets the number of viisble rows based on the height of the container and the rowHeight
 */
export const visibleRecordCountSelector = createSelector(
  positionSettingsSelector,
  (positionSettings) => {
    const rowHeight = positionSettings.get('rowHeight');
    const height = positionSettings.get('height');

    return Math.ceil(height / rowHeight);
  }
);

// From what i can tell from the original virtual scrolling plugin...
// 1. We want to get the visible record count
// 2. Get the size of the dataset we're working with (whether thats local or remote)
// 3. Figure out the renderedStart and End display index
// 4. Show only the records that'd fall in the render indexes

Add comment about how to proceed


import Promise from 'bluebird';
import { GetVideoResponse, VideoLocationType } from './protos';
import { toCassandraUuid, toProtobufTimestamp, toProtobufUuid } from '../common/protobuf-conversions';
import { NotFoundError } from '../common/grpc-errors';
import { getCassandraClient } from '../../common/cassandra';

/**
 * Gets the details of a specific video from the catalog.
 */
export function getVideo(call, cb) {
  return Promise.try(() => {
    let { request } = call;

    let client = getCassandraClient();
    let requestParams = [
      toCassandraUuid(request.videoId)
    ];
    return client.executeAsync('SELECT * FROM videos WHERE videoid = ?', requestParams);
  })
  .then(resultSet => {
    let row = resultSet.first();
    if (row === null) {
      throw new NotFoundError(`A video with id ${request.videoId.value} was not found`);
    }

    return new GetVideoResponse({
      videoId: toProtobufUuid(row.videoid),
      userId: toProtobufUuid(row.userid),
      name: row.name,
      description: row.description,
      location: row.location,
      locationType: row.location_type,
      tags: row.tags,
      addedDate: toProtobufTimestamp(row.added_date)
    });
  })
  .asCallback(cb);
};

import Promise from 'bluebird';
import { GetVideoResponse, VideoLocationType } from './protos';
import { toCassandraUuid, toProtobufTimestamp, toProtobufUuid } from '../common/protobuf-conversions';
import { NotFoundError } from '../common/grpc-errors';
import { getCassandraClient } from '../../common/cassandra';

/**
 * Gets the details of a specific video from the catalog.
 */
export function getVideo(call, cb) {
  return Promise.try(() => {
    let { request } = call;

    let client = getCassandraClient();
    let requestParams = [
      toCassandraUuid(request.videoId)
    ];
    return client.executeAsync('SELECT * FROM videos WHERE videoid = ?', requestParams);
  })
  .then(resultSet => {
    let row = resultSet.first();
    if (row === null) {
      throw new NotFoundError(`A video with id ${request.videoId.value} was not found`);
    }

    return new GetVideoResponse({
      videoId: toProtobufUuid(row.videoid),
      userId: toProtobufUuid(row.userid),
      name: row.name,
      description: row.description,
      location: row.location,
      locationType: row.location_type,
      tags: row.tags === null ? [] : row.tags,
      addedDate: toProtobufTimestamp(row.added_date)
    });
  })
  .asCallback(cb);
};

Handle null tags when getting video


Add an extra call in test script to trigger JIT


'use strict';

// mocha defines to avoid JSHint breakage
/* global describe, it, before, beforeEach, after, afterEach */

var assert = require('../../utils/assert.js');
var preq   = require('preq');
var server = require('../../utils/server.js');

describe('router - misc', function() {
    this.timeout(20000);

    before(function () { return server.start(); });

    it('should deny access to /{domain}/sys', function() {
        return preq.get({
            uri: server.config.hostPort + '/en.wikipedia.org/sys/table'
        }).catch(function(err) {
            assert.deepEqual(err.status, 403);
        });
    });

});

'use strict';

// mocha defines to avoid JSHint breakage
/* global describe, it, before, beforeEach, after, afterEach */

var assert = require('../../utils/assert.js');
var preq   = require('preq');
var server = require('../../utils/server.js');

describe('router - misc', function() {

    this.timeout(20000);

    before(function () { return server.start(); });

    it('should deny access to /{domain}/sys', function() {
        return preq.get({
            uri: server.config.hostPort + '/en.wikipedia.org/sys/table'
        }).catch(function(err) {
            assert.deepEqual(err.status, 403);
        });
    });

    it('should set a request ID for each sub-request and return it', function() {
        var slice = server.config.logStream.slice();
        return preq.get({
            uri: server.config.bucketURL + '/html/Foobar',
            headers: {
                'Cache-Control': 'no-cache'
            }
        }).then(function(res) {
            slice.halt();
            var reqId = res.headers['x-request-id'];
            assert.notDeepEqual(reqId, undefined, 'Request ID not returned');
            slice.get().forEach(function(line) {
                var a = JSON.parse(line);
                if(a.req || a.request_id) {
                    assert.deepEqual(a.request_id, reqId, 'Request ID mismatch');
                }
            });
        });
    });

    it('should honour the provided request ID', function() {
        var reqId = 'b6c17ea83d634b31bb28d60aae1caaac';
        var slice = server.config.logStream.slice();
        return preq.get({
            uri: server.config.bucketURL + '/html/Foobar',
            headers: {
                'X-Request-Id': reqId
            }
        }).then(function(res) {
            slice.halt();
            assert.deepEqual(res.headers['x-request-id'], reqId, 'Returned request ID does not match the sent one');
            slice.get().forEach(function(line) {
                var a = JSON.parse(line);
                if(a.req || a.request_id) {
                    assert.deepEqual(a.request_id, reqId, 'Request ID mismatch');
                }
            });
        });
    });

});

Add tests for the request ID generation and retrieval


/* eslint-disable no-console */
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = process.env.PORT || 3000;

const api = require('../lib/api');

app.all('/*', (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With');
    next();
});

app.use(bodyParser.json({ limit: '5mb' }));
app.use(bodyParser.urlencoded({ extended: true }));

app.use('/api/v1', api);

app.listen(port, () => {
    console.log(`Listening on port ${port}`);
});
/* eslint-enable no-console */

/* eslint-disable no-console */
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = process.env.PORT || 3000;

const api = require('../lib/api');

app.all('/*', (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'X-Requested-With');
    next();
});

app.use(bodyParser.json({ limit: '5mb' }));
app.use(bodyParser.urlencoded({ extended: true }));

app.use('/api/v1', api);
app.use('/embed/v1', api);
app.use('/embed/api/v1', api);

app.listen(port, () => {
    console.log(`Listening on port ${port}`);
});
/* eslint-enable no-console */

Update to use extra endpoints


$(window).load(function () {
    var Ector = require('ector');
    ector = new Ector();
    var previousResponseNodes = null;
    var user = { username: "Guy"};
    var msgtpl = $('#msgtpl').html();
    var lastmsg = false;
    $('#msgtpl').remove();
    var message;

    $('#send').on('click', function () {
        var d = new Date();
        var entry = $('#message').val();
        message = {
            user: user,
            message: entry,
            h: d.getHours(),
            m: d.getMinutes()
        };
        $('#message').attr('value',''); // FIXME

        $('#messages').append('
' + Mustache.render(msgtpl, message) + '
');
        $('#messages').animate({scrollTop : $('#messages').prop('scrollHeight')}, 500);

        ector.addEntry(entry);
        ector.linkNodesToLastSentence(previousResponseNodes);
        var response = ector.generateResponse();
        // console.log('%s: %s', ector.name, response.sentence);
        previousResponseNodes = response.nodes;

        d = new Date();
        message = {
            user: {username: ector.name},
            message: response.sentence,
            h: d.getHours(),
            m: d.getMinutes()
        };
        $('#messages').append('
' + Mustache.render(msgtpl, message) + '
');
        $('#messages').animate({scrollTop : $('#messages').prop('scrollHeight')}, 500);
        return false;
    });
});

$(window).load(function () {
    var Ector = require('ector');
    ector = new Ector();
    var previousResponseNodes = null;
    var user = { username: "Guy"};
    var msgtpl = $('#msgtpl').html();
    var lastmsg = false;
    $('#msgtpl').remove();
    var message;

    $('#send').on('click', function () {
        var d = new Date();
        var entry = $('#message').val();
        message = {
            user: user,
            message: entry,
            h: d.getHours(),
            m: d.getMinutes()
        };
        $('#message').attr('value','');

        $('#messages').append('
' + Mustache.render(msgtpl, message) + '
');
        $('#messages').animate({scrollTop : $('#messages').prop('scrollHeight')}, 500);

        ector.addEntry(entry);
        ector.linkNodesToLastSentence(previousResponseNodes);
        var response = ector.generateResponse();
        // console.log('%s: %s', ector.name, response.sentence);
        previousResponseNodes = response.nodes;

        d = new Date();
        message = {
            user: {username: ector.name},
            message: response.sentence,
            h: d.getHours(),
            m: d.getMinutes()
        };
        $('#messages').append('
' + Mustache.render(msgtpl, message) + '
');
        $('#messages').animate({scrollTop : $('#messages').prop('scrollHeight')}, 500);
        return false;
    });
});

Remove the comment (line already fixed)


var Checker = require('../lib/checker');
var assert = require('assert');

describe('rules/require-blocks-on-newline', function() {
    var checker;
    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
    });
    it('should report missing newline after opening brace', function() {
        checker.configure({ requireBlocksOnNewline: true });
        assert(checker.checkString('if (true) {abc();\n}').getErrorCount() === 1);
    });
    it('should report missing newline before closing brace', function() {
        checker.configure({ requireBlocksOnNewline: true });
        assert(checker.checkString('if (true) {\nabc();}').getErrorCount() === 1);
    });
    it('should report missing newlines in both cases', function() {
        checker.configure({ requireBlocksOnNewline: true });
        assert(checker.checkString('if (true) {abc();}').getErrorCount() === 2);
    });
    it('should not report with no spaces', function() {
        checker.configure({ requireBlocksOnNewline: true });
        assert(checker.checkString('if (true) {\nabc();\n}').isEmpty());
    });
    it('should not report empty function definitions', function() {
        checker.configure({ requireBlocksOnNewline: true });
        assert(checker.checkString('var a = function() {};').isEmpty());
    });
});

var Checker = require('../lib/checker');
var assert = require('assert');

describe('rules/require-blocks-on-newline', function() {
    var checker;
    beforeEach(function() {
        checker = new Checker();
        checker.registerDefaultRules();
        checker.configure({ requireBlocksOnNewline: true });
    });
    it('should report missing newline after opening brace', function() {
        assert(checker.checkString('if (true) {abc();\n}').getErrorCount() === 1);
    });
    it('should report missing newline before closing brace', function() {
        assert(checker.checkString('if (true) {\nabc();}').getErrorCount() === 1);
    });
    it('should report missing newlines in both cases', function() {
        assert(checker.checkString('if (true) {abc();}').getErrorCount() === 2);
    });
    it('should not report with no spaces', function() {
        assert(checker.checkString('if (true) {\nabc();\n}').isEmpty());
    });
    it('should not report empty function definitions', function() {
        assert(checker.checkString('var a = function() {};').isEmpty());
    });
});

Move checker.configure(...) line to beforeeach


/**
 * Main controller for Ghost frontend
 */

/*global require, module */

var Ghost = require('../../ghost'),
    api = require('../api'),

    ghost = new Ghost(),
    frontendControllers;

frontendControllers = {
    'homepage': function (req, res) {
        // Parse the page number
        var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1;

        // No negative pages
        if (pageParam < 1) {
            return res.redirect("/page/1/");
        }

        api.posts.browse({page: pageParam}).then(function (page) {
            // If page is greater than number of pages we have, redirect to last page
            if (pageParam > page.pages) {
                return res.redirect("/page/" + (page.pages) + "/");
            }

            // Render the page of posts
            ghost.doFilter('prePostsRender', page.posts, function (posts) {
                res.render('index', {posts: posts, pagination: {page: page.page, prev: page.prev, next: page.next, limit: page.limit, total: page.total, pages: page.pages}});
            });
        });
    },
    'single': function (req, res) {
        api.posts.read({'slug': req.params.slug}).then(function (post) {
            ghost.doFilter('prePostsRender', post.toJSON(), function (post) {
                res.render('post', {post: post});
            });
        });
    }
};

module.exports = frontendControllers;

/**
 * Main controller for Ghost frontend
 */

/*global require, module */

var Ghost = require('../../ghost'),
    api = require('../api'),

    ghost = new Ghost(),
    frontendControllers;

frontendControllers = {
    'homepage': function (req, res) {
        // Parse the page number
        var pageParam = req.params.page !== undefined ? parseInt(req.params.page, 10) : 1;

        // No negative pages
        if (pageParam < 1) {
            return res.redirect("/page/1/");
        }

        api.posts.browse({page: pageParam}).then(function (page) {
            var maxPage = page.pages;

            // A bit of a hack for situations with no content.
            if (maxPage === 0) {
                maxPage = 1;
                page.pages = 1;
            }

            // If page is greater than number of pages we have, redirect to last page
            if (pageParam > maxPage) {
                return res.redirect("/page/" + maxPage + "/");
            }

            // Render the page of posts
            ghost.doFilter('prePostsRender', page.posts, function (posts) {
                res.render('index', {posts: posts, pagination: {page: page.page, prev: page.prev, next: page.next, limit: page.limit, total: page.total, pages: page.pages}});
            });
        });
    },
    'single': function (req, res) {
        api.posts.read({'slug': req.params.slug}).then(function (post) {
            ghost.doFilter('prePostsRender', post.toJSON(), function (post) {
                res.render('post', {post: post});
            });
        });
    }
};

module.exports = frontendControllers;

Fix redirect loop when no content


/**
 * Created by alex on 11/30/15.
 */

describe('ColorFinder class', function () {

    it('should get default config value', function () {
        expect(ColorFinder.getConfig('maxColorValue')).toBe(230);
    });

    it('should update config value', function () {
        expect(ColorFinder.setConfig('maxColorValue', 200).getConfig('maxColorValue')).toBe(200);
    });

});

/**
 * Created by alex on 11/30/15.
 */

describe('ColorFinder class', function () {

    it('should get default config value', function () {
        expect(ColorFinder.getConfig('maxColorValue')).toBe(230);
    });

    it('should update config value', function () {
        expect(ColorFinder.setConfig('maxColorValue', 200).getConfig('maxColorValue')).toBe(200);
    });

    it('should throw error if config key unknown', function () {
        expect(function () {
            ColorFinder.setConfig('customConfig', 'OK?');
        }).toThrow(new Error('ColorFinder: setConfig: Invalid config key'));
    });

});

Add one more test to init travis


var RippleGateway = require('../../lib/http_client.js').Gateway;
var crypto = require('crypto');
var assert = require('assert');
function rand() { return crypto.randomBytes(32).toString('hex'); }

describe('RippleTransactions', function(){

  describe('on behalf of a user', function(){

    it.skip('should create a payment to a ripple account', function(){
      // POST /payments
      done();
    });

    it.skip('should not be able to send a payment to the gateway', function(){
      // POST /payments
      done();
    });

    it.skip('should list all payments made to or from a user', function(){
      // GET /payments
      done();
    });

  });

  describe('on behalf of an admin', function(){

    it.skip('should create payment to a ripple account', function(){
      // POST /payments
      done();
    });

    it.skip('should list payments sent to or from a hosted wallet', function(){
      // GET /payments
      done();
    });

    it.skip('should list all payments made to or from all hosted wallets', function(){
      // GET /payments
      done();
    });

  });

});

var RippleGateway = require('../../lib/http_client.js').Gateway;
var crypto = require('crypto');
var assert = require('assert');
function rand() { return crypto.randomBytes(32).toString('hex'); }

describe('RippleTransactions', function(){

  describe('on behalf of a user', function(){

    before(function(done){
      client = new RippleGateway.Client({
        api: 'https://localhost:4000'
      });
      client.user = rand();
      client.secret = rand();
      client.createUser({}, function(err, resp){
        if (err) { throw new Error(err); }
        user = resp;
        done();
      });
    });

    it('should create a payment to a ripple account', function(done){
      var paymentOptions = {
        to_account: 'rNeSkJhcxDaqzZCAvSfQrxwPJ2Kjddrj4a',
        from_account: 'rNeSkJhcxDaqzZCAvSfQrxwPJ2Kjddrj4a',
        from_tag: '2',
        amount: '1',
        currency: 'USD'
      };
      client.sendPayment(paymentOptions, function(err, payment){
        console.log(err, payment);
        assert(!err);
        assert(payment.id > 0);
        done();
      });
    });

    it('should not be able to send a payment to the gateway', function(done){
      // POST /payments
      assert(true);
      done();
    });

    it.skip('should list all payments made to or from a user', function(done){
      // GET /payments
      done();
    });

  });

  describe('on behalf of an admin', function(){

    it.skip('should create payment to a ripple account', function(done){
      // POST /payments
      done();
    });

    it.skip('should list payments sent to or from a hosted wallet', function(done){
      // GET /payments
      done();
    });

    it.skip('should list all payments made to or from all hosted wallets', function(done){
      // GET /payments
      done();
    });

  });

});

Add example test for sending payment.


var router = require( 'express' ).Router()
var Post = require( '../../models/post' )
var websockets = require( '../../websockets' )

router.get( '/', function( req, res, next ) {
    Post.find()
    .sort( '-date' )
    .exec( function( err, posts ) {
        if ( err ) { return next( err ) }
        res.json( posts )
    })
})

router.post( '/', function( req, res, next ) {
    var post = new Post({
        body: req.body.body
    })
    post.username = req.auth.username
    post.save( function ( err, post ) {
        if ( err ) { return next( err ) }
        websockets.broadcast( 'new_post', post )
        res.json( 201, post )
    })
})

module.exports = router

var router = require( 'express' ).Router()
var Post = require( '../../models/post' )
var websockets = require( '../../websockets' )

router.get( '/', function( req, res, next ) {
    Post.find()
    .sort( '-date' )
    .exec( function( err, posts ) {
        if ( err ) { return next( err ) }
        res.json( posts )
    })
})

router.post( '/', function( req, res, next ) {
    var post = new Post({
        body: req.body.body
    })
    post.username = req.auth.username
    post.save( function ( err, post ) {
        if ( err ) { return next( err ) }
        websockets.broadcast( 'new_post', post )
        res.status( 201).json( post )
    })
})

module.exports = router

Change post json handling on success


var Barista    = require(process.cwd() + '/lib/barista.js'),
    Backbone   = require('backbone'),
    ExampleApp = require(process.cwd() + '/spec/ex1/exampleApp1.js'),
    context    = describe;

describe('Barista.Model', function() {
  var model;

  beforeEach(function() {
    Barista.config(ExampleApp);
  });

  describe('isA', function() {
    it('returns true with arg \'Backbone.Model\'', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Backbone.Model')).toBe(true);
    });

    it('returns true with arg\'Barista.Model\'', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Barista.Model')).toBe(true);
    });

    it('returns false with another argument', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Barista.Collection')).toBe(false);
    });
  });

  describe('sync', function() {
    beforeEach(function() {
      model = new Barista.TaskModel();
      spyOn(Backbone, 'sync');
    });

    it('does not call Backbone.sync', function() {
      model.sync();
      expect(Backbone.sync).not.toHaveBeenCalled();
    });
  });

  describe('get', function() {

  });
});

var Barista    = require(process.cwd() + '/lib/barista.js'),
    Backbone   = require('backbone'),
    ExampleApp = require(process.cwd() + '/spec/ex1/exampleApp1.js'),
    context    = describe;

describe('Barista.Model', function() {
  var model;

  beforeEach(function() {
    Barista.config(ExampleApp);
  });

  describe('isA', function() {
    it('returns true with arg \'Backbone.Model\'', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Backbone.Model')).toBe(true);
    });

    it('returns true with arg\'Barista.Model\'', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Barista.Model')).toBe(true);
    });

    it('returns false with another argument', function() {
      var newModel = new Barista.Model();
      expect(newModel.isA('Barista.Collection')).toBe(false);
    });
  });

  describe('sync', function() {
    beforeEach(function() {
      model = new Barista.TaskModel();
      spyOn(Backbone, 'sync');
    });

    it('does not call Backbone.sync', function() {
      model.sync();
      expect(Backbone.sync).not.toHaveBeenCalled();
    });
  });

  describe('get', function() {
    beforeEach(function() {
      model = new Barista.TaskModel({title: 'Foobar'});
    });

    it('retrieves the object\'s attribute', function() {
      expect(model.get('title')).toBe('Foobar');
    });
  });
});

Add specs for the sync method of the model prototype


module.exports = {
  database: 'factory-girl-sequelize',
  options: {
    dialect: 'sqlite',
    storage: 'test/tmp/test.db',
    logging: null
  }
};

module.exports = {
  database: 'factory-girl-sequelize',
  options: {
    dialect: 'sqlite',
    storage: ':memory:',
    logging: null
  }
};

Change to use in-memory SQLite


/* global navigator, Promise*/

import Ember from 'ember';

const Mock = Ember.Object.extend({
  available: true,
  name: null,
  value: null,

  isAvailable(value) {
    return this._setAndMock('available', value);
  },

  deviceName(deviceName) {
    return this._setAndMock('name', deviceName);
  },

  characteristicValue(value) {
    return this._setAndMock('value', value);
  },

  _setAndMock(key, value) {
    this.set(key, value);

    this._mock();

    return this;
  },

  _mock() {
    let isAvailable = this.get('available');
    let deviceName = this.get('name');
    let characteristicValue = this.get('value');

    let bluetooth;

    if (isAvailable) {
      bluetooth = {
        requestDevice: function() {
          return Promise.resolve({
            name: deviceName,
            gatt: function() {
              return Promise.resolve({
                getPrimaryService: function() {
                  return Promise.resolve({
                    getCharacteristic: function() {
                      return Promise.resolve({
                        readValue: function() {
                          return Promise.resolve({
                            getUint8: function() {
                              return characteristicValue;
                            }
                          });
                        }
                      });
                    }
                  });
                }
              });
            }
          });
        }
      };
    }

    this._createGetter(bluetooth);
  },

  _createGetter(value) {
    navigator.__defineGetter__('bluetooth', function(){
      return value;
    });
  }
});

export default function mockBluetooth() {
  let instance = Mock.create();

  return instance;
}

/* global navigator, Promise*/

import Ember from 'ember';

const Mock = Ember.Object.extend({
  available: true,
  name: null,
  value: null,

  isAvailable(value) {
    return this._setAndMock('available', value);
  },

  deviceName(deviceName) {
    return this._setAndMock('name', deviceName);
  },

  characteristicValue(value) {
    return this._setAndMock('value', value);
  },

  _setAndMock(key, value) {
    this.set(key, value);

    this._mock();

    return this;
  },

  _mock() {
    let isAvailable = this.get('available');
    let deviceName = this.get('name');
    let characteristicValue = this.get('value');

    let bluetooth;

    if (isAvailable) {
      bluetooth = {
        requestDevice: function() {
          return Promise.resolve({
            name: deviceName,
            gatt: {
              connect: function() {
                return Promise.resolve({
                  getPrimaryService: function() {
                    return Promise.resolve({
                      getCharacteristic: function() {
                        return Promise.resolve({
                          readValue: function() {
                            return Promise.resolve({
                              getUint8: function() {
                                return characteristicValue;
                              }
                            });
                          }
                        });
                      }
                    });
                  }
                });
              }
            }
          });
        }
      };
    }

    this._createGetter(bluetooth);
  },

  _createGetter(value) {
    navigator.__defineGetter__('bluetooth', function(){
      return value;
    });
  }
});

export default function mockBluetooth() {
  let instance = Mock.create();

  return instance;
}

Add connect function to mockBluetooth


const amoCDN = 'https://addons-cdn.allizom.org';
const staticHost = 'https://addons-discovery-cdn.allizom.org';

module.exports = {
  staticHost,

  CSP: {
    directives: {
      scriptSrc: [staticHost],
      styleSrc: [staticHost],
      imgSrc: [
        "'self'",
        'data:',
        amoCDN,
        staticHost,
      ],
      mediaSrc: [staticHost],
    },
  },
};

const amoCDN = 'https://addons-stage-cdn.allizom.org';
const staticHost = 'https://addons-discovery-cdn.allizom.org';

module.exports = {
  staticHost,

  CSP: {
    directives: {
      scriptSrc: [staticHost],
      styleSrc: [staticHost],
      imgSrc: [
        "'self'",
        'data:',
        amoCDN,
        staticHost,
      ],
      mediaSrc: [staticHost],
    },
  },
};

Update amoCDN for disco stage config


export default function areObjectValuesDefined(obj) {
    return Object.keys(obj)
        .map((key) => obj[key])
        .reduce((prev, value) => {
            return prev && value !== undefined;
        }, true);
}

/**
 * Checks if all values in a object are defined
 * @param {Object} obj The object
 * @return {boolean}
 */
export default function areObjectValuesDefined(obj) {
    return Object.keys(obj)
        .map((key) => obj[key])
        .every(isDefined);
}

function isDefined(value) {
    return value !== undefined;
}

Use every() instead of reduce()


function EmscriptenPrecacheApi(apiPointer, cwrap, runtime) {

    var _apiPointer = apiPointer;
    var _beginPrecacheOperation = null;
    var _cancelPrecacheOperation = null;
    var _cancelCallback = null;
    var _completeCallback = null;

    this.registerCallbacks = function(completeCallback, cancelCallback) {
        if (_completeCallback !== null) {
            runtime.removeFunction(_completeCallback);
        }
        _completeCallback = runtime.addFunction(completeCallback);
        if (_cancelCallback !== null) {
            runtime.removeFunction(_cancelCallback);
        }
        _cancelCallback = runtime.addFunction(cancelCallback);
    };

    this.beginPrecacheOperation = function(operationId, operation) {
        _beginPrecacheOperation = _beginPrecacheOperation || cwrap("beginPrecacheOperation", null, ["number", "number", "number", "number", "number", "number", "number"]);

        var latlong = operation.getCentre();
        _beginPrecacheOperation(_apiPointer, operationId, latlong.lat, latlong.lng, operation.getRadius(), _completeCallback, _cancelCallback);
    };

    this.cancelPrecacheOperation = function(operationId) {
        _cancelPrecacheOperation = _cancelPrecacheOperation || cwrap("cancelPrecacheOperation", null, ["number", "number"]);
        _cancelPrecacheOperation(_apiPointer, operationId);
    };
}

module.exports = EmscriptenPrecacheApi;

function EmscriptenPrecacheApi(apiPointer, cwrap, runtime) {

    var _apiPointer = apiPointer;
    var _beginPrecacheOperation = null;
    var _cancelPrecacheOperation = null;
    var _cancelCallback = null;
    var _completeCallback = null;

    this.registerCallbacks = function(completeCallback, cancelCallback) {
        if (_completeCallback !== null) {
            runtime.removeFunction(_completeCallback);
        }
        _completeCallback = runtime.addFunction(completeCallback);
        if (_cancelCallback !== null) {
            runtime.removeFunction(_cancelCallback);
        }
        _cancelCallback = runtime.addFunction(cancelCallback);
    };

    this.beginPrecacheOperation = function(operationId, operation) {
        _beginPrecacheOperation = _beginPrecacheOperation || cwrap("beginPrecacheOperation", null, ["number", "number", "number", "number", "number", "number", "number"]);

        var latlong = operation.getCentre();
        _beginPrecacheOperation(_apiPointer, operationId, latlong.lat, latlong.lng, operation.getRadius(), _completeCallback, _cancelCallback);
    };

    this.cancelPrecacheOperation = function(operationId) {
        _cancelPrecacheOperation = _cancelPrecacheOperation || cwrap("cancelPrecacheOperation___", null, ["number", "number"]);
        _cancelPrecacheOperation(_apiPointer, operationId);
    };
}

module.exports = EmscriptenPrecacheApi;

Test that a broken function binding is detected when testing interop, and halts deployment.


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

var _allTests = [
    "twig_test.html",
    "twig/environment_test.html",
    "twig/filter_test.html",
    "twig/markup_test.html",
    "templates/template_tests.html"
];

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

var _allTests = [
    "twig_test.html",
    "twig/environment_test.html",
    "twig/markup_test.html",
    "templates/template_tests.html"
];

Remove references to filter tests


"use strict";

var format = require('util').format;
var config = require('config');

function upgradeLegacyAccount(req, res, next) {
  if (!req.session.legacyInstanceId) {
    return next();
  }
  // User is trying to upgrade their account
  var instanceId = req.session.legacyInstanceId;
  delete req.session.legacyInstanceId;
  var Permission = req.popit.permissions();
  Permission.create({
    account: req.user.id,
    instance: instanceId,
    role: 'owner',
  }, function(err) {
    if (err) {
      return next(err);
    }
    req.flash('info', 'Account successfully upgraded');
    var Instance = req.popit.master().model('Instance');
    Instance.findById(instanceId, function(err, instance) {
      if (err) {
        return next(err);
      }
      // Redirect to the instance the user was trying to log into
      res.redirect(format(config.instance_server.base_url_format, instance.slug));
    });
  });
}

module.exports = upgradeLegacyAccount;

"use strict";

var format = require('util').format;
var config = require('config');

function upgradeLegacyAccount(req, res, next) {
  if (!req.session.legacyInstanceId) {
    return next();
  }
  // User is trying to upgrade their account
  var instanceId = req.session.legacyInstanceId;
  delete req.session.legacyInstanceId;
  var Permission = req.popit.permissions();
  Permission.create({
    account: req.user.id,
    instance: instanceId,
    role: 'owner',
  }, function(err) {
    if (err) {
      return next(err);
    }
    req.flash('info', 'Account successfully upgraded');
    var Instance = req.popit.master().model('Instance');
    Instance.findById(instanceId, function(err, instance) {
      if (err) {
        return next(err);
      }
      if (!instance) {
        return res.redirect('/instances');
      }
      // Redirect to the instance the user was trying to log into
      res.redirect(format(config.instance_server.base_url_format, instance.slug));
    });
  });
}

module.exports = upgradeLegacyAccount;

Fix legacy upgrade with missing instance


var gulp = require('gulp');
var jshint = require('gulp-jshint');
var jasmine = require('gulp-jasmine');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');

gulp.task('lint', function () {
    gulp.src('./*.js')
        .pipe(jshint('jshintrc.json'))
        .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('test', function () {
    gulp.src('test.js')
        .pipe(jasmine());
});

gulp.task('uglify', function () {
    gulp.src('lambada.js')
        .pipe(uglify())
        .pipe(rename('lambada.min.js'))
        .pipe(gulp.dest('.'));
});

gulp.task('default', ['lint', 'test']);

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var jasmine = require('gulp-jasmine');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');

gulp.task('lint', function () {
    return gulp.src('./*.js')
        .pipe(jshint('jshintrc.json'))
        .pipe(jshint.reporter('jshint-stylish'));
});

gulp.task('test', function () {
    return gulp.src('test.js')
        .pipe(jasmine());
});

gulp.task('uglify', function () {
    return gulp.src('lambada.js')
        .pipe(uglify())
        .pipe(rename('lambada.min.js'))
        .pipe(gulp.dest('.'));
});

gulp.task('default', ['lint', 'test']);

Return the stream for each task


var gulp = require('gulp'),
    eslint = require('gulp-eslint'),
    mocha = require('gulp-mocha'),
    flow = require('gulp-flowtype'),
    babel = require('babel/register');

gulp.task('lint', function() {
    return gulp.src(['src/*.js', 'src/__tests__/*.js'])
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failOnError());
});

gulp.task('typecheck', function() {
    return gulp.src(['src/*.js', 'src/__tests__/*.js'])
        .pipe(flow({
            all: false,
            weak: false,
            declarations: './build/flow',
            killFlow: false,
            beep: true,
            abort: false
        }));
});

gulp.task('test', ['lint'], function() {

    global.expect = require('chai').expect;
    global.sinon = require('sinon');

    return gulp.src(['src/__tests__/{,*/}*-test.js'])
            .pipe(mocha({
                compilers: {
                    js: babel
                },
                reporter: 'spec',
                ui: 'bdd'
            }));
});

gulp.task('default', ['lint', 'test']);

var gulp = require('gulp'),
    eslint = require('gulp-eslint'),
    mocha = require('gulp-mocha'),
    flow = require('gulp-flowtype'),
    babel = require('babel/register');

gulp.task('lint', function() {
    return gulp.src(['src/*.js', 'src/__tests__/*.js'])
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failOnError());
});

gulp.task('typecheck', function() {
    return gulp.src(['src/*.js', 'src/__tests__/*.js'])
        .pipe(flow({
            all: false,
            weak: false,
            declarations: './build/flow',
            killFlow: false,
            beep: true,
            abort: false
        }));
});

gulp.task('test', ['lint'], function() {

    global.expect = require('chai').expect;
    global.sinon = require('sinon');
    global.document = {
        location: {
            pathname: ''
        }
    };

    global.window = {
        addEventListener() {}
    };

    return gulp.src(['src/__tests__/{,*/}*-test.js'])
            .pipe(mocha({
                compilers: {
                    js: babel
                },
                reporter: 'spec',
                ui: 'bdd'
            }));
});

gulp.task('default', ['lint', 'test']);

Add window and document to globals for tests


var gulp = require('gulp'),
    jsdoc = require('gulp-jsdoc'),
    ghPages = require('gulp-gh-pages'),
    docsSrcDir = './assets/js/**/*.js',
    docsDestDir = './docs/js',
    jsDocTask;

jsDocTask = function() {
  return gulp.src(docsSrcDir)
    .pipe(
      jsdoc(docsDestDir,
        {
          path: './node_modules/jaguarjs-jsdoc',
          applicationName: 'Dough JavaScript',
          cleverLinks: true,
          copyright: 'Copyright Money Advice Service ©',
          linenums: true,
          collapseSymbols: false
        },
        {
          plugins: ['plugins/markdown'],
        }
      )
    );
};

gulp.task('deploy', function() {
  return gulp.src(docsDestDir + '/**/*')
    .pipe(ghPages());
});

gulp.task('default', ['jsdoc']);

gulp.task('build', ['jsdoc', 'deploy']);

gulp.task('jsdoc', jsDocTask);

gulp.task('watch', function() {
  jsDocTask();
  gulp.watch(docsSrcDir, ['jsdoc']);
});

var gulp = require('gulp'),
    jsdoc = require('gulp-jsdoc'),
    ghPages = require('gulp-gh-pages'),
    docsSrcDir = './assets/js/**/*.js',
    docsDestDir = './docs/js',
    jsDocTask;

jsDocTask = function() {
  return gulp.src([docsSrcDir, './README.md'])
    .pipe(
      jsdoc(docsDestDir,
        {
          path: './node_modules/jaguarjs-jsdoc',
          applicationName: 'Dough JavaScript',
          cleverLinks: true,
          copyright: 'Copyright Money Advice Service ©',
          linenums: true,
          collapseSymbols: false
        },
        {
          plugins: ['plugins/markdown'],
        }
      )
    );
};

gulp.task('deploy', function() {
  return gulp.src(docsDestDir + '/**/*')
    .pipe(ghPages());
});

gulp.task('default', ['jsdoc']);

gulp.task('build', ['jsdoc', 'deploy']);

gulp.task('jsdoc', jsDocTask);

gulp.task('watch', function() {
  jsDocTask();
  gulp.watch(docsSrcDir, ['jsdoc']);
});

Use the Dough README on docs landing page


var gulp = require('gulp');

var files = ['index.js', 'test/*.js', 'gulpfile.js'];

gulp.task('lint', function (done) {
  var eslint = require('gulp-eslint');
  return gulp.src(files)
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError()).on('error', done);
});

gulp.task('test', function (done) {
  var mocha = require('gulp-mocha');
  return gulp.src('test/*.js', { read: false })
    .pipe(mocha()).on('error', done);
});

gulp.task('default', ['lint', 'test']);

gulp.task('watch', function() {
  gulp.watch(files, ['lint', 'test']);
});

var gulp = require('gulp');

var files = ['index.js', 'lib/*.js', 'test/*.js', 'gulpfile.js'];

gulp.task('lint', function (done) {
  var eslint = require('gulp-eslint');
  return gulp.src(files)
    .pipe(eslint())
    .pipe(eslint.format())
    .pipe(eslint.failAfterError()).on('error', done);
});

gulp.task('test', function (done) {
  var mocha = require('gulp-mocha');
  return gulp.src('test/*.js', { read: false })
    .pipe(mocha()).on('error', done);
});

gulp.task('default', ['lint', 'test']);

gulp.task('watch', function() {
  gulp.watch(files, ['lint', 'test']);
});

Split code into lib subfolder


var gulp= require('gulp')
var dts = require('dts-generator');

gulp.task('default', function(){
  dts  .generate({
    name: 'uservice',
    baseDir: './module',
    excludes: ['./typings/node/node.d.ts', './typings/typescript/lib.es6.d.ts'],
    files: [ './index.ts' ],
    out: './uservice.d.ts'
  });
})

var gulp= require('gulp')
var dts = require('dts-generator');

gulp.task('default', function(){
  dts  .generate({
    name: 'uservices',
    baseDir: './module',
    excludes: ['./typings/node/node.d.ts', './typings/typescript/lib.es6.d.ts'],
    files: [ './index.ts' ],
    out: './uservices.d.ts'
  });
})

Fix name to consistent uservices


'use strict';

var validate = require('./validate');
var ValidationError = require('../error/validation_error');

module.exports = function validateLayoutProperty(options) {
    var key = options.key;
    var style = options.style;
    var styleSpec = options.styleSpec;
    var value = options.value;
    var propertyKey = options.objectKey;
    var layerSpec = styleSpec['layout_' + options.layerType];

    if (options.valueSpec || layerSpec[propertyKey]) {
        var errors = [];

        if (options.layerType === 'symbol') {
            if (propertyKey === 'icon-image' && !style.sprite) {
                errors.push(new ValidationError(key, value, 'use of "icon-image" requires a style "sprite" property'));
            } else if (propertyKey === 'text-field' && !style.glyphs) {
                errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
            }
        }

        return errors.concat(validate({
            key: options.key,
            value: value,
            valueSpec: options.valueSpec || layerSpec[propertyKey],
            style: style,
            styleSpec: styleSpec
        }));

    } else {
        return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)];
    }

};

'use strict';

var validate = require('./validate');
var ValidationError = require('../error/validation_error');

module.exports = function validateLayoutProperty(options) {
    var key = options.key;
    var style = options.style;
    var styleSpec = options.styleSpec;
    var value = options.value;
    var propertyKey = options.objectKey;
    var layerSpec = styleSpec['layout_' + options.layerType];

    if (options.valueSpec || layerSpec[propertyKey]) {
        var errors = [];

        if (options.layerType === 'symbol') {
            if (propertyKey === 'icon-image' && style && !style.sprite) {
                errors.push(new ValidationError(key, value, 'use of "icon-image" requires a style "sprite" property'));
            } else if (propertyKey === 'text-field' && style && !style.glyphs) {
                errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
            }
        }

        return errors.concat(validate({
            key: options.key,
            value: value,
            valueSpec: options.valueSpec || layerSpec[propertyKey],
            style: style,
            styleSpec: styleSpec
        }));

    } else {
        return [new ValidationError(key, value, 'unknown property "%s"', propertyKey)];
    }

};

Fix exception caused by calling validateLayoutProperty without passing a style


/* eslint-env node */
'use strict'

const EmberApp = require('ember-cli/lib/broccoli/ember-app')
const cssnext = require('postcss-cssnext')

module.exports = function(defaults) {
  let app = new EmberApp(defaults, {
    postcssOptions: {
      compile: {
        enabled: false
      },
      filter: {
        enabled: true,
        plugins: [
          {
            module: cssnext,
            options: {
              browsers: [
                '> 1%',
                'last 3 versions',
                'Firefox ESR'
              ]
            }
          }
        ]
      }
    }
  })

  app.import('bower_components/xss/dist/xss.js')

  return app.toTree()
}

/* eslint-env node */
'use strict'

const EmberApp = require('ember-cli/lib/broccoli/ember-app')
const cssnext = require('postcss-cssnext')

module.exports = function(defaults) {
  let app = new EmberApp(defaults, {
    postcssOptions: {
      compile: {
        enabled: false
      },
      filter: {
        enabled: true,
        map: { inline: false },
        plugins: [
          {
            module: cssnext,
            options: {
              browsers: [
                '> 1%',
                'last 3 versions',
                'Firefox ESR'
              ]
            }
          }
        ]
      }
    }
  })

  app.import('bower_components/xss/dist/xss.js')

  return app.toTree()
}

Disable inline sourcemaps in postcss


"use strict";

const Task = require('../Task'),
    gulp = require('gulp'),
    path = require('path'),
    nodemon = require('gulp-nodemon'),
    ProjectType = require('../../ProjectType'),
    _ = require('lodash');

class NodeWatchBuildTask extends Task {

    constructor(buildManager, taskRunner) {
        super(buildManager, taskRunner);
        this.command = "watch-build";
        this.availableTo = [ProjectType.NODEJS];
    }

    action() {
        return nodemon(_.merge({
            script: 'bootstrapper.' + (this._buildManager.options.typescript ? "ts" : "js"),
            ext: 'js json ts',
            execMap: {
                "ts": path.resolve(__dirname, "../../../node_modules/ts-node/dist/bin/ts-node.js")
            }
        }, this._buildManager.options.nodemon));
    }
}

module.exports = NodeWatchBuildTask;

"use strict";

const Task = require('../Task'),
    gulp = require('gulp'),
    path = require('path'),
    ProjectType = require('../../ProjectType'),
    _ = require('lodash');

class NodeWatchBuildTask extends Task {

    constructor(buildManager, taskRunner) {
        super(buildManager, taskRunner);
        this.command = "watch-build";
        this.availableTo = [ProjectType.NODEJS];
    }

    action() {
        return require('gulp-nodemon')(_.merge({
            script: 'bootstrapper.' + (this._buildManager.options.typescript ? "ts" : "js"),
            ext: 'js json ts',
            execMap: {
                "ts": path.resolve(__dirname, "../../../node_modules/ts-node/dist/bin/ts-node.js")
            }
        }, this._buildManager.options.nodemon));
    }
}

module.exports = NodeWatchBuildTask;

Fix double ctr+c when exiting watch-build


/*jslint devel: true, browser: true, indent: 2, nomen: true */
/*global define */

define([], function () {
  'use strict';

  console.log('it works');
});

/*jslint devel: true, browser: true, indent: 2, nomen: true */
/*global define */

define([], function () {
  'use strict';

  // console.log('it works');
});

Comment out annoying debug code.


// Store the preference locale in cookies and (if available) session to use
// on next requests.

'use strict';

var _ = require('lodash');

var LOCALE_COOKIE_MAX_AGE = 0xFFFFFFFF; // Maximum 32-bit unsigned integer.

module.exports = function (N, apiPath) {
  N.validate(apiPath, {
    locale: { type: 'string' }
  });

  N.wire.on(apiPath, function set_language(env, callback) {
    var locale = env.params.locale;

    if (!_.contains(N.config.locales.enabled, env.params.locale)) {
      // User sent a non-existent or disabled locale - reply with the default.
      locale = N.config.locales['default'];
    }

    env.extras.setCookie('locale', locale, {
      path: '/'
    , maxAge: LOCALE_COOKIE_MAX_AGE
    });

    if (env.session) {
      env.session.locale = locale;
    }

    if (env.session && env.session.user_id) {
      N.models.users.User.findByIdAndUpdate(env.session.user_id, { locale: locale }, callback);
    } else {
      callback();
    }
  });
};

// Store the preference locale in cookies and (if available) session to use
// on next requests.

'use strict';

var _ = require('lodash');

var LOCALE_COOKIE_MAX_AGE = 0xFFFFFFFF; // Maximum 32-bit unsigned integer.

module.exports = function (N, apiPath) {
  N.validate(apiPath, {
    locale: { type: 'string' }
  });

  N.wire.on(apiPath, function set_language(env, callback) {
    var locale = env.params.locale;

    if (!_.contains(N.config.locales.enabled, env.params.locale)) {
      // User sent a non-existent or disabled locale - reply with the default.
      locale = N.config.locales['default'];
    }

    env.extras.setCookie('locale', locale, {
      path: '/'
    , maxAge: LOCALE_COOKIE_MAX_AGE
    });

    if (env.session) {
      env.session.locale = locale;
    }

    if (env.session && env.session.user_id) {
      N.models.users.User.update({ _id: env.session.user_id }, { locale: locale }, callback);
    } else {
      callback();
    }
  });
};

Update user locale without fetching user's account.


var	name    = require('./package.json').moduleName,
    fs      = require('fs'),
    gulp    = require('gulp'),
    plugins = require('gulp-load-plugins')()

var head = fs.readFileSync('./node_modules/@electerious/modulizer/head.js', { encoding: 'utf8' }),
    foot = fs.readFileSync('./node_modules/@electerious/modulizer/foot.js', { encoding: 'utf8' })

var catchError = function(err) {

	console.log(err.toString())
	this.emit('end')

}

gulp.task('scripts', function() {

	gulp.src('./src/scripts/*.js')
	    .pipe(plugins.header(head, { name: name }))
	    .pipe(plugins.footer(foot))
	    .pipe(plugins.babel())
	    .pipe(plugins.concat(name + '.min.js', { newLine: "\n" }))
	    .pipe(plugins.uglify())
	    .on('error', catchError)
	    .pipe(gulp.dest('./dist'))

})

gulp.task('default', ['scripts'])

gulp.task('watch', ['scripts'], function() {

	gulp.watch('./src/scripts/*.js', ['scripts'])

})

var	name    = require('./package.json').moduleName,
    fs      = require('fs'),
    gulp    = require('gulp'),
    plugins = require('gulp-load-plugins')()

var head = fs.readFileSync('./node_modules/@electerious/modulizer/head.js', { encoding: 'utf8' }),
    foot = fs.readFileSync('./node_modules/@electerious/modulizer/foot.js', { encoding: 'utf8' })

var catchError = function(err) {

	console.log(err.toString())
	this.emit('end')

}

gulp.task('scripts', function() {

	gulp.src('./src/scripts/*.js')
	    .pipe(plugins.header(head, { name: name }))
	    .pipe(plugins.footer(foot))
	    .pipe(plugins.babel())
	    .pipe(plugins.concat(name + '.min.js', { newLine: "\n" }))
	    .pipe(plugins.uglify())
	    .on('error', catchError)
	    .pipe(gulp.dest('./dist'))

})

gulp.task('default', ['scripts'])

gulp.task('watch', ['scripts'], function() {

	gulp.watch('./src/scripts/**/*.js', ['scripts'])

})

Include sub-folders when watching for changes


var gulp = require('gulp');
var mocha = require('gulp-mocha');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
require('coffee-script/register');

gulp.task('test', function(){
  return gulp.src('./test/**/*.coffee')
             .pipe(mocha());
});

gulp.task('bundle', function(done) {
  gulp.src('./src/**/*.coffee')
    .pipe(coffee({bare: true}))
    .pipe(gulp.dest('lib'));
  done();
});

gulp.task('watch', function() {
  gulp.watch([ '**/*.coffee' ], [ 'bundle', 'test' ]);
});

gulp.task('default', ['watch']);

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
require('coffee-script/register');

gulp.task('test', ['bundle'], function(){
  return gulp.src('./test/**/*.coffee')
             .pipe(mocha());
});

gulp.task('bundle', function() {
  return gulp.src('./src/**/*.coffee')
    .pipe(coffee({bare: true}))
    .pipe(gulp.dest('lib'));
});

gulp.task('watch', function() {
  gulp.watch([ '**/*.coffee' ], [ 'bundle', 'test' ]);
});

gulp.task('default', ['watch']);

Set 'bundle' as a dependency to 'test'


const async = require('./async')

module.exports = function(providers, cb) {

  function setup(values) {
    const currentValues = results.reduce(( pre, cur ) => Object.assign(pre, cur), {})

    cb(null,
      {
        get: key => currentValues[key],
        getDynamic: key => () => currentValues[key],
        all: currentValues
      }
    )
  }

  async.merge(providers.map(provider => (cb) => provider.read(cb)), results => {
    const errors = result.filter(r => r.err !== undefined)

    if(errors.length > 0) {
      cb(errors[0])
    } else {
      setup(results.map(r => r.res))
    }
  })
}

const async = require('./async')

module.exports = function(providers, cb) {

  function setup(values) {
    const currentValues = results.reduce(( pre, cur ) => Object.assign(pre, cur), {})

    cb(null,
      {
        get: key => currentValues[key],
        getDynamic: key => () => currentValues[key],
        all: currentValues
      }
    )
  }

  async.merge(providers.map(provider => provider.read), results => {
    const errors = result.filter(r => r.err !== undefined)

    if(errors.length > 0) {
      cb(errors[0])
    } else {
      setup(results.map(r => r.res))
    }
  })
}

Simplify passing read to merge call


var MacaroonAuthUtils       = require("../utils/macaroon_auth.js");

module.exports = function(options) {
    return function getMacaroonUserSecret(req, res, next) {
        if(typeof options.collection !== "undefined" && options.collection !== ""){
            var userId = "";
            if(req.method == "GET" || req.method == "DELETE"){
                userId = req.query.userId;
            }
            else{
                userId = req.body.userId;
            }

            if(typeof userId !== "undefined" && userId !== ""){
                var collection = req.db.collection(options.collection);
                collection.findOne({userId: userId})
                    .then(function(user){
                        if(user !== null){
                            console.log("Setting macaroonUserSecret for user: " + user.userId);
                            var macaroonSecret = MacaroonAuthUtils.calculateMacaroonSecret(user.macaroonSecret);
                            req.macaroonSecret = macaroonSecret;
                        }
                        else{
                            console.log("Setting macaroonUserSecret to null for user");
                            req.macaroonUserSecret = null;
                        }
                        next();
                    }).catch(function (error) {
                        console.log("Promise rejected:");
                        console.log(error);
                        res.sendStatus("401");
                    });
            }
            else{
                console.log("userId not found. Setting macaroonUserSecret to null: " + userId);
                req.macaroonUserSecret = null;
                next();
            }
        }
        else{
            var error = new Error("Error configuring getMacaroonUserSecret")
            console.log(error);
            res.sendStatus("401");
        }
    };
};

var mAuthMint   = require("mauth").mAuthMint;

module.exports = function(options) {
    return function getMacaroonUserSecret(req, res, next) {
        if(typeof options.collection !== "undefined" && options.collection !== ""){
            var userId = "";
            if(req.method == "GET" || req.method == "DELETE"){
                userId = req.query.userId;
            }
            else{
                userId = req.body.userId;
            }

            if(typeof userId !== "undefined" && userId !== ""){
                var collection = req.db.collection(options.collection);
                collection.findOne({userId: userId})
                    .then(function(user){
                        if(user !== null){
                            console.log("Setting macaroonUserSecret for user: " + user.userId);
                            var macaroonSecret = mAuthMint.calculateMacaroonSecret(user.macaroonSecret);
                            req.macaroonSecret = macaroonSecret;
                        }
                        else{
                            console.log("Setting macaroonUserSecret to null for user");
                            req.macaroonUserSecret = null;
                        }
                        next();
                    }).catch(function (error) {
                        console.log("Promise rejected:");
                        console.log(error);
                        res.sendStatus("401");
                    });
            }
            else{
                console.log("userId not found. Setting macaroonUserSecret to null: " + userId);
                req.macaroonUserSecret = null;
                next();
            }
        }
        else{
            var error = new Error("Error configuring getMacaroonUserSecret")
            console.log(error);
            res.sendStatus("401");
        }
    };
};

Fix require to use new mauth package


const CleanWebpackPlugin = require("clean-webpack-plugin")
const path = require("path")
const webpack = require("webpack")

const dist = path.join(process.cwd(), "public")
const src = path.join(process.cwd(), "src")

//module.exports = { dist, src }
module.exports = {
  entry: [path.join(src, "index.js")],
  module: {
    rules: [
      {
        test: /\.(graphql|gql)?$/,
        use: "raw-loader"
      },
      {
        exclude: /node_modules/,
        test: /\.js?$/,
        use: [
          {
            loader: "babel-loader"
          }
        ]
      },
      {
        test: /\.y(a?)ml$/,
        use: ["json-loader", "yaml-loader"]
      }
    ]
  },
  node: {
    __filename: true,
    __dirname: true
  },
  output: { path: dist, filename: "server.js" },
  plugins: [
		new CleanWebpackPlugin(dist),
		new webpack.IgnorePlugin(/vertx/),
    new webpack.NamedModulesPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  target: "node"
}

const CleanWebpackPlugin = require("clean-webpack-plugin")
const path = require("path")
const webpack = require("webpack")

const dist = path.join(process.cwd(), "public")
const src = path.join(process.cwd(), "src")

//module.exports = { dist, src }
module.exports = {
  entry: [path.join(src, "index.js")],
  module: {
    rules: [
      {
        test: /\.(graphql|gql)?$/,
        use: "raw-loader"
      },
      {
        exclude: /node_modules/,
        test: /\.js?$/,
        use: [
          {
            loader: "babel-loader"
          }
        ]
      },
      {
        test: /\.y(a?)ml$/,
        use: ["json-loader", "yaml-loader"]
      }
    ]
  },
  node: {
    __filename: true,
    __dirname: true
  },
  output: { path: dist, filename: "server.js" },
  plugins: [
    new CleanWebpackPlugin(dist, {
      root: process.cwd()
    }),
    new webpack.IgnorePlugin(/vertx/),
    new webpack.NamedModulesPlugin(),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  target: "node"
}

Change project root variable in clean plugin


"use strict"

var _ = require('underscore'),
  fs = require('fs'),
  sys = require('sys'),
  exec = require('child_process').exec,
  program = require('commander');

var path = require('path'),
  fs = require('fs'),
  lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib');

// CLI
program.version('0.0.1')
  .parse(process.argv);

// Exec new Gruntfile
var execGrunt = function () {
  var pintConfig = require(path.join(process.cwd(), 'Pint.js'));
  var gruntfileTemplate = fs.readFileSync(path.join(lib, 'templates/Gruntfile.tmpl'), 'utf8');

  // Stringify config but remove open and closing braces
  var config=JSON.stringify(pintConfig.build.config);
  config = config.substring(1, config.length - 1)

  fs.writeFileSync("./Gruntfile.js", _.template(gruntfileTemplate)({
    gruntTasks : config
  }))

  exec("grunt", function(err, stdout) {
    sys.puts(stdout.trim());

    exec("rm -rf Gruntfile.js", function(err, stdout) {
      sys.puts(stdout.trim());
    });
  });
};

exports.drink = execGrunt;

"use strict"

var _ = require('underscore'),
  fs = require('fs'),
  sys = require('sys'),
  exec = require('child_process').exec,
  program = require('commander'),
  path = require('path');

var pintPath = path.join(__dirname, '..'),
  targetPath = process.cwd()

// CLI
program.version('0.0.1')
  .parse(process.argv);

// Exec new Gruntfile
var execGrunt = function () {
  var pintConfig = require(path.join(process.cwd(), 'Pint.js'));
  var gruntfileTemplate = fs.readFileSync(path.join(pintPath, 'lib/templates/Gruntfile.tmpl'), 'utf8');

  // Stringify config but remove open and closing braces
  var config=JSON.stringify(pintConfig.build.config);
  config = config.substring(1, config.length - 1)

  fs.writeFileSync(path.join(targetPath, "Pintfile.js"), _.template(gruntfileTemplate)({
    gruntTasks : config
  }))

  exec("grunt --gruntfile Pintfile.js", function(err, stdout) {
    sys.puts(stdout.trim());

    exec("rm -rf Pintfile.js", function(err, stdout) {
      sys.puts(stdout.trim());
    });
  });
};

exports.drink = execGrunt;

Change files to be Pintfiles so as not to conflict with Grunt


// SwellRT bootstrap script

// A fake SwellRT object to register on ready handlers
// before the GWT module is loaded

window.swellrt = {

  onReady: function(handler) {
       if (!handler || typeof handler !== "function")
         return;

       if (!window._lh)
    	   window._lh = [];

       window._lh.push(handler);
      }
}

var scripts = document.getElementsByTagName('script');
var thisScript = scripts[scripts.length -1];

if (thisScript) {
  var p = document.createElement('a');
  p.href = thisScript.src;

  // Polyfill for ES6 proxy/reflect
  if (!window.Proxy || !window.Reflect) {
    var reflectSrc = p.protocol + "//" +p.host  + "/reflect.js";
    document.write("<script src='"+reflectSrc+"'></script>");
  }

  var scriptSrc = p.protocol + "//" +p.host  + "/swellrt_beta/swellrt_beta.nocache.js";
  document.write("<script src='"+scriptSrc+"'></script>");
}

// SwellRT bootstrap script

// A fake SwellRT object to register on ready handlers
// before the GWT module is loaded
window.swellrt = {

  onReady: function(handler) {
       if (!handler || typeof handler !== "function")
         return;

       if (window.swellrt.runtime) {
          handler.apply(window, window.swellrt.runtime.get());
       } else {
          if (!window._lh)
            window._lh = [];
          window._lh.push(handler);
       }
    }
}

var scripts = document.getElementsByTagName('script');
var thisScript = scripts[scripts.length -1];

if (thisScript) {
  var p = document.createElement('a');
  p.href = thisScript.src;

  // Polyfill for ES6 proxy/reflect
  if (!window.Proxy || !window.Reflect) {
    try {
      var reflectSrc = p.protocol + "//" +p.host  + "/reflect.js";
      document.write("<script src='"+reflectSrc+"'></script>");
    } catch (e) {
      console.log("No proxies supported: "+e);
    }
  }

  var scriptSrc = p.protocol + "//" +p.host  + "/swellrt_beta/swellrt_beta.nocache.js";
  document.write("<script src='"+scriptSrc+"'></script>");
} else {
  console.log("Unable to inject swellrt script!");
}

Fix code launching onReady() handlers


var path   = require('path');
var util   = require('util');
var yeoman = require('yeoman-generator');

module.exports = TestGenerator;

// TestGenerator stubs out a very basic test suite during the generation
// process of a new generator.
//
// XXX:
//  - consider adding _.string API to generators prototype

function TestGenerator() {
  yeoman.generators.NamedBase.apply(this, arguments);

  // dasherize the thing
  this.filename = this.dasherize(this.name).replace(/:/, '-');

  this.argument('files', {
    type: Array,
    banner: 'app/file/to/test.js test/something.js ...'
  });

  this.option('internal', {
    desc: 'Enable this flag when generating from yeoman-generators repo'
  });

  this.option('prefix', {
    desc: 'Specify an alternate base directory',
    defaults: 'test/generators/'
  });

  this.pkg = this.options.internal ? '../..' : 'yeoman-generators';
}

util.inherits(TestGenerator, yeoman.generators.NamedBase);

TestGenerator.prototype.createTestSuite = function() {
  this.template('test.js', path.join(this.options.prefix, 'test-' + this.filename + '.js'));
};

var path   = require('path');
var util   = require('util');
var yeoman = require('yeoman-generator');

module.exports = TestGenerator;

// TestGenerator stubs out a very basic test suite during the generation
// process of a new generator.
//
// XXX:
//  - consider adding _.string API to generators prototype

function TestGenerator() {
  yeoman.generators.NamedBase.apply(this, arguments);

  // dasherize the thing
  this.filename = this._.dasherize(this.name).replace(/:/, '-');

  this.argument('files', {
    type: Array,
    banner: 'app/file/to/test.js test/something.js ...'
  });

  this.option('internal', {
    desc: 'Enable this flag when generating from yeoman-generators repo'
  });

  this.option('prefix', {
    desc: 'Specify an alternate base directory',
    defaults: 'test/generators/'
  });

  this.pkg = this.options.internal ? '../..' : 'yeoman-generators';
}

util.inherits(TestGenerator, yeoman.generators.NamedBase);

TestGenerator.prototype.createTestSuite = function() {
  this.template('test.js', path.join(this.options.prefix, 'test-' + this.filename + '.js'));
};

Update dasherized name to use this._


const _ = require('lodash/fp')
const axios = require('axios')

const BN = require('../../../bn')

function getBuyPrice (obj) {
  const currencyPair = obj.currencyPair

  return axios({
    method: 'get',
    url: `https://api.coinbase.com/v2/prices/${currencyPair}/buy`,
    headers: {'CB-Version': '2017-07-10'}
  })
    .then(r => r.data)
}

function getSellPrice (obj) {
  const currencyPair = obj.currencyPair

  return axios({
    method: 'get',
    url: `https://api.coinbase.com/v2/prices/${currencyPair}/sell`,
    headers: {'CB-Version': '2017-07-10'}
  })
    .then(r => r.data)
}

function ticker (account, fiatCode, cryptoCode) {
  return Promise.resolve()
    .then(() => {
      if (!_.includes(cryptoCode, ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC'])) {
        throw new Error('Unsupported crypto: ' + cryptoCode)
      }
    })
    .then(() => {
      const currencyPair = `${cryptoCode}-${fiatCode}`
      const promises = [
        getBuyPrice({currencyPair}),
        getSellPrice({currencyPair})
      ]

      return Promise.all(promises)
    })
    .then(([buyPrice, sellPrice]) => ({
      rates: {
        ask: BN(buyPrice.data.amount),
        bid: BN(sellPrice.data.amount)
      }
    }))
}

module.exports = {
  ticker
}

const _ = require('lodash/fp')
const axios = require('axios')

const BN = require('../../../bn')

function getBuyPrice (obj) {
  const currencyPair = obj.currencyPair

  return axios({
    method: 'get',
    url: `https://api.coinbase.com/v2/prices/${currencyPair}/buy`,
    headers: {'CB-Version': '2017-07-10'}
  })
    .then(r => r.data)
}

function getSellPrice (obj) {
  const currencyPair = obj.currencyPair

  return axios({
    method: 'get',
    url: `https://api.coinbase.com/v2/prices/${currencyPair}/sell`,
    headers: {'CB-Version': '2017-07-10'}
  })
    .then(r => r.data)
}

function ticker (account, fiatCode, cryptoCode) {
  return Promise.resolve()
    .then(() => {
      if (!_.includes(cryptoCode, ['BTC', 'ETH', 'LTC', 'BCH', 'ZEC', 'DASH'])) {
        throw new Error('Unsupported crypto: ' + cryptoCode)
      }
    })
    .then(() => {
      const currencyPair = `${cryptoCode}-${fiatCode}`
      const promises = [
        getBuyPrice({currencyPair}),
        getSellPrice({currencyPair})
      ]

      return Promise.all(promises)
    })
    .then(([buyPrice, sellPrice]) => ({
      rates: {
        ask: BN(buyPrice.data.amount),
        bid: BN(sellPrice.data.amount)
      }
    }))
}

module.exports = {
  ticker
}

Add DASH to Coinbase ticker


const assert = require('assert')
const deprecations = require('electron').deprecations

describe('deprecations', function () {
  beforeEach(function () {
    deprecations.setHandler(null)
    process.throwDeprecation = true
  })

  it('allows a deprecation handler function to be specified', function () {
    var messages = []

    deprecations.setHandler(function (message) {
      messages.push(message)
    })

    require('electron').webFrame.registerUrlSchemeAsSecure('some-scheme')

    assert.deepEqual(messages, ['registerUrlSchemeAsSecure is deprecated. Use registerURLSchemeAsSecure instead.'])
  })

  it('throws an exception if no deprecation handler is specified', function () {
    assert.throws(function () {
      require('electron').webFrame.registerUrlSchemeAsPrivileged('some-scheme')
    }, 'registerUrlSchemeAsPrivileged is deprecated. Use registerURLSchemeAsPrivileged instead.')
  })
})

const assert = require('assert')
const deprecations = require('electron').deprecations

describe('deprecations', function () {
  beforeEach(function () {
    deprecations.setHandler(null)
    process.throwDeprecation = true
  })

  it('allows a deprecation handler function to be specified', function () {
    var messages = []

    deprecations.setHandler(function (message) {
      messages.push(message)
    })

    require('electron').deprecate.log('this is deprecated')

    assert.deepEqual(messages, ['this is deprecated'])
  })

  it('throws an exception if no deprecation handler is specified', function () {
    assert.throws(function () {
      require('electron').webFrame.registerUrlSchemeAsPrivileged('some-scheme')
    }, 'registerUrlSchemeAsPrivileged is deprecated. Use registerURLSchemeAsPrivileged instead.')
  })
})

Add explicit call to deprecate.log


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

var userResponder = new cote.Responder({
    name: 'user responder',
    namespace: 'user',
    respondsTo: ['create']
});

var userPublisher = new cote.Publisher({
    name: 'user publisher',
    namespace: 'user',
    broadcasts: ['update']
});

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

userResponder.on('create', function(req, cb) {
    models.User.create({}, cb);

    updateUsers();
});

userResponder.on('list', function(req, cb) {
    var query = req.query || {};
    models.User.find(query, cb);
});

function updateUsers() {
    models.User.find(function(err, users) {
        userPublisher.publish('update', users);
    });
}

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

var userResponder = new cote.Responder({
    name: 'user responder',
    namespace: 'user',
    respondsTo: ['create']
});

var userPublisher = new cote.Publisher({
    name: 'user publisher',
    namespace: 'user',
    broadcasts: ['update']
});

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

userResponder.on('create', function(req, cb) {
    models.User.create({}, cb);

    updateUsers();
});

userResponder.on('list', function(req, cb) {
    var query = req.query || {};
    models.User.find(query, cb);
});

userResponder.on('get', function(req, cb) {
    models.User.get(req.id, cb);
});

function updateUsers() {
    models.User.find(function(err, users) {
        userPublisher.publish('update', users);
    });
}

Add get API to user service


export const INTRODUCTION = '1. Introduction';
export const PRIMITIVES = '2. Primitives';
export const FOUNDATION = '3. Foundation';
export const LOW_LEVEL_BLOCKS = '4. Low level blocks';
export const MID_LEVEL_BLOCKS = '5. Mid level blocks';
export const COMPOSITIONS = '6. Compositions';
export const PLAYGROUND = '7. Playground';

export const addStoryInGroup = (groupTitle, storyTitle) => `${groupTitle} / ${storyTitle}`;

Add function to compose the story title based on group name


import React from 'react'
import { Router, Route, browserHistory } from 'react-router'

// views.
import Layout from './views/Layout'
import Home from './views/Home'
import About from './views/About'

const Routes = () => {
  return (
    <Router history={browserHistory}>
      <Route component={Layout}>
        <Route name='home' path='/' component={Home} />
        <Route name='about' path='/about' component={About} />
      </Route>
    </Router>
  )
}

export default Routes

import React from 'react'
import { Router, Route, browserHistory } from 'react-router'

import Layout from './views/Layout'

import Home from './views/Home'
import About from './views/About'

const Routes = () => {
  return (
    <Router history={browserHistory}>
      <Route component={Layout}>
        <Route name='home' path='/' component={Home} />
        <Route name='about' path='/about' component={About} />
      </Route>
    </Router>
  )
}

export default Routes

Remove the unnecessary comment from the store.js file.


const {resolve} = require('path');
const webpack =require('webpack');

module.exports = {
    entry: [
        './index.tsx'
    ],
    output:{
        filename: 'bundle.js',
        path: resolve(__dirname, 'static'),
        publicPath: ''
    },
    resolve:{
        extensions: ['js', '.jsx', '.ts', '.tsx', '.css']
    },
    context: resolve(__dirname, 'src'),
    devtool: 'inline-source-map',
    devServer:{
        hot: true,
        contentBase: resolve(__dirname, 'static'),
        publicPath: ''
    },
    module: {
        rules:[{
                test: /\.(ts|tsx)$/,
                use: ['awesome-typescript-loader']
            },{
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins: []
}

const {resolve} = require('path');
const webpack =require('webpack');

module.exports = {
    entry: [
        './index.tsx'
    ],
    output:{
        filename: 'bundle.js',
        path: resolve(__dirname, 'static'),
        publicPath: ''
    },
    resolve:{
        extensions: ['.js', '.jsx', '.ts', '.tsx', '.css']
    },
    context: resolve(__dirname, 'src'),
    devtool: 'inline-source-map',
    devServer:{
        hot: true,
        contentBase: resolve(__dirname, 'static'),
        publicPath: ''
    },
    module: {
        rules:[{
                test: /\.(ts|tsx)$/,
                use: ['awesome-typescript-loader']
            },{
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins: []
};

Fix typo for js file.


(function() {
    var element = null;
    var nav_elements = document.querySelectorAll('li.nav-item-container');

    for (var i = 0; i < nav_elements.length; i++) {
        var current = nav_elements[i];
        if (current.innerHTML == 'My Library') {
            element = current;
            break;
        }
    }

    if (element != null) {
        chrome.storage.sync.get({'gpmDefaultLibraryView': 'albums'}, function(item) {
            element.setAttribute('data-type', item.gpmDefaultLibraryView);
        });
    } else {
        console.log('No element found; did Google change the page?');
    }
})();

(function() {
    var element = null;
    var nav_elements = document.querySelectorAll('.nav-item-container');

    for (var i = 0; i < nav_elements.length; i++) {
        var current = nav_elements[i];
        if (current.innerHTML == 'My Library') {
            element = current;
            break;
        }
    }

    if (element != null) {
        chrome.storage.sync.get({'gpmDefaultLibraryView': 'albums'}, function(item) {
            element.setAttribute('data-type', item.gpmDefaultLibraryView);
        });
    } else {
        console.log('No element found; did Google change the page?');
    }
})();

Fix selector after Google change


#! /usr/bin/env node
var yargs = require("yargs");

console.log(yargs.parse(process.argv.slice(2)));

//var argv = require("yargs").argv;
//process.argv.slice(2).forEach(function (val, index, array) {
//  console.log(index + ': ' + val);
//});

// function readStdIn(callback) {
//     var called = false, data = "", finish = function (content) {
//         if (!called) {
//             process.stdin.pause();
//             callback(content);
//             called = true;
//         }
//     };
//     process.stdin.on("error", function () {
//         finish();
//     });
//     process.stdin.on("end", function () {
//         //finish(data);
//     });
//     process.stdin.on("readable", function () {
//         var chunk = this.read();
//         if (chunk === null) {
//             finish(data);
//         } else {
//            data += chunk;
//         }
//     });
// }
//
// readStdIn(function (fromStdIn) {
//     console.log(fromStdIn);
//     console.log(fromStdIn.length);
//     //console.log(argv);
// });

#! /usr/bin/env node

var App = require("../lib/app").App;

var app = new App();
app.run();

Clean up CLI entry point script.


var URL   = require('url')
  , redis = require('redis');

module.exports = function (config) {
  var client, url, port, host, db, pass;

  if (config = config || {}) {
    try {

      url     = URL.parse(config && config.url || process.env.REDIS_PORT || 'redis://localhost:6379');
      port    = url.port;
      host    = url.hostname;
      db      = config.db;
      auth    = config && config.auth;

      options = {
        no_ready_check: true
      }

      client = redis.createClient(port, host, options);

      if (auth) {
        client.auth(auth, function () {});
      }

      if (db) {
        client.select(db);
      }

    } catch (e) {
      throw new Error(e);
    }
  }

  return module.exports = client;
};

var URL   = require('url')
  , redis = require('redis');

module.exports = function (config) {
  var client, url, port, host, db, auth, options;

  if (config = config || {}) {
    try {

      url     = URL.parse(config && config.url || process.env.REDIS_PORT || 'redis://localhost:6379');
      port    = url.port;
      host    = url.hostname;
      db      = config.db;
      auth    = config && config.auth;

      options = {
        no_ready_check: true
      };

      client = redis.createClient(port, host, options);

      if (auth) {
        client.auth(auth, function () {});
      }

      if (db) {
        client.select(db);
      }

    } catch (e) {
      throw new Error(e);
    }
  }

  return module.exports = client;
};

Define variables that are used but not defined


var ItemEditController = Em.ObjectController.extend({
  setComplete: function () {
    var complete = this.get('canonicalModel.complete');
    this.set('model.complete', complete);
  }.observes('canonicalModel.complete'),

  actions: {
    cancel: function () {
      this.get('model').destroy();
      this.transitionToRoute('items');
    },

    save: function () {
      var self = this,
          item = this.get('model');

      this.api.edit('items', item).then(function (data) {
        var id = Ember.get(data, 'id');

        self.store.load('items', data);
        self.send('refresh');

        self.transitionToRoute('item.index', self.store.find('items', id));
      }).catch(function () {
        alert('Sorry, something went wrong saving your edited item! Please try again later.');
      });
    },
  }
});

export default ItemEditController;

var ItemEditController = Em.ObjectController.extend({
  setComplete: function () {
    var model = this.get('model'),
        complete;

    // this observer fires even when this controller is not part of the active route.
    // this is because route controllers are singletons and persist.
    // since changing routes destroys the temp model we used for editing, we must
    // avoid accessing or mutating it until we know it's fresh (on entering the route).
    if (model.isDestroyed) {
      return;
    }

    complete = this.get('canonicalModel.complete');
    model.set('complete', complete);
  }.observes('canonicalModel.complete'),

  actions: {
    cancel: function () {
      this.get('model').destroy();
      this.transitionToRoute('items');
    },

    save: function () {
      var self = this,
          item = this.get('model');

      this.api.edit('items', item).then(function (data) {
        var id = Ember.get(data, 'id');

        self.store.load('items', data);
        self.send('refresh');

        self.transitionToRoute('item.index', self.store.find('items', id));
      }).catch(function () {
        alert('Sorry, something went wrong saving your edited item! Please try again later.');
      });
    },
  }
});

export default ItemEditController;

Fix ItemEditController observer accessing model when model was destroyed


var ItemEditController = Em.ObjectController.extend({
  complete: function (key, value) {
    if (arguments.length > 1) {
      return value;
    }

    return this.get('canonicalModel.complete');
  }.property('canonicalModel.complete'),

  actions: {
    cancel: function () {
      this.get('model').destroy();
      this.transitionToRoute('items');
    },

    save: function () {
      var self = this,
          item = this.get('model');

      this.api.edit('items', item).then(function (data) {
        var id = Ember.get(data, 'id');

        self.store.load('items', data);
        self.send('refresh');

        self.transitionToRoute('item.index', self.store.find('items', id));
      }).catch(function () {
        alert('Sorry, something went wrong saving your edited item! Please try again later.');
      });
    },
  }
});

export default ItemEditController;

var ItemEditController = Em.ObjectController.extend({
  setComplete: function () {
    var complete = this.get('canonicalModel.complete');
    this.set('model.complete', complete);
  }.observes('canonicalModel.complete'),

  actions: {
    cancel: function () {
      this.get('model').destroy();
      this.transitionToRoute('items');
    },

    save: function () {
      var self = this,
          item = this.get('model');

      this.api.edit('items', item).then(function (data) {
        var id = Ember.get(data, 'id');

        self.store.load('items', data);
        self.send('refresh');

        self.transitionToRoute('item.index', self.store.find('items', id));
      }).catch(function () {
        alert('Sorry, something went wrong saving your edited item! Please try again later.');
      });
    },
  }
});

export default ItemEditController;

Fix saving item `complete` field


(function() {
    'use strict';

    angular
        .module('app')
        .controller('LoginDialogController', ['$mdDialog', function($mdDialog) {
            var vm = this;

            vm.showDialog = showDialog;

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

            function showDialog(url) {
                $mdDialog.show({
                    controller: DialogController,
                    templateUrl: get_tatoeba_root_url() + '/users/login_dialog_template?redirect=' + url,
                    parent: angular.element(document.body),
                    clickOutsideToClose:true
                });
            }

            function DialogController($scope, $mdDialog) {
                $scope.close = function() {
                    $mdDialog.cancel();
                };
            }
        }]);
})();

(function() {
    'use strict';

    angular
        .module('app')
        .controller('LoginDialogController', ['$mdDialog', function($mdDialog) {
            var vm = this;

            vm.showDialog = showDialog;

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

            function showDialog(url) {
                $mdDialog.show({
                    controller: DialogController,
                    templateUrl: get_tatoeba_root_url() + '/users/login_dialog_template?redirect=' + url,
                    parent: angular.element(document.body),
                    clickOutsideToClose: true,
                    fullscreen: true
                });
            }

            function DialogController($scope, $mdDialog) {
                $scope.close = function() {
                    $mdDialog.cancel();
                };
            }
        }]);
})();

Make login dialog fullscreen on -xs and -sm breakpoints


'use strict';

const shell = require('shelljs');
const cmd = require('./cmd');

// Execute msbuild.exe with passed arguments
module.exports = function exec(args) {
    process.exit(shell.exec(cmd(args)).code);
}

'use strict';

const shell = require('shelljs');
const cmd = require('./cmd');

// Execute msbuild.exe with passed arguments
module.exports = function exec(args) {
    const result = shell.exec(cmd(args)).code;
    if (result !== 0) {
        console.log();
        console.log(`MSBuild failed. ERRORLEVEL '${result}'.'`)
        process.exit(result);
    }
    console.log('MSBuild successfully completed.');
}

Fix handling of MSBuild errors


var canihaz = require('canihaz'),
  fs = require('fs'),
  p = require('path');

/**
 * Install dependency modules that are not yet installed, and needed for executing the tasks.
 *
 * @param {Array} depNames: an array of dependency module names
 * @param {String} dir: application directory where node_modules dir is located
 * @param {Function} cb: standard cb(err, result) callback
 */
function install(depNames, dir, cb) {
  fs.readdir(p.join(dir, 'node_modules'), function(err, installed) {
    var uninstalled = [];
    depNames.forEach(function (depName) {
      if (installed.indexOf(depName) === -1) {
        uninstalled.push(depName);
      }
    });
    if (uninstalled.length > 0) {
      console.log('[deps] Installing modules: %s (might take a while)', uninstalled .join(', '));
      canihaz({ key: 'optDependencies' }).apply(this, depNames.concat(cb));
    } else {
      cb();
    }
  });
}

exports.install = install;

var canihaz = require('canihaz'),
  fs = require('fs'),
  p = require('path');

/**
 * Install dependency modules that are not yet installed, and needed for executing the tasks.
 *
 * @param {Array} depNames: an array of dependency module names
 * @param {String} dir: application directory where node_modules dir is located
 * @param {Function} cb: standard cb(err, result) callback
 */
function install(depNames, dir, cb) {
  fs.readdir(p.join(dir, 'node_modules'), function(err, installed) {
    var uninstalled = [];
    depNames.forEach(function (depName) {
      if (installed.indexOf(depName) === -1) {
        uninstalled.push(depName);
      }
    });
    if (uninstalled.length > 0) {
      console.log('[deps] Installing modules: %s (might take a while, once-off only)', uninstalled .join(', '));
      canihaz({ key: 'optDependencies' }).apply(this, depNames.concat(cb));
    } else {
      cb();
    }
  });
}

exports.install = install;

Add note that lazy-installed modules are once-off only.


var buffer = require("./buffer");

/**
 * @namespace Splat
 */
module.exports = {
  makeBuffer: buffer.makeBuffer,
  flipBufferHorizontally: buffer.flipBufferHorizontally,
  flipBufferVertically: buffer.flipBufferVertically,

  ads: require("./ads"),
  AStar: require("./astar"),
  BinaryHeap: require("./binary-heap"),
  Game: require("./game"),
  iap: require("./iap"),
  Input: require("./input"),
  leaderboards: require("./leaderboards"),
  math: require("./math"),
  openUrl: require("./openUrl"),
  NinePatch: require("./ninepatch"),
  Particles: require("./particles"),
  saveData: require("./save-data"),
  Scene: require("./scene"),

  components: {
    animation: require("./components/animation"),
    camera: require("./components/camera"),
    friction: require("./components/friction"),
    image: require("./components/image"),
    movement2d: require("./components/movement-2d"),
    playableArea: require("./components/playable-area"),
    playerController2d: require("./components/player-controller-2d"),
    position: require("./components/position"),
    size: require("./components/size"),
    timers: require("./components/timers"),
    velocity: require("./components/velocity")
  }
};

var buffer = require("./buffer");

/**
 * @namespace Splat
 */
module.exports = {
  makeBuffer: buffer.makeBuffer,
  flipBufferHorizontally: buffer.flipBufferHorizontally,
  flipBufferVertically: buffer.flipBufferVertically,

  ads: require("./ads"),
  AStar: require("./astar"),
  BinaryHeap: require("./binary-heap"),
  Game: require("./game"),
  iap: require("./iap"),
  Input: require("./input"),
  leaderboards: require("./leaderboards"),
  math: require("./math"),
  openUrl: require("./openUrl"),
  NinePatch: require("./ninepatch"),
  Particles: require("./particles"),
  saveData: require("./save-data"),
  Scene: require("./scene")
};

Remove big export of components


import React from 'react';

const Root = (props) => {
  return (
    <div>{props.children}</div>
  );
};

Root.displayName = 'Root';

export default Root;

import React, { Children } from 'react';

const Root = ({ children }) => Children.only(children);

Root.displayName = 'Root';
export default Root;

Remove <div/> from Root and add Children.only