const CleanCSS = require("clean-css");
const sass = require("sass");
const through = require("through2");

// Minimal wrapper plugin around CleanCss
module.exports.minify = (options) => {
    return through.obj((file, enc, callback) => {
        const content = file.contents.toString() || "";
        new CleanCSS(options).minify(content, (errors, css) => {
            if (errors) {
                return callback(errors.join(" "));
            }
            file.contents = new Buffer.from(css.styles);
            return callback(null, file);
        });
    });
};

// Compile SASS files to CSS
module.exports.compile = (options) => {
    return through.obj((file, enc, callback) => {
        const renderOptions = {
            ...options,
            data: file.contents.toString() || "",
        };
        return sass.render(renderOptions, (error, result) => {
            if (error) {
                return callback(error.message);
            }
            file.contents = result.css;
            return callback(null, file);
        });
    });
};

const CleanCSS = require("clean-css");
const sass = require("sass");
const through = require("through2");

// Minimal wrapper plugin around CleanCss
module.exports.minify = options => {
    return through.obj((file, enc, callback) => {
        const content = file.contents.toString() || "";
        new CleanCSS(options).minify(content, (errors, css) => {
            if (errors) {
                return callback(errors.join(" "));
            }
            file.contents = new Buffer.from(css.styles);
            return callback(null, file);
        });
    });
};

// Compile SASS files to CSS
module.exports.compile = options => {
    return through.obj((file, enc, callback) => {
        const data = file.contents.toString() || "";
        const result = sass.compileString(data, options || {});
        // Update file content and continue
        // TODO: check error compiling the SASS file
        file.contents = new Buffer.from(result.css);
        return callback(null, file);
    });
};

Migrate to new sass.compile function


"use strict";

var fs = require("fs"),
    main = require("./main"),
    config = require("./config");

function evaluate(params) {
    var cmd = params.command || "",
        filename = params.filename || "",
        entrypoint = params.entrypoint || "",
        host = params.host || "127.0.0.1",
        path = params.path,
        options = params;

    if (!cmd && !filename && !entrypoint) {
        throw new Error("command or filename or entrypoint need to be filled.");
    }

    if (cmd && filename) {
        throw new Error("command and filename are exclusive.");
    }

    if (host && path) {
        throw new Error("host and path are exclusive.");
    }

    if (filename) {
        cmd = fs.readFileSync(filename, "utf8");
        cmd = cmd.replace(/(\r\n)/g, "\n");
    }

    if (entrypoint) {
        cmd += "\n" + entrypoint + "(";
        if (params.data) {
            cmd += "'" + JSON.stringify(params.data) + "')";
        } else {
            cmd += ")";
        }
    }

    main.sendAction(cmd, config.CMD_TYPE.EVAL,
        "Sending command to Rserve", options);
}
exports.evaluate = evaluate;

"use strict";

var fs = require("fs"),
    main = require("./main"),
    config = require("./config");

function evaluate(params) {
    var cmd = params.command || "",
        filename = params.filename || "",
        entrypoint = params.entrypoint || "",
        options = params;

    if (!cmd && !filename && !entrypoint) {
        throw new Error("command or filename or entrypoint need to be filled.");
    }

    if (cmd && filename) {
        throw new Error("command and filename are exclusive.");
    }

    if (params.host && params.path) {
        throw new Error("host and path are exclusive.");
    }

    if (filename) {
        cmd = fs.readFileSync(filename, "utf8");
        cmd = cmd.replace(/(\r\n)/g, "\n");
    }

    if (entrypoint) {
        cmd += "\n" + entrypoint + "(";
        if (params.data) {
            cmd += "'" + JSON.stringify(params.data) + "')";
        } else {
            cmd += ")";
        }
    }

    main.sendAction(cmd, config.CMD_TYPE.EVAL,
        "Sending command to Rserve", options);
}
exports.evaluate = evaluate;

Fix host and path validation.


"use strict";

function FillMeInError() {
    this.name = "FillMeInError";
    this.message = this.name;
    Error.captureStackTrace(this, FillMeInError);
}

var assert = require("assert");

assert.isNull = function(object) {
    assert.equal(null, object);
};

assert.methodExists = function(type, method, arity) {
    assert.equal("function", typeof(type.prototype[method]), "Expected " + type.name + "." + method + " to be a function");
    assert.equal(arity, type.prototype[method].length, "Expected " + type.name + "." + method + ".length == " + arity);
};

global.__ = "FILL ME IN";
global.___ = FillMeInError;
global.ArrayList = require("../lib/array-list");
global.assert = assert;
global.Kamayan = require("../lib/kamayan");
global.FillMeInError = FillMeInError;
global.FixedArray = require("../lib/fixed-array");
global.IndexError = require("../lib/index-error");

"use strict";

function FillMeInError() {
    this.name = "FillMeInError";
    this.message = this.name;
    Error.captureStackTrace(this, FillMeInError);
}

var assert = require("assert");

assert.isNull = function(object) {
    assert.equal(null, object);
};

assert.methodExists = function(type, method, arity) {
    assert.equal("function", typeof(type.prototype[method]), "Expected " + type.name + "." + method + " to be a function");
    assert.equal(arity, type.prototype[method].length, "Expected " + type.name + "." + method + ".length == " + arity);
};

// assert.throws is allowing too many things to pass, so we are going to change
// it to just what we need it to do.
assert.throws = function(fn, expected) {
    var thrown = false;

    try {
        fn.call();
    } catch (e) {
        thrown = true;

        if (e.constructor != expected) {
            assert.fail(e.constructor.name, expected.name, "Expected exception of type " + expected.name + ", but got " + e.constructor.name + " instead");
        }
    }

    if (!thrown) {
        assert.fail("<nothing was raised>", expected.name, "Expected exception of type " + expected.name + ", but nothing was thrown");
    }
};

global.__ = "FILL ME IN";
global.___ = FillMeInError;
global.ArrayList = require("../lib/array-list");
global.assert = assert;
global.Kamayan = require("../lib/kamayan");
global.FillMeInError = FillMeInError;
global.FixedArray = require("../lib/fixed-array");
global.IndexError = require("../lib/index-error");

Customize assert.throws, as it behaves in unintuitive ways sometimes


export class PlayerModelService {
	constructor($log, $http, $localStorage, _, websocket) {
		'ngInject';

		this.$log = $log;
		this.$http = $http;
		this.$localStorage = $localStorage;

		this._ = _;
		this.ws = websocket;

		this.model = {
			player: null
		};

		this.numDrawCards = 7;
	}

	insert(data) {
		this.$log.info('insert()', data, this);

		data.isCurrent = true;
		this.model.player = data;
		this.$localStorage.player = this.model.player;
	}

	update(data) {
		Object.assign(this.model.player, data);
	}
}

export class PlayerModelService {
	constructor($log, $http, $localStorage, _, websocket) {
		'ngInject';

		this.$log = $log;
		this.$http = $http;
		this.$localStorage = $localStorage;

		this._ = _;
		this.ws = websocket;

		this.model = {
			player: null
		};

		this.numDrawCards = 7;
	}

	insert(data) {
		let pl = Object.assign({}, {
					isCurrent: true,
					cardsInHand: []
				}, data
			);

		this.$log.info('insert()', pl, this);

		this.model.player = pl;
		this.$localStorage.player = this.model.player;
	}

	update(data) {
		Object.assign(this.model.player, data);
	}
}

Use Object.assign() to update object


/*
    ___ usage ___ en_US ___
    node stdout.udp.bin.js --bind ip:port

    options:

        --help                      display help message
        -p, --port      <integer>   port to listen to
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    program.helpIf(program.param.help)
    program.required('port')
    var dgram = require('dgram')
    var socket = dgram.createSocket('udp4')
    socket.on('message', function (buffer) {
        console.log('called')
        program.stdout.write(buffer)
    })
    program.on('SIGINT', socket.close.bind(socket))
    async(function () {
        // TODO Bind should be port or port and address.
        socket.bind(+program.param.port, async())
    }, function () {
        return 0
    })
}))

/*
    ___ usage ___ en_US ___
    node stdout.udp.bin.js --bind ip:port

    options:

        --help                      display help message
        -p, --port      <integer>   port to listen to
    ___ . ___

 */
require('arguable')(module, require('cadence')(function (async, program) {
    program.helpIf(program.param.help)
    program.required('port')
    var dgram = require('dgram')
    var socket = dgram.createSocket('udp4')
    socket.on('message', function (buffer) {
        program.stdout.write(buffer)
        program.stdout.write('\n')
    })
    program.on('SIGINT', socket.close.bind(socket))
    async(function () {
        // TODO Bind should be port or port and address.
        socket.bind(+program.param.port, async())
    }, function () {
        return 0
    })
}))

Fix Prolific UDP listener print line.


const JSONWebToken = require('../../models/jsonwebtoken');

describe('JSONWebToken', function() {

  it('should be able to round trip', () => {
    const userId = 1;
    const {sig, token} = JSONWebToken.create(userId);
    const subject = new JSONWebToken(token);

    const {sig: sig2} = JSONWebToken.create(userId);

    expect(subject.verify(sig)).toBeTruthy();
    expect(subject.verify(sig2)).toEqual(false);
  });

});

const JSONWebToken = require('../../models/jsonwebtoken');
const uuid = require('uuid');
const jwt = require('jsonwebtoken');
const ec = require('../../ec-crypto');

describe('JSONWebToken', function() {

  it('should be able to round trip', () => {
    const userId = 1;
    const {sig, token} = JSONWebToken.create(userId);
    const subject = new JSONWebToken(token);

    const {sig: sig2} = JSONWebToken.create(userId);

    expect(subject.verify(sig)).toBeTruthy();
    expect(subject.verify(sig2)).toEqual(false);
  });

  it('should fail to verify with a missing key id', async () => {
    const pair = ec.generateKeyPair();
    const sig = jwt.sign({}, pair.private, {
      algorithm: ec.JWT_ALGORITHM
    });
    expect(await JSONWebToken.verifyJWT(sig)).toEqual(false);
  });

  it('should fail to verify with an incorrect key id', async () => {
    const pair = ec.generateKeyPair();
    const sig = jwt.sign({}, pair.private, {
      algorithm: ec.JWT_ALGORITHM,
      keyid: 'tomato'
    });
    expect(await JSONWebToken.verifyJWT(sig)).toEqual(false);
  });

  it('should fail to verify a JWT with the "none" alg', async () => {
    const pair = ec.generateKeyPair();
    const sig = jwt.sign({}, pair.private, {
      algorithm: 'none',
      keyid: uuid.v4()
    });
    expect(await JSONWebToken.verifyJWT(sig)).toEqual(false);
  });

});

Add tests of JWT kid and alg values


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

var middleware = module.exports = {};

middleware.loadRoles = function (req, res, next) {
    if (req.user) {
        model.role.model.find({'_id': { $in: req.user.roles }}, function (err, docs) {
            if (err) next();

            var roles = [];
            var permissions = [];
            for (var d in docs) {
                var role = docs[d];
                roles.push(role.name);
                if (role.permissions) {
                    for (var permission in role.permissions) {
                        if (permissions.indexOf(permission) !== 0) {
                            permissions.push(permission);
                        }
                    }
                }
            }
            if (!req.bauhaus) req.bauhaus = {};
            req.bauhaus.roles = roles;
            req.bauhaus.permissions = permissions;

            next();
        })
    } else {
        next();
    }
};

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

var middleware = module.exports = {};

middleware.loadRoles = function (req, res, next) {
    if (req.user && !req.session.user) {
        model.role.model.find({'_id': { $in: req.user.roles }}, function (err, docs) {
            if (err) next();

            var roles = [];
            var permissions = [];
            for (var d in docs) {
                var role = docs[d];
                roles.push(role.name);
                if (role.permissions) {
                    for (var permission in role.permissions) {
                        if (permissions.indexOf(permission) !== 0) {
                            permissions.push(permission);
                        }
                    }
                }
            }

            var user = {
                id: req.user._id,
                username: req.user.username,
                roles: roles,
                permissions: permissions
            }
            // add user info to session
            req.session.user = user;

            next();
        })
    } else {
        // remove user info from session
        req.session.user = null;
        next();
    }
};

Store roles and permissions in user session instead of reloading them each request


const Config = require('utils/config');

module.exports = Marionette.CompositeView.extend({

    template: require('templates/builder/pageDetails/pageElements/elementsCompositeView'),
    childView: require('./elementItemView'),
    childViewContainer: 'ul#elements-list',

    initialize: function() {
        if (!this.model) {
            return;
        }

        this.collection = this.model.elements;
    },

});

const Config = require('utils/config');

module.exports = Marionette.CompositeView.extend({

    template: require('templates/builder/pageDetails/pageElements/elementsCompositeView'),
    emptyView: require('./emptyElementsView'),
    childView: require('./elementItemView'),
    childViewContainer: 'ul#elements-list',

    initialize: function() {
        if (!this.model) {
            return;
        }

        this.collection = this.model.elements;
    },

});

Add emptyView option back to element list


// @flow
import type { AddressMap, KnxAddress } from '../types';

import React from 'react';

import createStore from '../lib/create-store';
import withRedux from 'next-redux-wrapper';
import App from '../components/App';
import WithBusSubsribe from '../components/WithBusSubribe';
import AddressList from '../components/AddressList';
import AppBar from '../components/AppBar';

import { compose, reject } from 'ramda';

const styles = {
  container: {
    textAlign: 'center',
    padding: '50px',
  },
};

/* Built address-list, remove some address-types which should not be displayed */
const addrFilter = reject((addr: KnxAddress) => addr.type === 'fb');

const IndexPage = props => {
  const { livestate }: AddressMap = addrFilter(props.smartHome);

  return (
    <App>

        <AppBar />

          <AddressList addresses={livestate} />

    </App>
  );
};

export default compose(
  withRedux(createStore, state => ({ smartHome: state.smartHome })),
  WithBusSubsribe
)(IndexPage);

// @flow
import type { AddressMap, KnxAddress } from '../types';

import React from 'react';

import createStore from '../lib/create-store';
import withRedux from 'next-redux-wrapper';
import App from '../components/App';
import WithBusSubsribe from '../components/WithBusSubribe';
import AddressList from '../components/AddressList';
import AppBar from '../components/AppBar';

import { compose, reject } from 'ramda';

const styles = {
  container: {
    textAlign: 'center',
    padding: '10px',
  },
};

/* Built address-list, remove some address-types which should not be displayed */
const addrFilter = reject((addr: KnxAddress) => addr.type === 'fb');

const IndexPage = props => {
  const { livestate }: AddressMap = addrFilter(props.smartHome);

  return (
    <App>

        <AppBar />

          <AddressList addresses={livestate} />

    </App>
  );
};

export default compose(
  withRedux(createStore, state => ({ smartHome: state.smartHome })),
  WithBusSubsribe
)(IndexPage);

Reduce padding for address-list to make it fit on mobile displays


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

var fs       = require("fs"),
    shell    = require("shelljs"),
    archiver = require("archiver");

module.exports = function(config, done) {
    var zip  = archiver("zip", { zlib : { level : 0 }}),
        dest = fs.createWriteStream("./dist/" + config.app + ".nw");

    dest.on("close", done);
    zip.on("error", done);

    zip.pipe(dest);

    shell.ls("-R", config.temp)
        .filter(function(item) {
            return fs.statSync(item).isFile();
        })
        .forEach(function(file) {
            zip.append(fs.createReadStream(file), { name : file });
        });

    zip.finalize(function(err, bytes) {
        if (err) {
            return done(err);
        }

        config.log("Wrote " + bytes + " bytes");
    });
};

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

var fs       = require("fs"),
    path     = require("path"),
    shell    = require("shelljs"),
    archiver = require("archiver");

module.exports = function(config, done) {
    var zip  = archiver("zip", { zlib : { level : 0 }}),
        dest = fs.createWriteStream(path.join("./temp", config.app + ".nw"));

    dest.on("close", done);
    zip.on("error", done);

    zip.pipe(dest);

    shell.ls("-R", config.temp)
        .filter(function(item) {
            return fs.statSync(item).isFile();
        })
        .forEach(function(file) {
            zip.append(
                fs.createReadStream(file),
                { name : file }
            );
        });

    zip.finalize(function(err, bytes) {
        if (err) {
            return done(err);
        }

        config.log("Wrote " + bytes + " bytes");
    });
};

Create complete zip of app


import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import TaskList from '../../../src/components/Todo/TaskList';

const setup = (props = {
  tasks: [],
  onTaskToggle() {},
  onTaskDelete() {},
}) => shallow(<TaskList {...props} />);

describe('Component | ToDo | TaskList', () => {
  it('renders', () => {
    const wrapper = setup();

    expect(wrapper.find('ul').length).to.equal(1);
  });
});

import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import TaskList from '../../../src/components/Todo/TaskList';

const setup = props => shallow(<TaskList {...props} />);

describe('Component | ToDo | TaskList', () => {
  it('renders', () => {
    const tasks = [
      {
        id: 1,
        description: 'test 1',
        isDone: false,
      },
      {
        id: 2,
        description: 'test 2',
        isDone: true,
      },
    ];

    const wrapper = setup({
      tasks,
      onTaskToggle() {},
      onTaskDelete() {},
    });

    expect(wrapper.find('ul')).to.have.lengthOf(1);
    expect(wrapper.find('ul').children()).to.have.lengthOf(tasks.length);
  });
});

Add tests for TaskList component


/**
 * Created by dungvn3000 on 3/11/14.
 */

Ext.define('sunerp.controller.sophancong.SoPhanCongListCtr', {
    extend: 'sunerp.controller.core.BaseListEditController',
    modelClass: 'sunerp.model.SoPhanCong',
    inject: ['soPhanCongStore', 'userService'],
    config: {
        soPhanCongStore: null,
        phongBangId: null,
        userService: null
    },
    searchField: "nhanVien.maNv",
    init: function () {
        this.mainStore = this.getSoPhanCongStore();
        this.setPhongBangId(this.getUserService().getCurrentUser().phongBangId);
        this.callParent(arguments);
    },
    addNewRow: function () {
        var rec = Ext.create(this.modelClass);
        rec.set('phongBangId', this.getPhongBangId());
        this.mainStore.insert(this.mainStore.count(), rec);
    }
});

/**
 * Created by dungvn3000 on 3/11/14.
 */

Ext.define('sunerp.controller.sophancong.SoPhanCongListCtr', {
    extend: 'sunerp.controller.core.BaseListEditController',
    modelClass: 'sunerp.model.SoPhanCong',
    inject: ['soPhanCongStore', 'userService'],
    config: {
        soPhanCongStore: null,
        phongBangId: null,
        userService: null
    },
    searchField: "nhanVien.maNv",
    init: function () {
        this.mainStore = this.getSoPhanCongStore();
        this.setPhongBangId(this.getUserService().getCurrentUser().phongBangId);
        this.callParent(arguments);
    },
    addNewRow: function () {
        var lastModel = this.getView().getStore().last();
        var rec = Ext.create(this.modelClass);
        rec.set('phongBangId', this.getPhongBangId());
        rec.set('ngayPhanCong', lastModel.get('ngayPhanCong'));
        this.mainStore.insert(this.mainStore.count(), rec);
    }
});

Fix can't insert when grouping.


Meteor.methods({
  'pingHost': function(host){
    this.unblock();

    var pingRes = Ping.host(host.ip);

    console.log("Host " + host.ip + ": " + pingRes.status + " " + pingRes.latency + "ms")

    if(pingRes.online){
      HostsCollection.update({_id: host._id},{$set: {
        lastSeen: new Date(),
        latency: pingRes.latency,
        status: pingRes.status
      }});
    } else {
      HostsCollection.update({_id: host._id},{$set: {
        status: pingRes.status
      }});
    }
  }
});

Meteor.methods({
  'pingHost': function(host){
    this.unblock();

    var pingRes = Ping.host(host.ip);

    console.log('Host ' + host.ip + ': ' + pingRes.status + ' ' + pingRes.latency + 'ms');

    if(pingRes.online){
      HostsCollection.update({_id: host._id},{$set: {
        lastSeen: new Date(),
        latency: pingRes.latency,
        status: pingRes.status
      }});
    } else {
      HostsCollection.update({_id: host._id},{$set: {
        status: pingRes.status
      }});
    }
  }
});

Use single quotes and semi colon


import Room from './room.js';

class RoomManager {

  constructor() {
    this.roomsById = {};
  }

  getRoom(roomCode) {
    return this.roomsById[roomCode];
  }

  openRoom() {
    let roomCode = this.obtainRoomCode();
    let room = new Room({
      players: [],
      code: roomCode
    });
    this.roomsById[roomCode] = room;
    return room;
  }

  closeRoom({ roomCode }) {
    delete this.roomsById[roomCode];
  }

  obtainRoomCode() {
    let roomCode;
    do {
      roomCode = this.generateRandomRoomCode();
    } while (this.roomsById[roomCode]);
    return roomCode;
  }

  generateRandomRoomCode() {
    let roomCode = '';
    let startIndex = 65;
    let endIndex = 90;
    for (var i = 0; i < RoomManager.roomCodeLength; i += 1) {
      roomCode += String.fromCharCode(Math.floor(startIndex + ((endIndex - startIndex + 1) * Math.random())));
    }
    return roomCode;
  }

}

// The number of characters is a given room code
RoomManager.roomCodeLength = 4;

export default RoomManager;

import Room from './room.js';

class RoomManager {

  constructor() {
    this.roomsById = {};
  }

  getRoom(roomCode) {
    return this.roomsById[roomCode];
  }

  openRoom() {
    let roomCode = this.obtainRoomCode();
    let room = new Room({
      players: [],
      code: roomCode
    });
    this.roomsById[roomCode] = room;
    return room;
  }

  closeRoom({ roomCode }) {
    delete this.roomsById[roomCode];
  }

  obtainRoomCode() {
    let roomCode;
    do {
      roomCode = this.generateRandomRoomCode();
    } while (this.roomsById[roomCode]);
    return roomCode;
  }

  generateRandomRoomCode() {
    let roomCode = '';
    // Uppercase letters A-Z
    let startIndex = 65;
    let endIndex = 90;
    for (var i = 0; i < RoomManager.roomCodeLength; i += 1) {
      roomCode += String.fromCharCode(Math.floor(startIndex + ((endIndex - startIndex + 1) * Math.random())));
    }
    return roomCode;
  }

}

// The number of characters is a given room code
RoomManager.roomCodeLength = 4;

export default RoomManager;

Add note about which chars are used to generate room code


var map = require('map-stream');

/**
 *
 * 排除 _ 开头的参数
 * @returns {Stream}
 */
module.exports = function (nextStream) {
      var stream = map(function (data, fn) {

            for (var key in data.data) {
                  /^_/.test(key) && delete data.data[key];
            }

            fn(null, data);
      });
      return stream;
};

var map = require('map-stream');

/**
 *
 * 排除 _ 开头的参数
 * @returns {Stream}
 */
module.exports = function (nextStream) {
  var stream = map(function (data, fn) {

      for(var key in data.data ){
            if(/_.+/.test(key)){
                delete data.data[key];
            }
      }

      fn(null, data);
  });
  return stream;
};

Revert "format and fix regex"


const
  fs = require('fs');

/* Remove all white space from str. */
function minifyString(str) {
 return str.replace(/\s/g, '');
};

/* Insert .min extension to FileName. */
function addMinExtension(FileName) {
  var fileExtIndex = FileName.indexOf('.')
    , filePrefix   = FileName.slice(0, fileExtIndex)
    , fileExten    = FileName.slice(fileExtIndex, FileName.length)
    , minFileName  = filePrefix + '.min' + fileExten;

  return minFileName;
};

/* Removes white space from file and
   writes new minified file. */
(function main() {

  /* Read the file into a string */
  var filePath       = process.argv[2]
    , fileContent    = fs.readFileSync(filePath, 'utf8')
    , minFileContent = minifyString(fileContent)
    , minFileName    = addMinExtension(filePath);

  var minifiedFile = fs.writeFile(minFileName, minFileContent, function(err) {
    if (err) { throw err; };
    console.log('-- ' + filePath + ' minified to ' + minFileName + ' --');
  });
})();

#!/usr/bin/env node

const
  fs = require('fs');

/* Remove all white space from str. */
function minifyString(str) {
  return str.replace(/\s/g, '');
};

/* Insert .min extension to FileName. */
function addMinExtension(FileName) {
  var fileExtIndex = FileName.indexOf('.')
    , filePrefix   = FileName.slice(0, fileExtIndex)
    , fileExten    = FileName.slice(fileExtIndex, FileName.length)
    , minFileName  = filePrefix + '.min' + fileExten;

  return minFileName;
};

/* Removes white space from file and writes minified data to a new file. */
(function main() {

  /* Read the file into a string */
  var filePath       = process.argv[2]
    , fileContent    = fs.readFileSync(filePath, 'utf8')
    , minFileContent = minifyString(fileContent)
    , minFileName    = addMinExtension(filePath);

  var minifiedFile = fs.writeFile(minFileName, minFileContent, function(err) {
    if (err) { throw err; };
    console.log('-- ' + filePath + ' minified to ' + minFileName + ' --');
  });
})();

Add node env location to script header.


import Kinvey from 'kinvey-javascript-sdk-core';
import { NetworkRack } from 'kinvey-javascript-sdk-core/es5/rack/rack';
import { HttpMiddleware } from 'kinvey-javascript-sdk-core/es5/rack/middleware/http';
import { PhoneGapHttpMiddleware } from './http';
import { PhoneGapPush } from './push';
import { PhoneGapPopup } from './popup';
import { PhoneGapDevice } from './device';

// Add Http middleware
const networkRack = NetworkRack.sharedInstance();
networkRack.swap(HttpMiddleware, new PhoneGapHttpMiddleware());

// Extend the Kinvey class
class PhoneGapKinvey extends Kinvey {
  static init(options) {
    // Initialize Kinvey
    const client = super.init(options);

    // Add Push module to Kinvey
    this.Push = new PhoneGapPush();

    // Return the client
    return client;
  }
}

// Expose some globals
global.KinveyDevice = PhoneGapDevice;
global.KinveyPopup = PhoneGapPopup;

// Export
module.exports = PhoneGapKinvey;

import Kinvey from 'kinvey-javascript-sdk-core';
import { KinveyError } from 'kinvey-javascript-sdk-core/es5/errors';
import { NetworkRack } from 'kinvey-javascript-sdk-core/es5/rack/rack';
import { HttpMiddleware } from 'kinvey-javascript-sdk-core/es5/rack/middleware/http';
import { PhoneGapHttpMiddleware } from './http';
import { PhoneGapPush } from './push';
import { PhoneGapPopup } from './popup';
import { PhoneGapDevice } from './device';

// Add Http middleware
const networkRack = NetworkRack.sharedInstance();
networkRack.swap(HttpMiddleware, new PhoneGapHttpMiddleware());

// Extend the Kinvey class
class PhoneGapKinvey extends Kinvey {
  static init(options) {
    if (PhoneGapDevice.isPhoneGap()) {
      const onDeviceReady = () => {
        document.removeEventListener('deviceready', onDeviceReady);

        if (!global.device) {
          throw new KinveyError('Cordova Device Plugin is not installed.',
            'Please refer to http://devcenter.kinvey.com/phonegap-v3.0/guides/push#ProjectSetUp for help with'
            + ' setting up your project.');
        }
      };

      document.addEventListener('deviceready', onDeviceReady, false);
    }

    // Initialize Kinvey
    const client = super.init(options);

    // Add Push module to Kinvey
    this.Push = new PhoneGapPush();

    // Return the client
    return client;
  }
}

// Expose some globals
global.KinveyDevice = PhoneGapDevice;
global.KinveyPopup = PhoneGapPopup;

// Export
module.exports = PhoneGapKinvey;

Check that cordova device plugin is installed


// command: 'cat ./stolaf-base/printer-data-url.txt | xargs curl --silent',
command: 'cat ./stolaf-base/printerstatus.csv',

refreshFrequency: 60000,
lastUpdateTime: undefined,

style: [
	"bottom: 0",
	"left: 75%",
	"width: 25%",
	"text-align: center",
	"border: 0",
	"height: 3%",
	"vertical-align: middle",
	"color: rgba(255, 255, 255, 0.5)",
	"font-weight: 300",
].join('\n'),

render: function(argument) {
	return 'Printers: ';
},

update: function(output, domEl) {
	if (!window.sto)             return '';
	if (!window.sto.libs.csv)    return '';
	if (!window.sto.libs.moment) return '';
	var csv = window.sto.libs.csv;
	var moment = window.sto.libs.moment;

	window.sto.data.printers = csv.parse(output, {header: true, cast: ['String', 'String', 'String']});;

	this.lastUpdateTime = new Date();
	domEl.querySelector('.last-updated').textContent = moment(this.lastUpdateTime).calendar();
},

// command: 'cat ./stolaf-base/printer-data-url.txt | xargs curl --silent',
command: 'bash ./stolaf-base/snmpGet.sh',

refreshFrequency: 60000,
lastUpdateTime: undefined,

style: [
	"bottom: 0",
	"left: 75%",
	"width: 25%",
	"text-align: center",
	"border: 0",
	"height: 3%",
	"vertical-align: middle",
	"color: rgba(255, 255, 255, 0.5)",
	"font-weight: 300",
].join('\n'),

render: function(argument) {
	return 'Printers: ';
},

update: function(output, domEl) {
	if (!window.sto)             return '';
	if (!window.sto.libs.csv)    return '';
	if (!window.sto.libs.moment) return '';
	var csv = window.sto.libs.csv;
	var moment = window.sto.libs.moment;

	window.sto.data.printers = csv.parse(output, {header: true, cast: ['String', 'String', 'String', 'String']});;

	this.lastUpdateTime = new Date();
	domEl.querySelector('.last-updated').textContent = moment(this.lastUpdateTime).calendar();
},

Update the background printer widget to handle the new system


var http = require('http'),
    httpProxy = require('http-proxy'),
    config = require('./config');

var sendError = function(err, req, res) {
  res.writeHead(500, {
    'Content-Type': 'text/plain'
  });

  res.end(config.error_message);
};

var proxy = httpProxy.createProxyServer({});

proxy.on('error', function(err, req, res) {
  sendError(err, req, res);
});

var server = require('http').createServer(function(req, res) {
  var reqHost = req.headers['host'];

  for(c in config.proxies) {

    var configHost = config.proxies[c].host;

    if(reqHost === configHost){
      return proxy.web(req, res, { target: 'http://127.0.0.1:' + config.proxies[c].local_port });
    }
  }

  console.log('No rules for :', req.headers['host']);
  sendError(new Error('No rule for host'), req, res);
});

console.log('listening on port ' + config.listening_port);
server.listen(config.listening_port);

var http = require('http'),
    httpProxy = require('http-proxy'),
    config = require('./config');

var sendError = function(err, req, res) {
  res.writeHead(500, {
    'Content-Type': 'text/plain'
  });

  res.end(config.error_message);
};

var proxy = httpProxy.createProxyServer({});

proxy.on('error', function(err, req, res) {
  console.log('Unable to forward the request from ', req.headers['host']);
  sendError(err, req, res);
});

var server = require('http').createServer(function(req, res) {
  var reqHost = req.headers['host'];

  for(c in config.proxies) {
    var configHost = config.proxies[c].host;
    if(reqHost === configHost){
      return proxy.web(req, res, { target: 'http://127.0.0.1:' + config.proxies[c].local_port });
    }
  }

  console.log('No rules for :', req.headers['host']);
  sendError(new Error('No rule for host'), req, res);
});

console.log('listening on port ' + config.listening_port);
server.listen(config.listening_port);

Add log when servers are unavailable


/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau
 * MIT Licensed
 */

"use strict";

const DataError = require("./../dataerror");

class ContentTypeProvider {
    constructor() {
    };

    getFromExt(ext) {
        switch (ext) {
            case ".json": return "application/json";
            case ".png": return "image/png";
            case ".jpg": return "image/jpg";
            case ".gif": return "image/gif";
            case ".svg": return "image/svg+xml";
            case ".js": return "application/javascript";
            case ".html": return "text/html";
            case ".css": return "text/css";
            case ".ico": return "image/x-icon";
            case ".ttf": return "application/x-font-ttf";
            case ".eot": return "application/vnd.ms-fontobject";
            case ".woff": return "application/font-woff";
            case ".appcache": return "text/cache-manifest";
            default: throw new DataError({ message: "Extension is not supported", data: { extension: ext }});
        };
    };
};

exports = module.exports = new ContentTypeProvider();

/*!
 * qwebs
 * Copyright(c) 2015 Benoît Claveau
 * MIT Licensed
 */

"use strict";

const DataError = require("./../dataerror");

class ContentTypeProvider {
    constructor() {
    };

    getFromExt(ext) {
        switch (ext) {
            case ".json": return "application/json";
            case ".png": return "image/png";
            case ".jpg": return "image/jpg";
            case ".gif": return "image/gif";
            case ".svg": return "image/svg+xml";
            case ".js": return "application/javascript";
            case ".html": return "text/html";
            case ".css": return "text/css";
            case ".ico": return "image/x-icon";
            case ".ttf": return "application/x-font-ttf";
            case ".eot": return "application/vnd.ms-fontobject";
            case ".woff": return "application/font-woff";
            case ".appcache": return "text/cache-manifest";
            case ".txt": return "text/plain";
            case ".xml": return "application/xml";
            default: throw new DataError({ message: "Extension is not supported", data: { extension: ext }});
        };
    };
};

exports = module.exports = new ContentTypeProvider();

Manage xml and text content type.


import CLIEngine from "./cli-engine";
import defaultOptions from "./default-options";
import log from "../helper/log";
import options from "./options";
import pkg from "../../package.json";

export default {
  /**
   * Executes the CLI based on an array of arguments that is passed
   * @param {String[]} args - The arguments to process
   * @returns {Number} The exit code for the operation
   */
  execute: (args) => {
    let currentOptions;
    let stream;

    try {
      currentOptions = options.parse(args);
    } catch (error) {
      log("error", error.message);
      return 1;
    }

    const files = currentOptions._;

    if (currentOptions.version) {
      log("log", `v${pkg.version}`);
    } else if (currentOptions.help) {
      log("log", options.generateHelp());
    } else {
      const engine = new CLIEngine(translateOptions(currentOptions));
      stream = engine.executeOnFiles(files);
    }

    return 0;
  }
}

/**
 * Translates the CLI options into the options expected by the CLIEngine
 * @param {Object} cliOptions - The CLI options object (optionator format)
 * @returns {Object} The options object for the CLIEngine
 * @private
 */
function translateOptions(cliOptions) {
  return {
    config: cliOptions.config || defaultOptions.config,
    output: cliOptions.output || defaultOptions.output,
    watch : cliOptions.watch || defaultOptions.watch
  };
}

import CLIEngine from "./cli-engine";
import defaultOptions from "./default-options";
import log from "../helper/log";
import options from "./options";
import pkg from "../../package.json";

export default {
  /**
   * Executes the CLI based on an array of arguments that is passed
   * @param {String[]} args - The arguments to process
   * @returns {Number} The exit code for the operation
   */
  execute: (args) => {
    let currentOptions;

    try {
      currentOptions = options.parse(args);
    } catch (error) {
      log("error", error.message);
      return 1;
    }

    const files = currentOptions._;

    if (currentOptions.version) {
      log("log", `v${pkg.version}`);
    } else if (currentOptions.help) {
      log("log", options.generateHelp());
    }

    if (currentOptions.version || currentOptions.help) {
      return 0;
    }

    if (currentOptions.watch) {
      // TODO: Implement watch mode. It maybe using chokidar.
    } else {
      const engine = new CLIEngine(translateOptions(currentOptions));
      engine.executeOnFiles(files);
    }

    return 0;
  }
}

/**
 * Translates the CLI options into the options expected by the CLIEngine
 * @param {Object} cliOptions - The CLI options object (optionator format)
 * @returns {Object} The options object for the CLIEngine
 * @private
 */
function translateOptions(cliOptions) {
  return {
    config: cliOptions.config || defaultOptions.config,
    output: cliOptions.output || defaultOptions.output,
    watch : cliOptions.watch || defaultOptions.watch
  };
}

Add TODO comment for watch mode


'use strict';
import React from 'react';

const Error404 = () => (

404.. This page is not found!

);

export default Error404;

// src2="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABIAQMAAABvIyEEAAAABlBMVEUAAABTU1OoaSf/AAAAAXRSTlMAQObYZgAAAENJREFUeF7tzbEJACEQRNGBLeAasBCza2lLEGx0CxFGG9hBMDDxRy/72O9FMnIFapGylsu1fgoBdkXfUHLrQgdfrlJN1BdYBjQQm3UAAAAASUVORK5CYII="

Add fallback view for unrecognized wildcard routes


/* global angular, mist */
import {web3} from '../../contract/Chess.sol';
angular.module('dappChess').factory('accounts', function () {
  return {
    // For testing purposes: Use the first 5 accounts for non-mist and the last 5 for mist browsers
    availableAccounts: (typeof(mist) === 'undefined') ?
      web3.eth.accounts.slice(0, 5) :
      web3.eth.accounts.slice(5, 10),
    defaultAccount: web3.eth.defaultAccount,
    requestAccount: (typeof(mist) !== 'undefined') ?
      mist.requestAccount :
      function(callback) {
        console.log('Not implemented yet');
        callback();
      }
  };
});

/* global angular, mist */
import {web3} from '../../contract/Chess.sol';
angular.module('dappChess').factory('accounts', function () {
  return {
    // Use the first 5 accounts for mist or firefox and the last 5 for other browsers
    availableAccounts: (typeof(mist) !== 'undefined' ||
    window.navigator.userAgent.indexOf('Firefox') !== -1) ?
      web3.eth.accounts.slice(0, 5) :
      web3.eth.accounts.slice(5, 10),
    defaultAccount: web3.eth.defaultAccount,
    requestAccount: (typeof(mist) !== 'undefined') ?
      mist.requestAccount :
      function(callback) {
        console.log('Not implemented yet');
        callback();
      }
  };
});

Check for firefox for testrpc initialisation


export default class Parallax3D {

  constructor(element, initialTransform) {
    this.elem = element;
    this.initialTransform = initialTransform;
    this.rotmax = 10;

    window.addEventListener('mousemove', e => this.update(e));
  }

  /** Get mouse coordinates on the screen in range [-1, 1] */
  static getMouse(e) {
    const w = window.innerWidth; const h = window.innerHeight;
    const halfw = w / 2; const halfh = h / 2;
    const x = e.clientX; const y = e.clientY;
    const finalx = (x - halfw) / halfw; const finaly = (y - halfh) / halfh;
    return [finalx, finaly];
  }

  /** Adjust rotation based on values from -1 to 1 */
  rotate(rotx, roty) {
    this.elem.style.transform = [
      this.initialTransform,
      `rotateX(${rotx * this.rotmax}deg)`,
      `rotateY(${roty * this.rotmax}deg)`,
    ].join(' ');
  }

  /** Update rotation from a mouse event */
  update(e) {
    // Flip mouse position and rotate by that amount
    this.rotate(...Parallax3D.getMouse(e).map(n => -n).reverse());
  }
}

export default class Parallax3D {

  constructor(element, initialTransform) {
    this.elem = element;
    this.initialTransform = initialTransform;
    this.rotmax = 10;

    window.addEventListener('mousemove', e => this.update(e));
  }

  /** Get mouse coordinates on the screen in range [-1, 1] */
  static getMouse(e) {
    const w = window.innerWidth; const h = window.innerHeight;
    const halfw = w / 2; const halfh = h / 2;
    const x = e.clientX; const y = e.clientY;
    const finalx = (x - halfw) / halfw; const finaly = (y - halfh) / halfh;
    return [finalx, finaly];
  }

  /** Adjust rotation based on values from -1 to 1 */
  rotate(rotx, roty) {
    this.elem.style.transform = [
      this.initialTransform,
      `rotateX(${rotx * this.rotmax}deg)`,
      `rotateY(${roty * this.rotmax}deg)`,
    ].join(' ');
  }

  /** Update rotation from a mouse event */
  update(e) {
    if (!this.disabled) {
      // Flip mouse position and rotate by that amount
      this.rotate(...Parallax3D.getMouse(e).map(n => -n).reverse());
    }
  }

  disable() {
    this.disabled = true;
    this.rotate(0, 0);
  }
  enable() {
    this.disabled = false;
  }
}

Add disable/enable methods to Parallax3D


// Heavily inspired by coffee-script again

exports.Scope = function (parent) {
    var self = this;

    if (parent) {
        self.root = null;
    } else {
        self.root = self;
    }

    self.parent = parent;

    // where we keep the variables names for this scope
    self.variables = {};

    // add a variable to the scope
    self.add = function (name) {
        if (self.variables[name]) {
            throw "Variable " + name + " already defined";
        } else {
            self.variables[name] = true;
        }
    }

    // check the existence of a variable in this scope or any parent
    self.check = function (name) {
        return !!self.variables[name] || self.parent.check(name);
    }

    // generate a temporary variable name
    self.temporary = function (name, index) {
        return '_' + name + index;
    }

    // create a temporary variable with an available name
    self.addTempVar = function (name, reserve) {
        var index = 0,
            newName = self.temporary(name, index);

        while (self.check(newName)) {
            index++;
            newName = self.temporary(name, index);
        }

        if (reserve) {
            self.add(newName);
        }

        return newName;
    }
}

// Heavily inspired by coffee-script again
(function() {
    var Scope;

    exports.Scope = Scope = (function () {
        Scope.root = null;

        function Scope(parent) {
            this.parent = parent;

            if (!this.parent) {
                Scope.root = this;
            }

            // where we keep the variables names for this scope
            this.variables = {};
        };

        // add a variable to the scope
        Scope.prototype.add = function (name) {
            if (this.variables[name]) {
                throw "Variable " + name + " already defined";
            } else {
                this.variables[name] = true;
            }
        };

        // check the existence of a variable in this scope or any parent
        Scope.prototype.check = function (name) {
            return !!this.variables[name] || this.parent.check(name);
        };

        // generate a temporary variable name
        Scope.prototype.temporary = function (name, index) {
            return '_' + name + index;
        };

        // create a temporary variable with an available name
        Scope.prototype.addTempVar = function (name, reserve) {
            var index = 0,
                newName = this.temporary(name, index);

            while (this.check(newName)) {
                index++;
                newName = this.temporary(name, index);
            }

            if (reserve) {
                this.add(newName);
            }

            return newName;
        };

        return Scope;
    })();

}).call(this);

Rewrite Scope with prototypal notation


// Polyfills
''.trim||(String.prototype.trim=function(){return this.replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g,'');});
if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, FNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof FNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
        };
    FNOP.prototype = this.prototype;
    fBound.prototype = new FNOP();

    return fBound;
  };
}

REIN.tools = {
    trackEvent: function (category, action, opt_label, opt_value) {
        window._gaq && window._gaq.push(['_trackEvent', category, action, opt_label, opt_value]);
    },

    trackPageView: function (url) {
        window._gaq && window._gaq.push(['_trackPageview', url]);
    }
};

// Polyfills
''.trim||(String.prototype.trim=function(){return this.replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g,'');});
if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }
    var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, FNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof FNOP ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments)));
        };
    FNOP.prototype = this.prototype;
    fBound.prototype = new FNOP();

    return fBound;
  };
}

REIN.tools = {
    debug: function (firstText) {
        var $debug = $('
'),
            template = _.template('
<%= t %>
'),
            debugFn = function (text) {
                console.log(text);
                $debug.append(template({t: text}));
            };
        $('body').append($debug);
        debugFn(firstText);
        return debugFn;
    },

    defer: function (object, method, delay) {
        var args = Array.prototype.slice.call(arguments, 3),
            fnBind = function () {
                object[method].apply(object, args);
            };
        setTimeout(fnBind, delay);
    },

    trackEvent: function (category, action, opt_label, opt_value) {
        window._gaq && window._gaq.push(['_trackEvent', category, action, opt_label, opt_value]);
    },

    trackPageView: function (url) {
        window._gaq && window._gaq.push(['_trackPageview', url]);
    }
};

Add custom defer and debug function


/**
 * main.js
 */

'use strict';

// Only run in capable browsers via feature detection
var didCutTheMustard = 'querySelector' in document
  && 'classList' in document.createElement('a')
  && 'addEventListener' in window;

/**
 * Add line numbers to

 */
function numberedLines() {
  var pre = document.querySelectorAll('pre'),
      pl = pre.length;

  for (var i = 0; i < pl; i++) {
    pre[i].insertAdjacentHTML('beforeend', '');
    var num = pre[i].innerHTML.split(/\n/).length;

    // Start counter at 1 to circumvent Jekyll adding an extra line in
    for (var j = 1; j < num; j++) {
      var lineNum = pre[i].querySelector('.ln');
      lineNum.insertAdjacentHTML('beforeend', '');
    }
  }
}

if (didCutTheMustard) {

  // Add class "js" to html element
  document.querySelector('html').classList.add('js');

  // Add numbered lines to

  numberedLines();

}

/**
 * main.js
 */

'use strict';

// Only run in capable browsers via feature detection
var didCutTheMustard = 'querySelector' in document
  && 'classList' in document.createElement('a')
  && 'addEventListener' in window;

/**
 * Add line numbers to

 */
function numberedLines() {
  var pre = document.querySelectorAll('pre'),
      pl = pre.length;

  for (var i = 0; i < pl; i++) {
    pre[i].insertAdjacentHTML('beforeend', '');
    var num = pre[i].innerHTML.split(/\n/).length;

    // Start counter at 1 to circumvent Jekyll adding an extra line in
    for (var j = 1; j < num; j++) {
      var lineNum = pre[i].querySelector('.ln');
      lineNum.insertAdjacentHTML('beforeend', '');
    }
  }
}

/**
 * Add a little christmas spirit
 */
function snowyHeader() {
  var headElem = document.querySelector('head');
  var snowStyles = '<link rel="stylesheet" href="//frippz-se.s3.amazonaws.com/christmas.css">';
  var header = document.querySelector('#header');

  headElem.insertAdjacentHTML('beforeend', snowStyles);
  header.classList.add('snow');
}

if (didCutTheMustard) {

  // Add class "js" to html element
  document.querySelector('html').classList.add('js');

  // Add numbered lines to

  numberedLines();

  // Let it snow!
  snowyHeader();

}

Add JS for some christmas spirit


define([
  'common/views/visualisations/bar-chart/user-satisfaction',
  'common/views/visualisations/bar-chart/bar-chart',
  'common/collections/journey',
  'extensions/collections/collection',
  'backbone'
],
function (UserSatisfaction, BarChart, JourneyCollection, Collection, Backbone) {

  describe('UserSatisfaction Bar Chart', function () {
    var graph;

    beforeEach(function () {
      spyOn(UserSatisfaction.prototype, 'render');

      graph = new UserSatisfaction({
        collection: new Collection([ { values: new Collection([]) } ], { format: 'integer' })
      });
    });

    describe('initialize()', function () {
      it('calls render() on a reset of the collection data', function () {
        expect(UserSatisfaction.prototype.render).not.toHaveBeenCalled();

        graph.collection.at(0).get('values').reset();
        expect(UserSatisfaction.prototype.render).toHaveBeenCalled();
      });
    });

    describe('components()', function () {
      beforeEach(function () {
        spyOn(BarChart.prototype, 'components').andReturn({
          hover: {
            view: {}
          },
          xaxis: {
            view: Backbone.View
          }
        });
      });

      it('removes the hover component from the BarChart', function () {
        expect(graph.components().hover).toBeUndefined();
      });

      it('removes the yaxis component from the BarChart', function () {
        expect(graph.components().yaxis).toBeUndefined();
      });

      it('sets the xasis to not useEllipses', function () {
        expect(graph.components().xaxis.view.prototype.useEllipses).toEqual(false);
      });
    });

  });

});

define([
  'common/views/visualisations/bar-chart/user-satisfaction',
  'common/views/visualisations/bar-chart/bar-chart',
  'extensions/collections/collection',
  'backbone'
],
function (UserSatisfaction, BarChart, Collection, Backbone) {

  describe('UserSatisfaction Bar Chart', function () {
    var graph;

    beforeEach(function () {
      spyOn(UserSatisfaction.prototype, 'render');

      graph = new UserSatisfaction({
        collection: new Collection([], { format: 'integer' })
      });
    });

    describe('initialize()', function () {
      it('calls render() on a reset of the collection data', function () {
        expect(UserSatisfaction.prototype.render).not.toHaveBeenCalled();

        graph.collection.reset();
        expect(UserSatisfaction.prototype.render).toHaveBeenCalled();
      });
    });

    describe('components()', function () {
      beforeEach(function () {
        spyOn(BarChart.prototype, 'components').andReturn({
          hover: {
            view: {}
          },
          xaxis: {
            view: Backbone.View
          }
        });
      });

      it('removes the hover component from the BarChart', function () {
        expect(graph.components().hover).toBeUndefined();
      });

      it('removes the yaxis component from the BarChart', function () {
        expect(graph.components().yaxis).toBeUndefined();
      });

      it('sets the xasis to not useEllipses', function () {
        expect(graph.components().xaxis.view.prototype.useEllipses).toEqual(false);
      });
    });

  });

});

Fix user satisfaction bar charts tests following removal of the matrix


define([
	'backbone',
	'jquery',
	'underscore',

	'chartsM',
	'visualizationsServiceM',
], function (Backbone, $, _, chartsM, visualizationsServiceM) {
	'use strict';

	var IframeChartV = Backbone.View.extend({
		initialize: function () {
			this.listenTo(chartsM, 'change:apiData', this.render);
		},
		render: function() {
			var visualizationData = _.find(visualizationsServiceM.get('visualizations'), function(item) {
				return item.slug === chartsM.get('currentChartSlug');
			});
			this.$el.empty().append($('<iframe>', {
				'class': 'visualization-iframe',
				src: visualizationData.iframeSrcUrl + '&height=' + this.$el.height() + '&width=' + this.$el.width() +
					'&legislation_url=' + (chartsM.get('legislation') || '') + '&year=' + chartsM.get('year'),
			}));
		},
	});

	return IframeChartV;
});

define([
	'backbone',
	'jquery',
	'underscore',

	'chartsM',
	'visualizationsServiceM',
], function (Backbone, $, _, chartsM, visualizationsServiceM) {
	'use strict';

	var IframeChartV = Backbone.View.extend({
		initialize: function () {
			this.listenTo(chartsM, 'change:apiData', this.render);
		},
		render: function() {
			var visualizationData = _.find(visualizationsServiceM.get('visualizations'), function(item) {
				return item.slug === chartsM.get('currentChartSlug');
			});
			if ( ! _.isUndefined(visualizationData)) {
				this.$el.empty().append($('<iframe>', {
					'class': 'visualization-iframe',
					src: visualizationData.iframeSrcUrl + '&height=' + this.$el.height() + '&width=' + this.$el.width() +
						'&legislation_url=' + (chartsM.get('legislation') || '') + '&year=' + chartsM.get('year'),
				}));
			}
		},
	});

	return IframeChartV;
});

Handle case iframe is rendered too early.


function strtok (str, tokens) {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brettz9.blogspot.com)
    // %        note 1: Use tab and newline as tokenizing characters as well
    // *     example 1: $string = "\t\t\t\nThis is\tan example\nstring\n";
    // *     example 1: $tok = strtok($string, " \n\t");
    // *     example 1: $b = '';
    // *     example 1: while($tok !== false) {$b += "Word="+$tok+"\n"; $tok = strtok(" \n\t");}
    // *     example 1: $b
    // *     returns 1: "Word=This\nWord=is\nWord=an\nWord=example\nWord=string\n"

    if (tokens === undefined) {
        tokens = str;
        str = strtok.leftOver;
    }
    if (str.length === 0) {
        return false;
    }
    if (tokens.indexOf(str[0]) !== -1) {
        return strtok(str.substr(1), tokens);
    }
    for (var i=0; i < str.length; i++) {
        if (tokens.indexOf(str[i]) !== -1) {
            break;
        }
    }
    strtok.leftOver = str.substr(i+1);
    return str.substring(0, i);
}

function strtok (str, tokens) {
    // http://kevin.vanzonneveld.net
    // +   original by: Brett Zamir (http://brettz9.blogspot.com)
    // %        note 1: Use tab and newline as tokenizing characters as well
    // *     example 1: $string = "\t\t\t\nThis is\tan example\nstring\n";
    // *     example 1: $tok = strtok($string, " \n\t");
    // *     example 1: $b = '';
    // *     example 1: while($tok !== false) {$b += "Word="+$tok+"\n"; $tok = strtok(" \n\t");}
    // *     example 1: $b
    // *     returns 1: "Word=This\nWord=is\nWord=an\nWord=example\nWord=string\n"

    if (!this.php_js) {
        this.php_js = {};
    }

    if (tokens === undefined) {
        tokens = str;
        str = this.php_js.strtokleftOver;
    }
    if (str.length === 0) {
        return false;
    }
    if (tokens.indexOf(str[0]) !== -1) {
        return this.strtok(str.substr(1), tokens);
    }
    for (var i=0; i < str.length; i++) {
        if (tokens.indexOf(str[i]) !== -1) {
            break;
        }
    }
    this.php_js.strtokleftOver = str.substr(i+1);
    return str.substring(0, i);
}

Fix recursive reference to use 'this' and don't store tokenization info on function.


const Report = require('./Report');
const Notification = require('./Notification');

async function Reporter( request, reply ) {
  // Params https://sites.google.com/a/webpagetest.org/docs/advanced-features/webpagetest-restful-apis
  const base = process.env.BASE || 'http://localhost:8080';
  const result = await new Report({
    k: process.env.WEB_PAGE_TEST_KEY || '', // k means KEY
    url: request.query.site,
    pingback: `${base}/verification/`,
  }).run();
  console.log(`Pinback: ${base}/verification/?hipchat=${request.query.hipchat}`);

  // Set error as default.
  let notificationOpts = {
    status: 'Error',
    description: `There was an error proccesing ${request.query.site}`,
    room: request.query.hipchat,
    url: request.query.site,
  }

  // Update notificationOptions if was a success
  if ( 'statusCode' in result && result.statusCode === 200 ) {
    notificationOpts = Object.assign({}, notificationOpts, {
      status: 'Started',
      description: `The performance tests for ${request.query.site} has started.`,
      url: result.data.userUrl,
    });
  }
  const notificationResult = await Notification(notificationOpts);
  return reply(notificationResult);
}

module.exports = Reporter;

const Report = require('./Report');
const Notification = require('./Notification');

async function Reporter( request, reply ) {
  // Params https://sites.google.com/a/webpagetest.org/docs/advanced-features/webpagetest-restful-apis
  const base = process.env.BASE || 'http://localhost:8080';
  const pinback = `${base}/verification/${request.query.hipchat}/`;
  const result = await new Report({
    k: process.env.WEB_PAGE_TEST_KEY || '', // k means KEY
    url: request.query.site,
    pingback: pinback,
  }).run();
  console.log(`Pinback: ${pinback}`);

  // Set error as default.
  let notificationOpts = {
    status: 'Error',
    description: `There was an error proccesing <a href="${request.query.site}">${request.query.site}</a>`,
    room: request.query.hipchat,
    url: request.query.site,
  }

  // Update notificationOptions if was a success
  console.log('Response from API', result);
  if ( 'statusCode' in result && result.statusCode === 200 ) {
    let { data } = result;
    notificationOpts = Object.assign({}, notificationOpts, {
      status: 'Started',
      description: `The performance tests for <a href="${request.query.site}">${request.query.site}</a> has started. (<a href="${data.userUrl}">Click for more details or the title).</a>`,
      url: data.userUrl,
    });
  }
  const notificationResult = await Notification(notificationOpts);
  return reply(notificationResult);
}

module.exports = Reporter;

Update pinback URL and reporter message


import compose from './compose'

/**
 * Creates a store enhancer that applies middleware to the dispatch method
 * of the Redux store. This is handy for a variety of tasks, such as expressing
 * asynchronous actions in a concise manner, or logging every action payload.
 *
 * See `redux-thunk` package as an example of the Redux middleware.
 *
 * Because middleware is potentially asynchronous, this should be the first
 * store enhancer in the composition chain.
 *
 * Note that each middleware will be given the `dispatch` and `getState` functions
 * as named arguments.
 *
 * @param {...Function} middlewares The middleware chain to be applied.
 * @returns {Function} A store enhancer applying the middleware.
 */
export default function applyMiddleware(...middlewares) {
  return (next) => (reducer, initialState) => {
    var store = next(reducer, initialState)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

import compose from './compose'

/**
 * Creates a store enhancer that applies middleware to the dispatch method
 * of the Redux store. This is handy for a variety of tasks, such as expressing
 * asynchronous actions in a concise manner, or logging every action payload.
 *
 * See `redux-thunk` package as an example of the Redux middleware.
 *
 * Because middleware is potentially asynchronous, this should be the first
 * store enhancer in the composition chain.
 *
 * Note that each middleware will be given the `dispatch` and `getState` functions
 * as named arguments.
 *
 * @param {...Function} middlewares The middleware chain to be applied.
 * @returns {Function} A store enhancer applying the middleware.
 */
export default function applyMiddleware(...middlewares) {
  return (createStore) => (reducer, initialState) => {
    var store = createStore(reducer, initialState)
    var dispatch = store.dispatch
    var chain = []

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

Change next to createStore for better readability


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

// TODO: browserfy var wgf = require('wgf')

if (location.hash) {
  var hashParams = location.hash.split('?')[1]
  CURRENT_LANGUAGE = hashParams.split('=')[1]
}

document.addEventListener(
  'DOMContentLoaded',
  function () {
    // TODO: make path to root relative
    wgf.listCards({rootPath: '', preferredLanguage: CURRENT_LANGUAGE})
      .then(wgf.getDeck)
      .then(
        wgf.attachNextCard,
        function (error) {
          console.error('Failed to load the deck.', error)
        })
  })

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

// TODO: browserfy var wgf = require('wgf')

if (location.hash) {
  var hashParams = location.hash.split('?')[1]
  CURRENT_LANGUAGE = hashParams.split('=')[1]
}

document.addEventListener(
  'DOMContentLoaded',
  function () {
    // TODO: make path to root relative
    wgf.listCards({rootPath: '', preferredLanguage: CURRENT_LANGUAGE})
      .then(wgf.getDeck)
      .then(wgf.attachNextCard)
      .catch(
        function (error) {
          console.error('Failed to load the deck.\n', error, '\n', error.stack)
        })
  })

Add stack trace to promises output.


// Settings
$(document).ready(function() {

  // Commission percentage
  window.mybtcprice.commission = 15;

  // Allow user to change commission?
  window.mybtcprice.commission_locked = false;

});

// Settings
$(document).ready(function() {

  // Commission percentage
  window.mybtcprice.commission = 13;

  // Allow user to change commission?
  window.mybtcprice.commission_locked = true;

});

Change calcualtion formula and premium to 13%


const {expect} = require('chai');

const s = require('../lib/spec');

const {isInteger} = s.utils;

describe('Test the form function', () => {
    before(() => {
        s.def('::a', isInteger);
    });

    it('should throw an error if spec doesn\'t exist', () => {
        expect(() => s.form('::foobar')).to.throw(Error, /Unable to resolve spec/);
    });
});

const {expect} = require('chai');

const s = require('../lib/spec');

const {isInteger} = s.utils;

describe('Test the form function', () => {
    before(() => {
        s.def('::a', isInteger);
    });

    it('should return the form', () => {
        expect(s.form('::a')).to.eql([]);
    });

    it('should throw an error if spec doesn\'t exist', () => {
        expect(() => s.form('::foobar')).to.throw(Error, /Unable to resolve spec/);
    });
});

Create additional (dummy) test to fix test coverage


(function (ng, app) {
    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider.state('it-system.usage.contracts', {
            url: '/contracts',
            templateUrl: 'partials/it-system/tab-contracts.html',
            controller: 'system.EditContracts',
            resolve: {
            }
        });
    }]);

    app.controller('system.EditContracts', ['$scope', '$state', '$stateParams', '$timeout', 'itSystemUsage',
        function ($scope, $state, $stateParams, $timeout, itSystemUsage) {
            $scope.reload = function() {
                reload(); // OMG HACK! TODO refactor! This is to wait for the autosave to finish then reload the view to reflect the change
            }

            // work around for $state.reload() not updating scope
            // https://github.com/angular-ui/ui-router/issues/582
            function reload() {
                return $state.transitionTo($state.current, $stateParams, {
                    reload: true
                }).then(function () {
                    $scope.hideContent = true;
                    return $timeout(function () {
                        return $scope.hideContent = false;
                    }, 1);
                });
            };
        }]);
})(angular, app);

(function (ng, app) {
    app.config(['$stateProvider', function ($stateProvider) {
        $stateProvider.state('it-system.usage.contracts', {
            url: '/contracts',
            templateUrl: 'partials/it-system/tab-contracts.html',
            controller: 'system.EditContracts',
            resolve: {
            }
        });
    }]);

    app.controller('system.EditContracts', ['$scope', '$state', '$stateParams', '$timeout', 'itSystemUsage',
        function ($scope, $state, $stateParams, $timeout, itSystemUsage) {
            $scope.reload = function() {
                $timeout(reload, 1000); // OMG HACK! TODO refactor! This is to wait for the autosave to finish then reload the view to reflect the change
            }

            // work around for $state.reload() not updating scope
            // https://github.com/angular-ui/ui-router/issues/582
            function reload() {
                return $state.transitionTo($state.current, $stateParams, {
                    reload: true
                }).then(function () {
                    $scope.hideContent = true;
                    return $timeout(function () {
                        return $scope.hideContent = false;
                    }, 1);
                });
            };
        }]);
})(angular, app);

Put a timer on reload to wait for autosave to finish


/**
 * Grunt-autoprefixer
 * @description Autoprefixer parses CSS and adds vendor-prefixed CSS properties using the Can I Use database.
 * @docs https://github.com/nDmitry/grunt-autoprefixer
 */

var config = require('../Config'),
	sassTaskConfig = require('./sass');

module.exports = {
	options: {
		browsers: config.project.browserSupport
	},
	css: {
		src: config.Sass.paths.distDir + '/*.css'
	}
};

/**
 * Grunt-autoprefixer
 * @description Autoprefixer parses CSS and adds vendor-prefixed CSS properties using the Can I Use database.
 * @docs https://github.com/nDmitry/grunt-autoprefixer
 */

var config = require('../Config');

module.exports = {
	options: {
		browsers: config.project.browserSupport
	},
	css: {
		src: config.Sass.paths.distDir + '/*.css'
	}
};

Remove an unnecessary file import of the sass config


var arrayContainsObject = require('./array-contains-object');
var collisionObstacles = [];
var Jump = require('./../jump');
var hypotenuse = require('./hypotenuse');

var isColliding = function(skier, obstacle) {
  if (hypotenuse(skier, obstacle) < skier.width && obstacle instanceof Jump) {

  } else if (hypotenuse(skier, obstacle) < skier.width && skier.jumping === false) {
    crashed(skier, obstacle, collisionObstacles);
  }
};

function crashed(skier, obstacle, collisionObstacles) {
  skier.crashed = true;
  if (arrayContainsObject(obstacle, collisionObstacles) === false) {
    collisionObstacles.push(obstacle);
    skier.lives -= 1;
  }
  document.onkeydown=function(){
    skier.crashed = false;
  };
}

function jump(skier) {
  skier.jumping = true;
  if (cancelableStateTimeout) {
    clearTimeout(cancelableStateTimeout);
  }
  var cancelableStateTimeout = setTimeout(function() {
    skier.jumping = false;
  }, 2000);
}

module.exports = isColliding;

var arrayContainsObject = require('./array-contains-object');
var collisionObstacles = [];
var Jump = require('./../jump');
var hypotenuse = require('./hypotenuse');

var isColliding = function(skier, obstacle) {
  if (hypotenuse(skier, obstacle) < skier.width && obstacle instanceof Jump) {
    jump(skier);
  } else if (hypotenuse(skier, obstacle) < skier.width && skier.jumping === false) {
    crashed(skier, obstacle, collisionObstacles);
  }
};

function crashed(skier, obstacle, collisionObstacles) {
  skier.crashed = true;
  if (arrayContainsObject(obstacle, collisionObstacles) === false) {
    collisionObstacles.push(obstacle);
    skier.lives -= 1;
  }
  document.onkeydown=function(){
    skier.crashed = false;
  };
}

function jump(skier) {
  skier.jumping = true;
  if (cancelableStateTimeout) {
    clearTimeout(cancelableStateTimeout);
  }
  var cancelableStateTimeout = setTimeout(function() {
    skier.jumping = false;
  }, 2000);
}

module.exports = isColliding;

Add actual call to the jumping function.


/**
 * @type {Object}
 */
function WebGLDebugUtils() {}

/**
 * @param {string} functionName the name of the WebGL function.
 * @param {number} args The arguments.
 * @return {string} The arguments as a string.
 */
WebGLDebugUtils.glFunctionArgsToString = function(functionName, args) {};

Add an extern for WebGLDebugUtils.glFunctionArgsToString


export default function configure(element, userOptions, defaultOptions) {
  return Object.keys(defaultOptions).reduce((options, key) => {
    const initial = defaultOptions[key];
    const attrValue = element.getAttribute(`data-${key.toLowerCase()}`);

    // eslint-disable-next-line no-param-reassign
    options[key] = attrValue || userOptions[key] || initial;

    return options;
  }, {});
}

export default function configure(element, userOptions, defaultOptions) {
  return Object.keys(defaultOptions).reduce((options, key) => {
    const attrValue = element.getAttribute(`data-${key.toLowerCase()}`);

    // eslint-disable-next-line no-param-reassign
    options[key] = attrValue || userOptions[key] || defaultOptions[key];

    return options;
  }, {});
}

Remove redundant variable to simplify the code


// @flow

import styles from './InterestGroup.css';
import React from 'react';
import InterestGroupComponent from './InterestGroup';
import Button from 'app/components/Button';
import { Content } from 'app/components/Content';
import { Link } from 'react-router';
import NavigationTab, { NavigationLink } from 'app/components/NavigationTab';
import type { InterestGroup } from 'app/models';

export type Props = {
  interestGroups: Array<InterestGroup>,
  loggedIn: boolean
};

const InterestGroupList = (props: Props) => {
  const groups = props.interestGroups.map((group, key) => (
    <InterestGroupComponent group={group} key={key} />
  ));
  const showCreate = props.loggedIn;
  return (
    <Content>

          <NavigationTab title="Interessegrupper">
            <NavigationLink to="">
               Hjem
            </NavigationLink>
          </NavigationTab>

            Her finner du all praktisk informasjon knyttet til
            våre interessegrupper.

          {showCreate && (
            <Link to="/interestgroups/create" className={styles.link}>
              <Button>Lag ny interessegruppe</Button>
            </Link>
          )}

{groups}

    </Content>
  );
};

export default InterestGroupList;

// @flow

import styles from './InterestGroup.css';
import React from 'react';
import InterestGroupComponent from './InterestGroup';
import Button from 'app/components/Button';
import { Content } from 'app/components/Content';
import { Link } from 'react-router';
import NavigationTab, { NavigationLink } from 'app/components/NavigationTab';
import type { InterestGroup } from 'app/models';

export type Props = {
  interestGroups: Array<InterestGroup>,
  loggedIn: boolean
};

const InterestGroupList = (props: Props) => {
  const groups = props.interestGroups.map((group, key) => (
    <InterestGroupComponent group={group} key={key} />
  ));
  const showCreate = props.loggedIn;
  return (
    <Content>

          <NavigationTab title="Interessegrupper">
            <NavigationLink to="">
               Hjem
            </NavigationLink>
          </NavigationTab>

            <Link to="/pages/info/39-praktisk-informasjon">Her</Link> finner du
            all praktisk informasjon knyttet til våre interessegrupper.

          {showCreate && (
            <Link to="/interestgroups/create" className={styles.link}>
              <Button>Lag ny interessegruppe</Button>
            </Link>
          )}

{groups}

    </Content>
  );
};

export default InterestGroupList;

Add link to interest group info page


/**
 * Created by unleet on 11/2/13.
 */

/**
 * A 12-factor friendly configuration manager.
 * Every setting the Turnpike framework keeps track of is given a default value here.
 * These values can be overridden in your project's config.json file, and can also
 * finally be overridden with environment variables. In all cases, a matching environment
 * variable should take precendence over any other way a setting can be specified.
 */

var _ = require('underscore');
var config = {
  testing: false,
  port: 1337
};

var load = function(localConfig) {
  _(config).extend(localConfig);
  env_vars();
}

var env_vars = function() {

}

module.exports = config;

Add some basics to get the server going enough for further testing.


import html from "innerself";
import Scene from "./Scene";
import { SCENE_LEVELS, SCENE_FIND, SCENE_NOPASS } from "./actions"

function LevelScore(score, idx) {
  return html`

       ${score}

  `;
}

export default function LevelSelect({results}) {
  const total = results.reduce((acc, cur) => acc + cur, 0);
  const average = Math.floor(total / results.length);
  // An inverted hyperbola with lim(x → ∞) = 1.
  const threshold = 100 * (1 - 2.5 / results.length);

  return Scene(
    {id: SCENE_LEVELS, from: "#000", to: "#000"},
    html`

          ${results.map(LevelScore)}
          ${ average > threshold
            ? `
next
`
            : `
…?
`
           }

`
  );
}

import html from "innerself";
import Scene from "./Scene";
import { SCENE_LEVELS, SCENE_FIND, SCENE_NOPASS } from "./actions"

function LevelScore(score, idx) {
  return html`

       ${score}

  `;
}

export default function LevelSelect({results}) {
  // This block assumes results has at least one item. The IntroScreen ensures
  // the user doesn't get here without any results.
  const total = results.reduce((acc, cur) => acc + cur);
  const average = Math.floor(total / results.length);
  // An inverted hyperbola with lim(x → ∞) = 1. Levels 2 and 3 are always
  // available. Level 4 requires an average of 0.33. Level 5 requires an
  // average of 0.5, etc.
  const threshold = 100 * (1 - 2 / results.length);

  return Scene(
    {id: SCENE_LEVELS, from: "#000", to: "#000"},
    html`

          ${results.map(LevelScore)}
          ${ average > threshold
            ? `
next
`
            : `
…?
`
           }

`
  );
}

Raise the treshold for levels 4+


export default
    function LoadConfig($log, $rootScope, $http, Store) {
        return function() {

            var configSettings = {};

            var configInit = function() {
                // Auto-resolving what used to be found when attempting to load local_setting.json
                if ($rootScope.loginConfig) {
                    $rootScope.loginConfig.resolve('config loaded');
                }
                $rootScope.$emit('ConfigReady');

                // Load new hardcoded settings from above

                global.$AnsibleConfig = configSettings;
                Store('AnsibleConfig', global.$AnsibleConfig);
                $rootScope.$emit('LoadConfig');
            };

            // Retrieve the custom logo information - update configSettings from above
            $http({
                method: 'GET',
                url: '/api/',
            })
                .success(function(response) {
                    if(response.custom_logo) {
                        configSettings.custom_logo = true;
                        $rootScope.custom_logo = response.custom_logo;
                    } else {
                        configSettings.custom_logo = false;
                    }

                    if(response.custom_login_info) {
                        configSettings.custom_login_info = response.custom_login_info;
                        $rootScope.custom_login_info = response.custom_login_info;
                    } else {
                        configSettings.custom_login_info = false;
                    }

                    configInit();

                }).catch(({error}) => {
                    $log.debug(error);
                    configInit();
                });

        };
    }

LoadConfig.$inject =
    [   '$log', '$rootScope', '$http',
        'Store'
    ];

export default
    function LoadConfig($log, $rootScope, $http, Store) {
        return function() {

            var configSettings = {};

            var configInit = function() {
                // Auto-resolving what used to be found when attempting to load local_setting.json
                if ($rootScope.loginConfig) {
                    $rootScope.loginConfig.resolve('config loaded');
                }
                $rootScope.$emit('ConfigReady');

                // Load new hardcoded settings from above

                global.$AnsibleConfig = configSettings;
                Store('AnsibleConfig', global.$AnsibleConfig);
                $rootScope.$emit('LoadConfig');
            };

            // Retrieve the custom logo information - update configSettings from above
            $http({
                method: 'GET',
                url: '/api/',
            })
                .then(function({data}) {
                    if({data}.custom_logo) {
                        configSettings.custom_logo = true;
                        $rootScope.custom_logo = {data}.custom_logo;
                    } else {
                        configSettings.custom_logo = false;
                    }

                    if({data}.custom_login_info) {
                        configSettings.custom_login_info = {data}.custom_login_info;
                        $rootScope.custom_login_info = {data}.custom_login_info;
                    } else {
                        configSettings.custom_login_info = false;
                    }

                    configInit();

                }).catch(({error}) => {
                    $log.debug(error);
                    configInit();
                });

        };
    }

LoadConfig.$inject =
    [   '$log', '$rootScope', '$http',
        'Store'
    ];

Change success to then manually


import React from 'react';

const styles = {
  width: 200,
  height: 200,
  border: '1px solid cyan',
  position: 'relative',
};

export default ({ children }) => ({
  render() {
    return (

{children}

    );
  }
});

import React from 'react';

const styles = {
  width: 200,
  height: 200,
  border: '1px solid cyan',
  position: 'relative',
};

export default ({ children }) => (

{children}

);

Fix stateless component. cc @catalinmiron


'use strict';

var path          = require('path')
  , createContext = require('vm').createContext
  , isFunction    = require('es5-ext/lib/Function/is-function')
  , ba2p          = require('deferred/lib/async-to-promise').bind
  , findRoot      = ba2p(require('next/lib/find-package-root'))
  , requireSilent = require('next/lib/require-silent')(require);

module.exports = function (lpath, tpath) {
	tpath = path.dirname(tpath);
	return findRoot(tpath)
	(function (root) {
		var c;
		while (true) {
			c = requireSilent(tpath + '/__tad.js');
			if (c) {
				if (c instanceof Error) {
					return c;
				} else if (c.context) {
					c = c.context;
					if (isFunction(c)) {
						c = c(lpath);
					}
					return createContext(c);
				}
			}
			if (tpath === root) {
				return global;
			}
			tpath = path.dirname(tpath);
		}
	});
};

'use strict';

var path          = require('path')
  , createContext = require('vm').createContext
  , isFunction    = require('es5-ext/lib/Function/is-function')
  , ba2p          = require('deferred/lib/async-to-promise').bind
  , findRoot      = ba2p(require('next/lib/find-package-root'))
  , requireFirst  = require('next/lib/require-silent')(
		require('next/lib/require-first-in-tree'));

module.exports = function (lpath, tpath) {
	tpath = path.dirname(tpath);
	return findRoot(tpath)
	(function (root) {
		var c = requireFirst('__tad', tpath, root);
		if (c) {
			if (c instanceof Error) {
				return c;
			} else if (c.context) {
				c = c.context;
				if (isFunction(c)) {
					c = c(lpath);
				}
				return createContext(c);
			}
		}
		return global;
	});
};

Use requireFirstInTree from node-ext package


module.exports = {
    API_HOST: JSON.stringify(process.env.API_HOST || 'http://api-staging.scratch.mit.edu')
};

module.exports = {
    API_HOST: JSON.stringify(process.env.API_HOST || 'https://api-staging.scratch.mit.edu')
};

Use SSL for the default API


function StatsWriter() {
  this.result = {
    element: 0,
    text: 0,
    attribute: 0
  };
}

StatsWriter.prototype.beginOpenElement = function(name) {
  this.result.element += 1;
}

StatsWriter.prototype.attribute = function(name, value) {
  this.result.attribute += 1;
}

StatsWriter.prototype.endOpenElement = function() {
}

StatsWriter.prototype.closeElement = function(name) {
}

StatsWriter.prototype.text = function(text) {
  this.result.text += 1;
}

StatsWriter.prototype.comment = function(comment) {
}

StatsWriter.prototype.getHTML = function() {
  return "elements: " + this.result.element + "\ntext segments: " + this.result.text + "\nattributes: " + this.result.attribute + "\n";
}

module.exports = StatsWriter;

function StatsWriter() {
  this.result = {
    element: 0,
    text: 0,
    attribute: 0,
    elements: {}
  };
}

StatsWriter.prototype.beginOpenElement = function(name) {
  this.result.element += 1;
  if (!(name in this.result.elements)) {
    this.result.elements[name] = 0;
  }
  this.result.elements[name] += 1;
}

StatsWriter.prototype.attribute = function(name, value) {
  this.result.attribute += 1;
}

StatsWriter.prototype.endOpenElement = function() {
}

StatsWriter.prototype.closeElement = function(name) {
}

StatsWriter.prototype.text = function(text) {
  this.result.text += 1;
}

StatsWriter.prototype.comment = function(comment) {
}

StatsWriter.prototype.getHTML = function() {
  var result = "elements: " + this.result.element + "\n"
  for (var element in this.result.elements) {
    result += '\t' + element + ': ' + this.result.elements[element] + '\n';
  }
  result += "text segments: " + this.result.text + "\nattributes: " + this.result.attribute + "\n";
  return result;
}

module.exports = StatsWriter;

Add per-element breakdown to stats.


/**

 Copyright 2015 Covistra Technologies Inc.

 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 _ = require('lodash'),
    Boom = require('boom'),
    P = require('bluebird');

module.exports = function(server, log) {

    return function(collection, fields) {
        log.debug("Checking uniqueness in collection %s", collection, fields);

        var db = server.plugins['covistra-mongodb'].MAIN;

        var coll = db.collection(collection);

        var q = {$or:[]};

        _.each(_.keys(fields), function(key) {
            var o = {};
            o[key] = fields[key];
            q.$or.push(o);
        });

        return P.promisify(coll.findOne, coll)(q).then(function(existing) {
            if(existing) {
                throw Boom.badRequest("username and email must be unique", fields);
            }
            else
                return true;
        });
    }
};

/**

 Copyright 2015 Covistra Technologies Inc.

 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 _ = require('lodash'),
    Boom = require('boom'),
    P = require('bluebird');

module.exports = function(server, log) {

    return function(dbName, collection, fields) {
        log.debug("Checking uniqueness in collection %s", collection, fields);

        var db = server.plugins['covistra-mongodb'][dbName || 'MAIN'];

        var coll = db.collection(collection);

        var q = {$or:[]};

        _.each(_.keys(fields), function(key) {
            var o = {};
            o[key] = fields[key];
            q.$or.push(o);
        });

        return P.promisify(coll.findOne, coll)(q).then(function(existing) {
            if(existing) {
                throw Boom.badRequest("username and email must be unique", fields);
            }
            else
                return true;
        });
    }
};

Make sure we provide which database to make the unique check


// allow to require('riot')
var riot = module.exports = require(process.env.RIOT || require('path').resolve(__dirname, '../../riot'))

var compiler = require('riot-compiler')

// allow to require('riot').compile
riot.compile = compiler.compile
riot.parsers = compiler.parsers

// allow to require('some.tag')
require.extensions['.tag'] = function(module, filename) {
  var src = riot.compile(require('fs').readFileSync(filename, 'utf8'))
  module._compile(
    'var riot = require(process.env.RIOT || "riot/riot.js");module.exports =' + src
  , filename)
}

// simple-dom helper
var sdom = require('./sdom')

function createTag(tagName, opts) {
  var root = document.createElement(tagName),
    tag = riot.mount(root, opts)[0]
  return tag
}

riot.render = function(tagName, opts) {
  var tag = createTag(tagName, opts),
    html = sdom.serialize(tag.root)
  // unmount the tag avoiding memory leaks
  tag.unmount()
  return html
}

riot.render.dom = function(tagName, opts) {
  return createTag(tagName, opts).root
}

// allow to require('riot')
var riot = module.exports = require(process.env.RIOT || require('path').resolve(__dirname, '../../riot'))

var compiler = require('riot-compiler')

// allow to require('riot').compile
riot.compile = compiler.compile
riot.parsers = compiler.parsers

// allow to require('some.tag')
require.extensions['.tag'] = function(module, filename) {
  var src = riot.compile(require('fs').readFileSync(filename, 'utf8'))
  module._compile(
    'var riot = require(process.env.RIOT || "riot/riot.js");module.exports =' + src
  , filename)
}

// simple-dom helper
var sdom = require('./sdom')

riot.render = function(tagName, opts) {
  var tag = riot.render.tag(tagName, opts),
    html = sdom.serialize(tag.root)
  // unmount the tag avoiding memory leaks
  tag.unmount()
  return html
}

riot.render.dom = function(tagName, opts) {
  return riot.render.tag(tagName, opts).root
}

riot.render.tag = function(tagName, opts) {
  var root = document.createElement(tagName),
    tag = riot.mount(root, opts)[0]
  return tag
}

Add riot.render.tag function to create raw tag


const isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0))
const event = isTouch ? 'touchstart' : 'click'

const directive = {
  instances: []
}

directive.onEvent = function (event) {
  directive.instances.forEach(({ el, fn }) => {
    if (event.target !== el && !el.contains(event.target)) {
      fn && fn(event)
    }
  })
}

directive.bind = function (el) {
  directive.instances.push({ el, fn: null })
  if (directive.instances.length === 1) {
    document.addEventListener(event, directive.onEvent)
  }
}

directive.update = function (el, binding) {
  if (typeof binding.value !== 'function') {
    throw new Error('Argument must be a function')
  }
  const instance = directive.instances.find(i => i.el === el)
  instance.fn = binding.value
}

directive.unbind = function (el) {
  const instanceIndex = directive.instances.findIndex(i => i.el === el)
  directive.instances.splice(instanceIndex, 1)
  if (directive.instances.length === 0) {
    document.removeEventListener(event, directive.onEvent)
  }
}

export default directive

const isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0))
const event = isTouch ? 'touchstart' : 'click'

const directive = {
  instances: []
}

directive.onEvent = function (event) {
  directive.instances.forEach(({ el, fn }) => {
    if (event.target !== el && !el.contains(event.target)) {
      fn && fn(event)
    }
  })
}

directive.bind = function (el, binding) {
  directive.instances.push({ el, fn: binding.value })
  if (directive.instances.length === 1) {
    document.addEventListener(event, directive.onEvent)
  }
}

directive.update = function (el, binding) {
  if (typeof binding.value !== 'function') {
    throw new Error('Argument must be a function')
  }
  const instance = directive.instances.find(i => i.el === el)
  instance.fn = binding.value
}

directive.unbind = function (el) {
  const instanceIndex = directive.instances.findIndex(i => i.el === el)
  directive.instances.splice(instanceIndex, 1)
  if (directive.instances.length === 0) {
    document.removeEventListener(event, directive.onEvent)
  }
}

export default directive

Fix outside click when no update event were fired on component


'use strict';

var slice   = Array.prototype.slice
  , toArray = require('es5-ext/lib/Object/prototype/to-array');

module.exports = function (fn, scope, args, resolve) {
	fn.apply(scope, toArray.call(args).concat(function (error, result) {
		if (error == null) {
			resolve((arguments.length > 2) ? slice.call(arguments, 1) : result);
		} else {
			resolve(error);
		}
	}));
};

'use strict';

var slice   = Array.prototype.slice
  , toArray = require('es5-ext/lib/Object/prototype/to-array');

module.exports = function (fn, scope, args, resolve) {
	return fn.apply(scope, toArray.call(args).concat(function (error, result) {
		if (error == null) {
			resolve((arguments.length > 2) ? slice.call(arguments, 1) : result);
		} else {
			resolve(error);
		}
	}));
};

Apply function should return a value


var React = require('react');
var ReactDOM = require('react-dom');

var Hi = React.createClass({
    render : function() {
        return (

Hi {this.props.name}.

        );
    }
});
ReactDOM.render(
    <Hi name="kidchenko"/>,
    document.getElementById('app')
);

var React = require('react');
var ReactDOM = require('react-dom');

var ShowList = React.createClass({
    render: function() {
        var listItems = this.props.friends.map(function(friend) {
            return
 {friend}

        });
        return (

Friends

                    {listItems}

        );
    }
});

var FriendsContainer = React.createClass({
    render : function() {
        var name = 'kidchenko';
        var friendList = ['Aspira', 'Weslin', 'Clecin']
        return (

                Hi {name}.
                <ShowList friends={friendList} />

        );
    }
});

ReactDOM.render(
    <FriendsContainer />,
    document.getElementById('app')
);

Add more advanced compoent using props


$(document).ready(function() {
    var form = document.getElementById('inner-form');
    var interface_type = document.getElementsByName('interface_type');
    var static_form = document.getElementById('static-form');
    var static_clone = static_form.cloneNode(true);
    static_clone.id ="static_clone";
    $(static_clone).removeAttr('style');
    var dynamic_form = document.getElementById('dynamic-form');
    var dynamic_clone = dynamic_form.cloneNode(true);
    dynamic_clone.id ="static_clone";
    $(dynamic_clone).removeAttr('style');
    for(var i = 0; i < interface_type.length; i++) {
        if (interface_type[i].checked) {
            if (form.lastChild.textContent != '') {
                form.removeChild(form.childNodes[form.childNodes.length -1]);
            };
            if (interface_type[i].value =='Static') {
                form.appendChild(static_clone);
            } else {
                form.appendChild(dynamic_clone);
            };
        };
        interface_type[i].onclick = function() {
            if (form.lastChild.textContent != '') {
                form.removeChild(form.childNodes[form.childNodes.length -1]);
            };
            if (this.value =='Static') {
                form.appendChild(static_clone);
            } else {
                form.appendChild(dynamic_clone);
            };
        };
    };
});

$(document).ready(function() {
    var form = document.getElementById('inner-form');
    var interface_type = document.getElementsByName('interface_type');
    var static_form = document.getElementById('static-form');
    var static_clone = static_form.cloneNode(true);
    static_clone.id ="static_clone";
    $(static_clone).removeAttr('style');
    var dynamic_form = document.getElementById('dynamic-form');
    var dynamic_clone = dynamic_form.cloneNode(true);
    dynamic_clone.id ="static_clone";
    $(dynamic_clone).removeAttr('style');
    for(var i = 0; i < interface_type.length; i++) {
        if (interface_type[i].checked) {
            if (form.lastChild.textContent != '') {
                form.removeChild(form.childNodes[form.childNodes.length -1]);
            };
            if (interface_type[i].value =='static_interface') {
                form.appendChild(static_clone);
            } else {
                form.appendChild(dynamic_clone);
            };
        };
        interface_type[i].onclick = function() {
            if (form.lastChild.textContent != '') {
                form.removeChild(form.childNodes[form.childNodes.length -1]);
            };
            if (this.value =='static_interface') {
                form.appendChild(static_clone);
            } else {
                form.appendChild(dynamic_clone);
            };
        };
    };
});

Fix augmented system form interface type selection


module.exports = require('./jslint-linter');
module.exports.create = function(options) {
  if (!options) { throw new TypeError('options is required (at least an empty object)'); }
  return Object.create(this, {
    options: { value: options },
    linter: { value: { check: require('../vendor/jshint').JSHINT } }
  });
};

module.exports = require('./jslint-linter');
module.exports.create = function (options) {
  if (!options) { throw new TypeError('options is required (at least an empty object)'); }
  return Object.create(this, {
    options: { value: options },
    linter: { value: { check: require('../vendor/jshint').JSHINT } }
  });
};

Fix missing space between function and (


'use strict';
import React from 'react';

const DPCLogo = () => (
  <svg
    width="570px"
    height="275px"
    style={{
      background: 'rgba(79, 152, 201, 0.75)',
      letterSpacing: '3px'
    }}>
    <text
      x="50%"
      y="52.5%"
      textAnchor="middle"
      style={{
        font: 'bold 100px/110px Georgia, sans-serif',
        fill: '#FFF',
        textAlign: 'center'
      }}>DPC</text>
    <text
      x="50%"
      y="72.5%"
      textAnchor="middle"
      fill="#FFF"
      style={{
        font: 'small-caps lighter 35px/35px Georgia, sans-serif',
        stroke: 'none',
        textAlign: 'center'
      }}>Davie Poplar Capital</text>
    <line
      x1="135px"
      y1="60%"
      x2="435px"
      y2="60%"
      style={{
        stroke: '#FFF',
        strokeWidth: '1'
      }} />
    <line
      x1="135px"
      y1="77.5%"
      x2="435px"
      y2="77.5%"
      style={{
        stroke: '#FFF',
        strokeWidth: '1'
      }} />
  </svg>
);

export default DPCLogo;

// Oh no! Your browser does not support inline SVG elements. Maybe try Chrome.

'use strict';
import React from 'react';

const DPCLogo = () => (
  <svg
    className="DPC-logo"
    version="1.1"
    xmlns="http://www.w3.org/2000/svg">
    <text
      data-section="logo-head"
      x="50%"
      y="52.5%">
      DPC
    </text>
    <text
      data-section="logo-sub"
      x="50%"
      y="72.5%">
      Davie Poplar Capital
    </text>
    <line
      x1="135px"
      y1="60%"
      x2="435px"
      y2="60%" />
    <line
      x1="135px"
      y1="77.5%"
      x2="435px"
      y2="77.5%" />
  </svg>
);

export default DPCLogo;

// Oh no! Your browser does not support inline SVG elements. Maybe try Chrome.

Remove all inline styles and delegate to the _svg Sass partial