var marked = require('marked');
var fs = require('fs');

var markedRenderer = new marked.Renderer();

marked.setOptions({
    renderer: markedRenderer,
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: false
});

// override renderer
markedRenderer.table = function(header, body) {
    return '
\n'
        + '
\n'
        + header
        + '
\n'
        + '
\n'
        + body
        + '
\n'
        + '
\n';
}

// helper function for converting markdown to html string
function convertMarkdown(file, callback) {
    // read md file
    fs.open(file, 'r', function(err, fd) {
        if (err) return callback(err);

        // convert
        fs.readFile(fd, 'utf8', (err, mdString) => {
            if (err) return callback(err);
            return marked(mdString, callback);
        });
    });
}

module.exports = convertMarkdown;

var marked = require('marked');
var fs = require('fs');

var markedRenderer = new marked.Renderer();

marked.setOptions({
    renderer: markedRenderer,
    gfm: true,
    tables: true,
    breaks: false,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: false
});

// override renderer
markedRenderer.table = function(header, body) {
    return '
\n'
        + '
\n'
        + header
        + '
\n'
        + '
\n'
        + body
        + '
\n'
        + '
\n';
}

markedRenderer.heading = function(text, level) {
    var escapedText = text.toLowerCase().replace(/[^\w,\u1100-\u11FF,\u3130-\u318F,\uAC00-\uD7AF]+/g, '-');

    return '<h' + level + '>' +
        text +
        '</h' + level + '>';
}

// helper function for converting markdown to html string
function convertMarkdown(file, callback) {
    // read md file
    fs.open(file, 'r', function(err, fd) {
        if (err) return callback(err);

        // convert
        fs.readFile(fd, 'utf8', (err, mdString) => {
            if (err) return callback(err);
            return marked(mdString, callback);
        });
    });
}

module.exports = convertMarkdown;

Support set anchor to header


"use strict";

function membershipFinder(schema, options) {
  schema.pre('init', function(next, data) {
    var queries = [];
    var query = {};
    query[options.field] = data._id;
    queries.push(query);
    queries.push({'member.@type': this.constructor.modelName, 'member.id': data._id});
    this.model('Membership').find({$or: queries}, function(err, docs) {
      if (err) {
        return next(err);
      }
      data.memberships = docs;
      next();
    });
  });
}

module.exports = membershipFinder;

"use strict";

/**
 * Find memberships that are associated with the current object and
 * populate them. This is necessary because memberships are stored in
 * a separate collections to people and organizations, but it makes
 * sense to return them inline.
 *
 * @param {mongoose.Schema} schema The schema to augment with this plugin
 * @param {Object} options
 * @param {String} options.field The field to query against
 */
function membershipFinder(schema, options) {
  schema.pre('init', function(next, data) {
    var queries = [];
    var query = {};
    query[options.field] = data._id;
    queries.push(query);
    queries.push({'member.@type': this.constructor.modelName, 'member.id': data._id});
    this.model('Membership').find({$or: queries}, function(err, docs) {
      if (err) {
        return next(err);
      }
      data.memberships = docs;
      next();
    });
  });
}

module.exports = membershipFinder;

Document the membershipFinder mongoose plugin


import m from 'mithril';

export const Col = (el) => m('div.col', [el])

export class NewOptionForm {
	oninit(vnode) {
		vnode.state.newOption = {
			name: '',
			pattern: '',
			selector: '',
			enabled: true
		};
	}

	view(vnode) {
		const {
			name,
			pattern,
			selector,
			enabled
		} = vnode.state.newOption;

    return m('form', [
      m('div.row.p-3', [
	      Col(m('input.form-control', { type: 'text', placeholder: 'Name', value: name})),
	      Col(m('input.form-control', { type: 'text', placeholder: 'Pattern', value: pattern })),
	      Col(m('input.form-control', { type: 'text', placeholder: 'Selector (Optional)', value: selector })),
	      Col(m('div.form-check.form-check-inline', [
            m('label.form-check-label', [
	            m('input.form-check-input', { type: 'checkbox', checked: enabled }),
              'Enabled',
            ]),
          ])),
	      Col(m('button.btn.btn-primary', { type: 'button' }, '+')),
      ]),
    ]);
  }
}

import m from 'mithril';

export const validateForm = ({ name, pattern }) => Boolean(name && pattern);

export const Col = el => m('div.col', [el]);

export class NewOptionForm {
  oninit(vnode) {
    vnode.state.newOption = {
      name: '',
      pattern: '',
      selector: '',
      enabled: true,
    };
  }

  view(vnode) {
    const { name, pattern, selector, enabled } = vnode.state.newOption;

    return m('form', [
      m('div.row.p-3', [
        Col(
          m('input.form-control', {
            type: 'text',
            placeholder: 'Name',
            value: name,
          })
        ),
        Col(
          m('input.form-control', {
            type: 'text',
            placeholder: 'Pattern',
            value: pattern,
          })
        ),
        Col(
          m('input.form-control', {
            type: 'text',
            placeholder: 'Selector (Optional)',
            value: selector,
          })
        ),
        Col(
          m('div.form-check.form-check-inline', [
            m('label.form-check-label', [
              m('input.form-check-input', {
                type: 'checkbox',
                checked: enabled,
              }),
              'Enabled',
            ]),
          ])
        ),
        Col(
          m(
            'button.btn.btn-primary',
            { type: 'button', disabled: !validateForm(vnode.state.newOption) },
            '+'
          )
        ),
      ]),
    ]);
  }
}

Disable button if name & pattern are empty; prettify


// require('./Pad.js')

function DrawingAppCtrl($scope, socket, drawingPad) {
  console.log("starting");
  $socket = socket;
  $scope.message;
  $scope.messages = [];
  $scope.joined = false;
  $scope.username;

  drawingPad.initialize(socket);

  $scope.sendMsg = function (message) {
    $scope.messages.push(message);
    $scope.message = "";
    socket.emit('msg', {msg: message, name: $scope.username});
  }

  $scope.join = function (groupName) {
    $scope.joined = true;
    socket.emit('joinGroup', {name: groupName});
  }

  $scope.chooseUsername = function (name) {
    console.log("stuff");
    $scope.username = name;
    socket.emit('setUsername', {username: name});
  }

  // socket.on('joinRoom', function(newRoom) {

  // })

  socket.on('draw', function (data) {
    drawingPad.drawLineFrom( data.begin, data.end );
  });

  socket.on('addMsg', function (data) {
    console.log(data);
    $scope.messages.push(data);
  });

}

// require('./Pad.js')

function DrawingAppCtrl($scope, socket, drawingPad) {
  console.log("starting");
  $socket = socket;
  $scope.message;
  $scope.messages = [];
  $scope.joined = false;
  $scope.username;

  drawingPad.initialize(socket);

  $scope.sendMsg = function (message) {
    $scope.messages.push({msg: message, name: $scope.username});
    $scope.message = "";
    socket.emit('msg', {msg: message, name: $scope.username});
  }

  $scope.join = function (groupName) {
    $scope.joined = true;
    socket.emit('joinGroup', {name: groupName});
  }

  $scope.chooseUsername = function (name) {
    console.log("stuff");
    $scope.username = name;
    socket.emit('setUsername', {username: name});
  }

  // socket.on('joinRoom', function(newRoom) {

  // })

  socket.on('draw', function (data) {
    drawingPad.drawLineFrom( data.begin, data.end );
  });

  socket.on('addMsg', function (data) {
    console.log(data);
    $scope.messages.push(data);
  });

}

Fix bug with messages not showing up for the user that sends the message


import express from 'express';
import UserController from '../controllers/UserController';

const userRouter = express.Router();
userRouter.post('/api/user/signup', UserController.createUser());
userRouter.post('/api/user/signin', [
  UserController.validateRequest(),
  UserController.authenticateUser()
]);
userRouter.use('/api', [
  UserController.getClientAuthToken(),
  UserController.authorizeUser()
]);
userRouter.get('/api/user/:username', UserController.getUser());
userRouter.put('/api/user', UserController.updateUser());
userRouter.delete('/api/user', UserController.deleteUser());
userRouter.get('/api/user/groups', UserController.getUserGroups());

export default userRouter;

import express from 'express';
import UserController from '../controllers/UserController';

const userRouter = express.Router();
userRouter.post('/api/user/signup', UserController.createUser());
userRouter.post('/api/user/signin', [
  UserController.validateRequest(),
  UserController.authenticateUser()
]);
userRouter.use('/api', [
  UserController.getClientAuthToken(),
  UserController.authorizeUser()
]);
userRouter.route('/api/user')
.put('/api/user', UserController.updateUser())
.delete('/api/user', UserController.deleteUser());
userRouter.get('/api/user/groups', UserController.getUserGroups());
userRouter.get('/api/user/:username', UserController.getUser());

export default userRouter;

Write updateUser and deleteUser as one route


/* Generated with Sango, by Afero.io */

var Sango = {
   VERSION = "Sango © 2016,2017 Afero, Inc - Build 223";
}

module.exports = Sango;

/* Generated with Sango, by Afero.io */

var Sango = {
   VERSION = "Sango © 2016,2017 Afero, Inc - Build 228";
}

module.exports = Sango;

Update test results for js


var loaderUtils = require("loader-utils");

module.exports = function(source, map) {
    var query = loaderUtils.parseQuery(this.query);

    if (!query.uniquePrefix) {
        this.emitError("Missing loader parameter uniquePrefix");
        return;
    }

    this.cacheable();

    var r = query.uniquePrefix;
    if (r) r += '-';

    source = source.replace(/kwfUp-/g, r);

    if (source.match(/kwfLocal/)) {
        var p = this.resourcePath;
        p = p.replace(process.cwd()+'/', '');

        p = p.replace(/^commonjs\/views\//, '');
        p = p.replace(/^reactjs\/(components|layouts)\//, '');
        p = p.replace(/^components\/(.*?)\/backbone\/views\//, '');
        p = p.replace(/^components\/(.*?)\/reactjs\/(components|layouts)\//, '');
        p = p.replace(/\.underscore\.tpl$/, '');
        p = p.replace(/\.[a-z]+$/, '');
        p = p.replace(/\/(.)/g, m => {
            return m.toUpperCase();
        });
        p = p.replace(/\//g, '');

        p = r + p;
        source = source.replace(/kwfLocal/g, p);

    }

    return source;
};

var loaderUtils = require("loader-utils");

module.exports = function(source, map) {
    var query = loaderUtils.parseQuery(this.query);

    if (!query.uniquePrefix) {
        this.emitError("Missing loader parameter uniquePrefix");
        return;
    }

    this.cacheable();

    var r = query.uniquePrefix;
    if (r) r += '-';

    source = source.replace(/kwfUp-/g, r);

    if (source.match(/kwfLocal/)) {
        var p = this.resourcePath;
        p = p.replace(process.cwd()+'/', '');

        p = p.replace(/^commonjs\/views\//, '');
        p = p.replace(/^reactjs\/(components|layouts)\//, '');
        p = p.replace(/^components\/(.*?)\/backbone\/views\//, '');
        p = p.replace(/^components\/(.*?)\/reactjs\/(components|layouts)\//, '');
        p = p.replace(/\.underscore\.tpl$/, '');
        p = p.replace(/\.[a-z]+$/, '');
        p = p.replace(/\/(.)/g, m => {
            return m.toUpperCase();
        });
        p = p.replace(/\//g, '');
        p = p.charAt(0).toLowerCase() + p.substr(1);

        p = r + p;
        source = source.replace(/kwfLocal/g, p);

    }

    return source;
};

Replace kwfLocal, begin with lower-case letter


chorus.views.WorkspaceShowSidebar = chorus.views.Sidebar.extend({
    constructorName: "WorkspaceShowSidebarView",
    className:"workspace_show_sidebar",

    subviews: {
        ".workspace_member_list": "workspaceMemberList"
    },

    setup:function () {
        this.bindings.add(this.model, "image:change", this.render);
        this.model.members().fetch();
        this.bindings.add(this.model.members(), "reset", this.render);
        this.workspaceMemberList = new chorus.views.WorkspaceMemberList();
        this.workspaceMemberList.setWorkspace(this.model);
    },

    additionalContext:function () {
        return {
            workspaceAdmin:this.model.workspaceAdmin(),
            imageUrl:this.model.imageUrl() + "&buster=" + chorus.cachebuster,
            hasImage:this.model.hasImage(),
            hasSandbox:!!this.model.sandbox(),
            currentUserIsMember: this.model.currentUserIsMember()
        };
    },

    postRender:function () {
        var self = this;
        this.$(".workspace_image").load(function () {
            self.$(".after_image").removeClass("hidden");
        });
        this.$('.workspace_image').load(_.bind(this.recalculateScrolling, this));
        this._super('postRender');
    }
});

chorus.views.WorkspaceShowSidebar = chorus.views.Sidebar.extend({
    constructorName: "WorkspaceShowSidebarView",
    className:"workspace_show_sidebar",

    subviews: {
        ".workspace_member_list": "workspaceMemberList"
    },

    setup:function () {
        this.bindings.add(this.model, "image:change", this.render);
        this.model.members().fetch();
        this.bindings.add(this.model.members(), "reset", this.render);
        this.workspaceMemberList = new chorus.views.WorkspaceMemberList();
        this.workspaceMemberList.setWorkspace(this.model);
    },

    additionalContext:function () {
        return {
            workspaceAdmin:this.model.workspaceAdmin(),
            imageUrl:this.model.imageUrl() + "&buster=" + chorus.cachebuster(),
            hasImage:this.model.hasImage(),
            hasSandbox:!!this.model.sandbox(),
            currentUserIsMember: this.model.currentUserIsMember()
        };
    },

    postRender:function () {
        var self = this;
        this.$(".workspace_image").load(function () {
            self.$(".after_image").removeClass("hidden");
        });
        this.$('.workspace_image').load(_.bind(this.recalculateScrolling, this));
        this._super('postRender');
    }
});

Fix error in cachebuster for workspace show sidebar


'use strict';

const expect = require('chai').expect;
const jsdomify = require('jsdomify').default;

const Controller = require('../source/components/filter/filter.controller.js');

describe('For the controller', () => {
    it('expect it to have two testing filters', () => {
        let controller = new Controller();

        expect(controller.filters()).to.be.have.length(2);
    });
});

describe('For the views', () => {
    before('create the dom', () => jsdomify.create());
    beforeEach('clear the dom', () => jsdomify.clear());
    after('destroy the dom', () => jsdomify.destroy());

    describe('expect FilterView', () => {
        it('should be ok', () => expect(true).to.be.ok );
    });
});

'use strict';

const expect = require('chai').expect;
const jsdomify = require('jsdomify').default;

const m = require('mithril');
const Filter = require('../source/models/filter.js');
const Controller = require('../source/components/filter/filter.controller.js');
const views = require('../source/components/filter/filter.view.js');

describe('For the controller', () => {
    it('expect it to have two testing filters', () => {
        let controller = new Controller();

        expect(controller.filters()).to.be.have.length(2);
    });
});

describe('For the views', () => {
    before('create the dom', () => jsdomify.create(''));
    after('destroy the dom', () => jsdomify.destroy());
    beforeEach('jsdom setup', () => {
        jsdomify.clear();
        this.document = jsdomify.getDocument();
        m.deps(this.document.defaultView);
    });

    describe('expect FilterView to', () => {
        beforeEach('setup filter', () => this.filter = new Filter({name: 'Test Filter'}));
        beforeEach('render view', () => {
            m.mount(
                this.document.body,
                {
                    view: () => views.filterView(null, [this.filter, 1])
                });
        });
        it('have an id', () => {
            let element = this.document.getElementById('filter1');
            expect(element).to.not.be.null;
        });
        it('be disabled by default', () => {
            let element = this.document.getElementById('filter1');
            expect(element.checked).to.be.false;
        });
        it('have checks update the model', () => {
            let element = this.document.getElementById('filter1');
            let label = this.document.getElementsByTagName('label')[0];
            element.checked = true;
            label.click();
            expect(this.filter.enabled()).to.be.true;
        });
        it('be bound to the model', () => {
            this.filter.enabled(true);
            m.redraw(true);
            let element = this.document.getElementById('filter1');
            expect(element.checked).to.be.true;
        });
    });
});

Test the single filter view


var module_ = require("module")
var babel

exports.init = function(path) {
  var dummyMod = {
    id: path,
    paths: module_._nodeModulePaths(path).concat(module_.globalPaths)
  }
  var resolved = module_._resolveFilename("babel-core", dummyMod)
  babel = require(resolved)
}

exports.transform = function(path, text) {
  if (/node_modules\//.test(path)) return text
  try {
    return babel.transform(text, {filename: path}).code
  } catch(e) {
    return "console.error(" + JSON.stringify(e + "") + ")"
  }
}

var module_ = require("module")
var babel

exports.init = function(path) {
  var dummyMod = {
    id: path,
    paths: module_._nodeModulePaths(path).concat(module_.globalPaths)
  }
  var resolved = module_._resolveFilename("babel-core", dummyMod)
  babel = require(resolved)
}

exports.transform = function(path, text) {
  if (/node_modules\//.test(path)) return text
  try {
    return babel.transform(text, {filename: path, sourceMaps: "inline"}).code
  } catch(e) {
    return "console.error(" + JSON.stringify(e + "") + ")"
  }
}

Enable source maps in default Babel transform


/* jshint node: true */

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

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

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

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

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

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

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },
    contentSecurityPolicy: {
      'default-src': "'none'",
      'script-src': "'self'",
      'font-src': "'self' data: https://fonts.gstatic.com ",
      'connect-src': "'self'",
      'img-src': "'self'",
      'style-src': "'self' https://fonts.googleapis.com",
      'media-src': "'self'"
    },
    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

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

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

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

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

  if (environment === 'production') {

  }

  return ENV;
};

Add CSP to make console less noisy during testing


/**
 * Created by ginger on 2017/10/29.
 */

var Kekule = require('../../dist/kekule.js').Kekule;

// Create a simple CO2 molecule
var mol = new Kekule.Molecule();
var atomC = mol.appendAtom('C');
var atomO1 = mol.appendAtom('O');
var atomO2 = mol.appendAtom('O');
mol.appendBond([atomC, atomO1], 2);
mol.appendBond([atomC, atomO2], 2);

// Output formula
var formula = mol.calcFormula();
console.log('Formula: ', formula.getText());

// Output SMILES
var smiles = Kekule.IO.saveFormatData(mol, 'smi');
console.log('SMILES: ', smiles);

// Output MOL2k
var mol2k = Kekule.IO.saveFormatData(mol, 'mol');
console.log('MOL 2000: \n', mol2k);

/**
 * Created by ginger on 2017/10/29.
 */

var Kekule = require('../../src/kekule.js').Kekule;

// Create a simple CO2 molecule
var mol = new Kekule.Molecule();
var atomC = mol.appendAtom('C');
var atomO1 = mol.appendAtom('O');
var atomO2 = mol.appendAtom('O');
mol.appendBond([atomC, atomO1], 2);
mol.appendBond([atomC, atomO2], 2);

// Output formula
var formula = mol.calcFormula();
console.log('Formula: ', formula.getText());

// Output SMILES
var smiles = Kekule.IO.saveFormatData(mol, 'smi');
console.log('SMILES: ', smiles);

// Output MOL2k
var mol2k = Kekule.IO.saveFormatData(mol, 'mol');
console.log('MOL 2000: \n', mol2k);

Change to use src js files directly in node test


import {
  TerminalRuntimeError,
  TerminalParsingError,
} from './TerminalErrors';

const errorHandler = (rsp) => {
  throw new TerminalRuntimeError(rsp);
};

const createSession = (rsp) => {
  if (
    !rsp[`common_${this.uapi_version}:HostToken`] ||
    !rsp[`common_${this.uapi_version}:HostToken`]._
  ) {
    throw new TerminalParsingError.TerminalSessionTokenMissing();
  }
  return rsp[`common_${this.uapi_version}:HostToken`]._;
};

const terminalRequest = (rsp) => {
  if (
    !rsp['terminal:TerminalCommandResponse'] ||
    !rsp['terminal:TerminalCommandResponse']['terminal:Text']
  ) {
    throw new TerminalParsingError.TerminalResponseMissing();
  }
  return rsp['terminal:TerminalCommandResponse']['terminal:Text'];
};

const closeSession = (rsp) => {
  if (
    !rsp[`common_${this.uapi_version}:ResponseMessage`] ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0] ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0]._ ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0]._.match(/Terminal End Session Successful/i)
  ) {
    throw new TerminalRuntimeError.TerminalCloseSessionFailed();
  }
  return true;
};

module.exports = {
  TERMINAL_ERROR: errorHandler,
  CREATE_SESSION: createSession,
  TERMINAL_REQUEST: terminalRequest,
  CLOSE_SESSION: closeSession,
};

import {
  TerminalRuntimeError,
  TerminalParsingError,
} from './TerminalErrors';

function errorHandler(rsp) {
  throw new TerminalRuntimeError(rsp);
}

function createSession(rsp) {
  if (
    !rsp[`common_${this.uapi_version}:HostToken`] ||
    !rsp[`common_${this.uapi_version}:HostToken`]._
  ) {
    throw new TerminalParsingError.TerminalSessionTokenMissing();
  }
  return rsp[`common_${this.uapi_version}:HostToken`]._;
}

function terminalRequest(rsp) {
  if (
    !rsp['terminal:TerminalCommandResponse'] ||
    !rsp['terminal:TerminalCommandResponse']['terminal:Text']
  ) {
    throw new TerminalParsingError.TerminalResponseMissing();
  }
  return rsp['terminal:TerminalCommandResponse']['terminal:Text'];
}

function closeSession(rsp) {
  if (
    !rsp[`common_${this.uapi_version}:ResponseMessage`] ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0] ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0]._ ||
    !rsp[`common_${this.uapi_version}:ResponseMessage`][0]._.match(/Terminal End Session Successful/i)
  ) {
    throw new TerminalRuntimeError.TerminalCloseSessionFailed();
  }
  return true;
}

module.exports = {
  TERMINAL_ERROR: errorHandler,
  CREATE_SESSION: createSession,
  TERMINAL_REQUEST: terminalRequest,
  CLOSE_SESSION: closeSession,
};

Fix of the terminal parser functions passed without context


/**
 * Copyright (c) 2017-present, Raphael Amorim.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * reference: https://developer.mozilla.org/en-US/docs/Web/Events
 *
 * @flow
 */

const EventConstants = {
  onClick: 'click',
  onBlur: 'blur',
  onFocus: 'focus',
  onSubmit: 'submit',
  onResize: 'resize',
  onLoad: 'load',
  onUnload: 'unload',
  onPress: 'keypress',
  onScroll: 'scroll',
  onKeypress: 'keypress',
  onKeydown: 'keydown',
  onKeyup: 'keyup',
};

export default EventConstants;

/**
 * Copyright (c) 2017-present, Raphael Amorim.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * reference: https://developer.mozilla.org/en-US/docs/Web/Events
 *
 * @flow
 */

const EventConstants = {
  onClick: 'click',
  onBlur: 'blur',
  onFocus: 'focus',
  onSubmit: 'submit',
  onResize: 'resize',
  onLoad: 'load',
  onUnload: 'unload',
  onPress: 'keypress',
  onScroll: 'scroll',
  onKeyPress: 'keypress',
  onKeyDown: 'keydown',
  onKeyUp: 'keyup',
};

export default EventConstants;

Fix 'onKeyDown', 'onKeyPress' and 'onKeyUp' callback name


// Rewrite in-line event handlers (eg. <input ... onclick=""> for a sub-set of common standard events)

document.addEventListener('DOMContentLoaded', function(e) {

  var selectors = ['load', 'click', 'mouseover', 'mouseout', 'keydown', 'keypress', 'keyup', 'blur', 'focus'];

  for(var i = 0, l = selectors.length; i < l; i++) {
    var els = document.querySelectorAll('[on' + selectors[i] + ']');
    for(var j = 0, k = els.length; j < k; j++) {
      var fn = new Function('e', els[j].getAttribute('on' + selectors[i]));
      var target = els[j];
      if(selectors[i] === 'load' && els[j] === document.body) {
        target = window;
      }

      els[j].removeAttribute('on' + selectors[i]);
      target.addEventListener(selectors[i], fn, true);
    }
  }

}, false);

opera.isReady(function() {

  // Rewrite in-line event handlers (eg. <input ... onclick=""> for a sub-set of common standard events)

  document.addEventListener('DOMContentLoaded', function(e) {

    var selectors = ['load', 'beforeunload', 'unload', 'click', 'dblclick', 'mouseover', 'mousemove',
                        'mousedown', 'mouseup', 'mouseout', 'keydown', 'keypress', 'keyup', 'blur', 'focus'];

    for(var i = 0, l = selectors.length; i < l; i++) {
      var els = document.querySelectorAll('[on' + selectors[i] + ']');
      for(var j = 0, k = els.length; j < k; j++) {
        var fn = new Function('e', els[j].getAttribute('on' + selectors[i]));
        var target = els[j];
        if(selectors[i].indexOf('load') > -1 && els[j] === document.body) {
          target = window;
        }

        els[j].removeAttribute('on' + selectors[i]);
        target.addEventListener(selectors[i], fn, true);
      }
    }

  }, false);

});

Add a broader set of events for inline event handler rewrite function


/** @babel */

import helpers from './spec-helpers'
import MarkerManager from '../lib/marker-manager'

describe('MarkerManager', () => {
  beforeEach(() => {
    waitsForPromise(() => {
      return helpers.activatePackages()
    })
  })

  describe('addMarkers', () => {
    it('verifies that only messages that have a range and a matching file path are marked', () => {
      const editor = {
        getPath: () => 'foo.tex',
        onDidDestroy: () => { return { dispose: () => null } }
      }
      const manager = new MarkerManager(editor)
      const messages = [{
        type: 'error',
        range: [[0, 0], [0, 1]],
        filePath: 'foo.tex'
      }, {
        type: 'warning',
        range: [[0, 0], [0, 1]],
        filePath: 'bar.tex'
      }, {
        type: 'info',
        filePath: 'foo.tex'
      }]
      spyOn(manager, 'addMarker')

      manager.addMarkers(messages, false)

      expect(manager.addMarker).toHaveBeenCalledWith('error', 'foo.tex', [[0, 0], [0, 1]])
      expect(manager.addMarker.calls.length).toEqual(1)
    })
  })
})

/** @babel */

import helpers from './spec-helpers'
import MarkerManager from '../lib/marker-manager'

describe('MarkerManager', () => {
  beforeEach(() => {
    waitsForPromise(() => {
      return helpers.activatePackages()
    })
  })

  describe('addMarkers', () => {
    let editor, manager

    beforeEach(() => {
      editor = {
        getPath: () => 'foo.tex',
        onDidDestroy: () => { return { dispose: () => null } }
      }
      manager = new MarkerManager(editor)
      spyOn(manager, 'addMarker')
      spyOn(manager, 'clear')
    })

    it('verifies that only messages that have a range and a matching file path are marked', () => {
      const messages = [{
        type: 'error',
        range: [[0, 0], [0, 1]],
        filePath: 'foo.tex'
      }, {
        type: 'warning',
        range: [[0, 0], [0, 1]],
        filePath: 'bar.tex'
      }, {
        type: 'info',
        filePath: 'foo.tex'
      }]

      manager.addMarkers(messages, false)

      expect(manager.addMarker).toHaveBeenCalledWith('error', 'foo.tex', [[0, 0], [0, 1]])
      expect(manager.addMarker.calls.length).toEqual(1)
      expect(manager.clear).not.toHaveBeenCalled()
    })

    it('verifies that clear is called when reset flag is set', () => {
      manager.addMarkers([], true)

      expect(manager.clear).toHaveBeenCalled()
    })
  })
})

Add test for reset flag


var Spinner = require('./../index');

Spinner.prototype.show = function() {
  this.model.set('spinning', true);
};

Spinner.prototype.hide = function() {
  this.model.set('spinning', false);
};

var Spinner = require('./../index');

Spinner.prototype._show = function() {
  this.model.set('spinning', true);
};

Spinner.prototype._hide = function() {
  this.model.set('spinning', false);
};

Rename spinner operations to the right name


var icalendar = require('icalendar');

exports.generateIcal = function(boards) {
    var ical = new icalendar.iCalendar();
    boards.each(function(board) {
        board.cards().each(function(card) {
            // no arm, no chocolate
            if (!card.get('badges').due) return;
            var event = new icalendar.VEvent();
            event.setSummary(card.get('name'));
            event.setDescription(card.get('description'));
            event.setDate(card.get('badges').due);
            event.addProperty('ATTACH', card.get('url'));
            ical.addComponent(event);
        });
    });
    return ical;
}

var icalendar = require('icalendar');

exports.generateIcal = function(boards) {
    var ical = new icalendar.iCalendar();
    boards.each(function(board) {
        board.cards().each(function(card) {
            // no arm, no chocolate
            if (!card.get('badges').due) return;
            var event = new icalendar.VEvent(card.id);
            event.setSummary(card.get('name'));
            event.setDescription(card.get('description'));
            event.setDate(card.get('badges').due);
            event.addProperty('ATTACH', card.get('url'));
            event.addProperty('URL', card.get('url'));
            ical.addComponent(event);
        });
    });
    return ical;
}

Add uid and another URL property.


angular.module('codebrag.commits')

    .directive('generalLikes', function (authService) {

        return {
            restrict: 'E',
            replace: true,
            scope: {
                author: '=',
                likesCollection: '=',
                submitLike: '&'
            },
            templateUrl: 'generalLikes',
            link: function (scope, element) {

                scope.noLikes = function () {
                    return _.isEmpty(scope.likesCollection)
                };
                scope.conjugatedLike = "likes";

                var currentUserName = authService.loggedInUser.fullName;

                var setUserAlreadyLikedStyle = function (isAlreadyLiked) {
                    if (isAlreadyLiked) $('div.like-commit', element).addClass("liked-by-user");
                };

                var removeAuthorWatch = scope.$watch(function () {
                    return scope.author
                }, function (newVal) {
                    if (angular.isUndefined(newVal)) {
                        return;
                    }
                    setUserAlreadyLikedStyle(scope.author == currentUserName);
                    removeAuthorWatch();
                });

                var removeCollectionReferenceWatch = scope.$watch(function () {
                    return scope.likesCollection
                }, function (newVal) {
                    if (angular.isUndefined(newVal)) {
                        return;
                    }
                    scope.$watch(function () {
                            return scope.likesCollection.length;
                        }, function (newVal) {
                            if (newVal > 1) {
                                scope.conjugatedLike = "like";
                            }
                            if (_.some(scope.likesCollection, function (like) {
                                return like.authorName == currentUserName
                            })) {
                                setUserAlreadyLikedStyle(true);
                            }
                        }
                    );
                    removeCollectionReferenceWatch();
                });
            }
        }

    }
)
;

angular.module('codebrag.commits')

    .directive('generalLikes', function (authService) {

        return {
            restrict: 'E',
            scope: {
                author: '=',
                likesCollection: '=',
                submitLike: '&'
            },
            templateUrl: 'generalLikes',
            link: function (scope, element) {

                scope.noLikes = function () {
                    return _.isEmpty(scope.likesCollection)
                };
                scope.conjugatedLike = "likes";

                var currentUserName = authService.loggedInUser.fullName;

                var setUserAlreadyLikedStyle = function (isAlreadyLiked) {
                    if (isAlreadyLiked) $('div.like-commit', element).addClass("liked-by-user");
                };

                var removeAuthorWatch = scope.$watch(function () {
                    return scope.author
                }, function (newVal) {
                    if (angular.isUndefined(newVal)) {
                        return;
                    }
                    setUserAlreadyLikedStyle(scope.author == currentUserName);
                    removeAuthorWatch();
                });

                var removeCollectionReferenceWatch = scope.$watch(function () {
                    return scope.likesCollection
                }, function (newVal) {
                    if (angular.isUndefined(newVal)) {
                        return;
                    }
                    scope.$watch(function () {
                            return scope.likesCollection.length;
                        }, function (newVal) {
                            if (newVal > 1) {
                                scope.conjugatedLike = "like";
                            }
                            if (_.some(scope.likesCollection, function (like) {
                                return like.authorName == currentUserName
                            })) {
                                setUserAlreadyLikedStyle(true);
                            }
                        }
                    );
                    removeCollectionReferenceWatch();
                });
            }
        }

    }
)
;

Revert back not replacing content for general likes directive


// Default options

'use strict';

module.exports = {
  html: false,
  xhtml: false,
  breaks: true,
  langprefix: 'language-'
};

// Default options

'use strict';

module.exports = {
  html: false,
  xhtml: false,
  breaks: false,
  langprefix: 'language-'
};

Set breaks off by default


/**
 * Expose
 */
module.exports = {
  /**
   * @param {Request} req
   * @return {Boolean}
   */
  hasEscapedFragment: function(req) {
    return !!req.query['_escaped_fragment_'];
  },

  /**
   * @param {String} ua
   * @return {Boolean}
   */
  isRequestByCrawler: function(ua) {
    return ua.indexOf('googlebot') !== -1
        || ua.indexOf('bingbot')   !== -1;
  }
}

/**
 * Expose
 */
module.exports = {
  /**
   * @param {Request} req
   * @return {Boolean}
   */
  hasEscapedFragment: function(req) {
    return !!req.query['_escaped_fragment_'];
  },

  /**
   * @param {String} ua
   * @return {Boolean}
   */
  isRequestByCrawler: function(ua) {
    return ua.indexOf('googlebot') !== -1
        || ua.indexOf('yahoo')     !== -1
        || ua.indexOf('bingbot')   !== -1
    ;
  }
}

Add yahoo bot user agent


'use strict';
var util = require('util');

var Node = require('./node');
var Element = require('./nodes/element');
var makeElement = require('./nodes/make-element');

function Document(markup, options) {
	if (typeof markup !== 'string') {
		options = markup;
		markup = null;
	}

	Node.call(this, {
		tagName: 'html',
		nodeType: 9,
		parseOptions: options
	});

	this.documentElement = new Element({
		tagName: 'html',
		ownerDocument: this,
		parseOptions: options
	});

	this.defaultView = options && options.defaultView || null;
	this.childNodes = [this.documentElement];

	if (markup) {
		this.documentElement.innerHTML = markup;
	}
}

util.inherits(Document, Element);

Document.prototype.write = function(content) {
	this.documentElement.innerHTML = content;
};

Document.prototype.createDocumentFragment = function() {
	return new Node({
		nodeType: 11,
		ownerDocument: this
	});
};

Document.prototype.createElement = function(nodeName) {
	return makeElement({
		nodeName: nodeName,
		ownerDocument: this
	});
};

Document.prototype.createTextNode = function(data) {
	if (arguments.length === 0) {
		throw new Error('Document#createTextNode: not enough arguments.');
	}

	return new Node({
		nodeType: 3,
		ownerDocument: this,
		data: data
	});
};

module.exports = Document;

'use strict';
var util = require('util');

var Node = require('./node');
var Element = require('./nodes/element');
var makeElement = require('./nodes/make-element');

function Document(options) {
	Node.call(this, {
		tagName: 'html',
		nodeType: 9,
		parseOptions: options
	});

	this.documentElement = new Element({
		tagName: 'html',
		ownerDocument: this,
		parseOptions: options
	});

	this.defaultView = options && options.defaultView || null;
	this.childNodes = [this.documentElement];
}

util.inherits(Document, Element);

Document.prototype.write = function(content) {
	this.documentElement.innerHTML = content;
};

Document.prototype.createDocumentFragment = function() {
	return new Node({
		nodeType: 11,
		ownerDocument: this
	});
};

Document.prototype.createElement = function(nodeName) {
	return makeElement({
		nodeName: nodeName,
		ownerDocument: this
	});
};

Document.prototype.createTextNode = function(data) {
	if (arguments.length === 0) {
		throw new Error('Document#createTextNode: not enough arguments.');
	}

	return new Node({
		nodeType: 3,
		ownerDocument: this,
		data: data
	});
};

module.exports = Document;

Remove markup-accepting signature of Document


'use strict';

var request = require('request');

function removeEmptyItemFilter(item) {
  return item.length > 0;
}

function tasksFromTextToObject(text) {
  return text
    .replace(/([ \t]+)/gm, ' ')     // Remove duplicate spaces
    .split('\n')                    // Create an array with the tasks
    .filter(removeEmptyItemFilter)  // Remove empty element
    .map(function (line) {          // Each task must be an object
      var fields = line.split(' ');
      return {
        name: fields[0],            // The first element is the name of the app
        port: parseInt(fields[1], 10),  // The second element is the port to use
        endpoints: fields.slice(2)  // The following elements are the endpoints
          .filter(removeEmptyItemFilter)
      };
    });
}

function Marathon(marathonUrl) {
  this._marathonUrl = marathonUrl;

  return this;
}

Marathon.prototype.getTasks = function (callback) {
  function onResponse(error, response, body) {
    if (error) {
      return callback(new Error('Unable to get the tasks using the Marathon ' +
        'API. Error: ' + error.message));
    }
    var tasks = tasksFromTextToObject(body);
    return callback(null, tasks);
  }

  var options = {
    url: this._marathonUrl + '/v2/tasks',
    headers: {
      'Accept': 'text/plain'
    }
  };
  request.get(options, onResponse);
};

module.exports = Marathon;

'use strict';

var request = require('request');

function removeEmptyItemFilter(item) {
  return item.length > 0;
}

function tasksFromTextToObject(text) {
  return text
    .replace(/([ \t]+)/gm, ' ')     // Remove duplicate spaces
    .split('\n')                    // Create an array with the tasks
    .filter(removeEmptyItemFilter)  // Remove empty element
    .map(function (line) {          // Each task must be an object
      var fields = line.split(' ');
      return {
        name: fields[0],            // The first element is the name of the app
        port: parseInt(fields[1], 10),  // The second element is the port to use
        endpoints: fields.slice(2)  // The following elements are the endpoints
          .filter(removeEmptyItemFilter)
      };
    });
}

function Marathon(marathonUrl) {
  this._marathonUrl = marathonUrl;

  return this;
}

Marathon.prototype.getTasks = function (callback) {
  function onResponse(error, response, body) {
    if (error) {
      return callback(new Error('Unable to get the tasks using the Marathon ' +
        'API. ' + error.toString()));
    }
    var tasks = tasksFromTextToObject(body);
    return callback(null, tasks);
  }

  var options = {
    url: this._marathonUrl + '/v2/tasks',
    headers: {
      'Accept': 'text/plain'
    }
  };
  request.get(options, onResponse);
};

module.exports = Marathon;

Use toString() to print the error coming from the API request


var childProcess = require('child_process');
var fs = require('fs-extra');
var glob = require('glob');
var path = require('path');
var sortPackageJson = require('sort-package-json');

// Update the core.
require('./update-core');

// Update the package.app.json file.
var data = require('./package.json');
data['scripts']['build'] = 'webpack'
data['jupyterlab']['outputDir'] = '..';
text = JSON.stringify(sortPackageJson(data), null, 2) + '\n';
fs.writeFileSync('./package.app.json', text);

// Update our app index file.
fs.copySync('./index.js', './index.app.js')

// Run a standard build with Typescript source maps working.
childProcess.execSync('npm run build:prod');

// Add  the release metadata.
var release_data = { version: version };
text = JSON.stringify(release_data, null, 2) + '\n';
fs.writeFileSync('./build/release_data.json', text);

var childProcess = require('child_process');
var fs = require('fs-extra');
var glob = require('glob');
var path = require('path');
var sortPackageJson = require('sort-package-json');

// Run a production build with Typescript source maps.
childProcess.execSync('npm run build:prod', {stdio:[0,1,2]});

// Update the package.app.json file.
var data = require('./package.json');
data['scripts'] = { 'build': 'webpack' };
data['jupyterlab']['outputDir'] = '..';
text = JSON.stringify(sortPackageJson(data), null, 2) + '\n';
fs.writeFileSync('./package.app.json', text);

// Update our app index file.
fs.copySync('./index.js', './index.app.js');

// Add  the release metadata.
var release_data = { version: data.jupyterlab.version };
text = JSON.stringify(release_data, null, 2) + '\n';
fs.writeFileSync('./build/release_data.json', text);

Clean up the make release script


var locastyle = locastyle || {};

locastyle.charCounter = (function() {
  'use strict';

  function updateCounter(index, count) {
    $('.ls-number-counter-'+index).text(count);
  }

  function countText() {
    $('[data-ls-module="charCounter"]').each(function(index, field) {
      var limit = $(field).attr('maxlength');
      var html = '
' + limit + ' caracteres restantes
';
      var prefixGroup = $(field).closest('.ls-prefix-group');

      $(field).removeAttr('maxlength').data().maxlength = limit;

      if (prefixGroup.length) {
        prefixGroup.after(html);
      } else {
        $(field).after(html);
      }

      $(field).keyup(function() {
        var count = $(this).val().length;
        var limit = $(this).data().maxlength;

        if(count > limit) {
          $(this).val($(this).val().substring(0, limit));
          updateCounter(index, 0);
        } else {
          updateCounter(index, limit - count);
        }
      });

      $(field).trigger('keyup');
    });
  }

  function init() {
    countText();
  }

  return {
    init: init
  };

}());

Break the char counter long line


var Extend = require('../utils/extend');

var Types = {
  LIGHT: require('./themes/light-theme'),
  DARK: require('./themes/dark-theme')
};

var ThemeManager = function() {
  return {
    types: Types,
    template: Types.LIGHT,

    spacing: Types.LIGHT.spacing,
    contentFontFamily: 'Roboto, sans-serif',

    palette: Types.LIGHT.getPalette(),
    component: Types.LIGHT.getComponentThemes(Types.LIGHT.getPalette()),

    getCurrentTheme: function() {
      return this;
    },

    // Component gets updated to reflect palette changes.
    setTheme: function(newTheme) {
      this.setSpacing(newTheme.spacing);
      this.setPalette(newTheme.getPalette());
      this.setComponentThemes(newTheme.getComponentThemes(newTheme.getPalette()));
    },

    setSpacing: function setSpacing(newSpacing) {
      this.spacing = Extend(this.spacing, newSpacing);
    },

    setPalette: function(newPalette) {
      this.palette = Extend(this.palette, newPalette);
      this.component = Extend(
        this.component,
        this.template.getComponentThemes(this.palette, this.spacing)
      );
    },

    setComponentThemes: function(overrides) {
      this.component = Extend(this.component, overrides);
    }
  };
};

module.exports = ThemeManager;

var Extend = require('../utils/extend');

var Types = {
  LIGHT: require('./themes/light-theme'),
  DARK: require('./themes/dark-theme')
};

var ThemeManager = function() {
  return {
    types: Types,
    template: Types.LIGHT,

    spacing: Types.LIGHT.spacing,
    contentFontFamily: 'Roboto, sans-serif',

    palette: Types.LIGHT.getPalette(),
    component: Types.LIGHT.getComponentThemes(Types.LIGHT.getPalette()),

    getCurrentTheme: function() {
      return this;
    },

    // Component gets updated to reflect palette changes.
    setTheme: function(newTheme) {
      this.setSpacing(newTheme.spacing);
      this.setPalette(newTheme.getPalette());
      this.setComponentThemes(newTheme.getComponentThemes(newTheme.getPalette()));
    },

    setSpacing: function setSpacing(newSpacing) {
      this.spacing = Extend(this.spacing, newSpacing);
      this.component = Extend(this.component, this.template.getComponentThemes(this.palette, this.spacing));
    },

    setPalette: function(newPalette) {
      this.palette = Extend(this.palette, newPalette);
      this.component = Extend(this.component, this.template.getComponentThemes(this.palette));
    },

    setComponentThemes: function(overrides) {
      this.component = Extend(this.component, overrides);
    }
  };
};

module.exports = ThemeManager;

Update component if spacing has been changed


/**
 * Copyright 2013 Facebook, 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.
 *
 * @providesModule getTestDocument
 */

/**
 * We need to work around the fact that we have two different
 * test implementations: once that breaks if we clobber document
 * (open-source) and one that doesn't support createHTMLDocument()
 * (jst).
 */
function getTestDocument() {
  if (document.implementation &&
      document.implementation.createHTMLDocument) {
    return document.implementation.createHTMLDocument('test doc');
  }
  return null;
}

module.exports = getTestDocument;

/**
 * Copyright 2013 Facebook, 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.
 *
 * @providesModule getTestDocument
 */

/**
 * We need to work around the fact that we have two different
 * test implementations: once that breaks if we clobber document
 * (open-source) and one that doesn't support createHTMLDocument()
 * (jst).
 */
function getTestDocument() {
  var iframe = document.createElement('iframe');
  iframe.style.cssText = 'position:absolute; visibility:hidden; bottom:100%; right:100%';
  iframe.src = 'data:text/html,<!doctype html><meta charset=utf-8><title>test doc</title>';
  document.body.appendChild(iframe);
  var testDocument = iframe.contentDocument;
  iframe.parentNode.removeChild(iframe);
  return testDocument;
}

module.exports = getTestDocument;

Use an iframe to create a testDocument… instead of `createHTMLDocument` since it isn't fully support by the browsers we care about.


'use babel'

import {transform as babelTransform} from 'flint-babel-core'
import {Parser} from '../compiler'
import {transformPlugin, getBabelConfig} from '../helpers'

const NEWLINE_REGEX = /\r\n|\n|\r/g
export const POSITION_TYPE = {
  VIEW_TOP: 'VIEW_TOP',
  VIEW_JSX: 'VIEW_JSX',
  STYLE: 'STYLE'
}

export function transformText(text, {
  log = null,
  writeStyle = null,
  onMeta = null,
  onImports = null,
  onExports = null
}) {
  let toReturn = ''
  Parser.pre('unknown', text, function(text) {
    toReturn = babelTransform(text, getBabelConfig({
      log, writeStyle, onMeta, onImports, onExports
    }))
  })
  transformPlugin.disposeLast()
  return toReturn
}

export function pointWithinRange(point, range) {
  return point.isGreaterThan(range[0]) && point.isLessThan(range[1])
}

export function getObjectAtPosition(objects, position) {
  for (const key in objects) {
    const value = objects[key]
    if (pointWithinRange(position, value.location)) {
      return value
    }
  }
  return null
}

export function getRowFromText(text, row) {
  const rowText = text.split(NEWLINE_REGEX)[row]
  return rowText || ''
}

'use babel'

import {transform as babelTransform} from 'flint-babel-core'
import {Parser} from '../compiler'
import {transformPlugin, getBabelConfig} from '../helpers'

const NEWLINE_REGEX = /\r\n|\n|\r/g
export const POSITION_TYPE = {
  VIEW_TOP: 'VIEW_TOP',
  VIEW_JSX: 'VIEW_JSX',
  STYLE: 'STYLE'
}

export function transformText(text, {
  log = null,
  writeStyle = null,
  onMeta = null,
  onImports = null,
  onExports = null
}) {
  let toReturn = ''
  // Setting this key so it's easier to distinguish in debug output
  Parser.pre('__editor__', text, function(text) {
    toReturn = babelTransform(text, getBabelConfig({
      log, writeStyle, onMeta, onImports, onExports
    }))
  })
  transformPlugin.disposeLast()
  return toReturn
}

export function pointWithinRange(point, range) {
  return point.isGreaterThan(range[0]) && point.isLessThan(range[1])
}

export function getObjectAtPosition(objects, position) {
  for (const key in objects) {
    const value = objects[key]
    if (pointWithinRange(position, value.location)) {
      return value
    }
  }
  return null
}

export function getRowFromText(text, row) {
  const rowText = text.split(NEWLINE_REGEX)[row]
  return rowText || ''
}

Set a more verbose key in transformText


var BootstrapTheme = Theme.extend({

	classes: {
		widget: 'fc-bootstrap3',

		tableGrid: 'table-bordered', // avoid `table` class b/c don't want margins. only border color
		tableList: 'table table-striped', // `table` class creates bottom margin but who cares

		buttonGroup: 'btn-group',
		button: 'btn btn-default',
		stateActive: 'active',
		stateDisabled: 'disabled',

		today: 'alert alert-warning', // the plain `warning` class requires `.table`, too much to ask

		popover: 'panel panel-default',
		popoverHeader: 'panel-heading',
		popoverContent: 'panel-body',

		// day grid
		headerRow: 'panel-default', // avoid `panel` class b/c don't want margins/radius. only border color
		dayRow: 'panel-default', // "

		// list view
		listView: 'panel panel-default'
	},

	baseIconClass: 'glyphicon',
	iconClasses: {
		close: 'glyphicon-remove',
		prev: 'glyphicon-chevron-left',
		next: 'glyphicon-chevron-right',
		prevYear: 'glyphicon-backward',
		nextYear: 'glyphicon-forward'
	},

	iconOverrideOption: 'bootstrapGlyphicons',
	iconOverrideCustomButtonOption: 'bootstrapGlyphicon',
	iconOverridePrefix: 'glyphicon-'

});

ThemeRegistry.register('bootstrap3', BootstrapTheme);

var BootstrapTheme = Theme.extend({

	classes: {
		widget: 'fc-bootstrap3',

		tableGrid: 'table-bordered', // avoid `table` class b/c don't want margins. only border color
		tableList: 'table table-striped', // `table` class creates bottom margin but who cares

		buttonGroup: 'btn-group',
		button: 'btn btn-default',
		stateActive: 'active',
		stateDisabled: 'disabled',

		today: 'alert alert-info', // the plain `info` class requires `.table`, too much to ask

		popover: 'panel panel-default',
		popoverHeader: 'panel-heading',
		popoverContent: 'panel-body',

		// day grid
		headerRow: 'panel-default', // avoid `panel` class b/c don't want margins/radius. only border color
		dayRow: 'panel-default', // "

		// list view
		listView: 'panel panel-default'
	},

	baseIconClass: 'glyphicon',
	iconClasses: {
		close: 'glyphicon-remove',
		prev: 'glyphicon-chevron-left',
		next: 'glyphicon-chevron-right',
		prevYear: 'glyphicon-backward',
		nextYear: 'glyphicon-forward'
	},

	iconOverrideOption: 'bootstrapGlyphicons',
	iconOverrideCustomButtonOption: 'bootstrapGlyphicon',
	iconOverridePrefix: 'glyphicon-'

});

ThemeRegistry.register('bootstrap3', BootstrapTheme);

Tweak the class for 'today' in the bootstrap theme


// A helper mixin for react components.
// Use by setting this.store to your root store,
// and call this.grab(path) to get a store link that
// will also trigger forceUpdate of this component
// if the data changes.
//
// TODO: figure out react event batching

var mixin = {
	componentWillMount: function() {
		this._grabs = {};
	},
	componentWillUnmount: function() {
		var s;
		for(var path in this._grabs) {
			s = this._grabs[path];
			s.removeListener('CHANGE', this.storeUpdated);
		}
		delete this._grabs;
	},
	storeUpdated: function() {
		this.forceUpdate(this.storeUpdateFinished);
	},
	grab: function(path) {
		if(!this.store)
			throw('grab() called before this.store set');

		var s = this._grabs[path];
		if(!s) {
			s = this.store.Find(path);
			if(!s)
				throw("Grab failed: Unable to find path '" + path + "' in store '" + this.store.Name + "'");

			s.addListener('CHANGE', this.storeUpdated);
			this._grabs[path] = s;
		}

		return s;
	}
};

module.exports = mixin;

// A helper mixin for react components.
// Use by setting this.store to your root store,
// and call this.grab(path) to get a store link that
// will also trigger forceUpdate of this component
// if the data changes.
//
// TODO: figure out react event batching

var mixin = {
	componentWillMount: function() {
		this._grabs = {};
	},
	componentWillUnmount: function() {
		var s;
		for(var path in this._grabs) {
			s = this._grabs[path];
			s.removeListener('CHANGE', this.storeUpdated);
		}
		delete this._grabs;
	},
	storeUpdated: function() {
		if(this.isMounted()) {
			this.forceUpdate(this.storeUpdateFinished);
		}
	},
	grab: function(path) {
		if(!this.store)
			throw('grab() called before this.store set');

		var s = this._grabs[path];
		if(!s) {
			s = this.store.Find(path);
			if(!s)
				throw("Grab failed: Unable to find path '" + path + "' in store '" + this.store.Name + "'");

			s.addListener('CHANGE', this.storeUpdated);
			this._grabs[path] = s;
		}

		return s;
	}
};

module.exports = mixin;

Fix racey forceUpdate call when components are being rebuilt


/*
 * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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.
 */
import React from 'react';
import Enzyme, { shallow, render, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import TestRenderer from 'react-test-renderer';
import Configs from '../../site/public/theme/defaultTheme';

// React 16 Enzyme adapter
Enzyme.configure({ adapter: new Adapter() });

// Make Enzyme functions available in all test files without importing
global.React = React;
global.shallow = shallow;
global.render = render;
global.mount = mount;
global.testRenderer = TestRenderer;

/*
 * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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.
 */
import React from 'react';
import Enzyme, { shallow, render, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import renderer from 'react-test-renderer';
// React 16 Enzyme adapter
Enzyme.configure({ adapter: new Adapter() });

// Make Enzyme functions available in all test files without importing
global.React = React;
global.shallow = shallow;
global.render = render;
global.mount = mount;
global.renderer = renderer;
if (global.document) {
    // To resolve createRange not defined issue https://github.com/airbnb/enzyme/issues/1626#issuecomment-398588616
    document.createRange = () => ({
        setStart: () => {},
        setEnd: () => {},
        commonAncestorContainer: {
            nodeName: 'BODY',
            ownerDocument: document,
        },
    });
}

Update Jest test setup to add mock document.createRance method and refactor global exposed methods


/**
 * Generic error handler method for ajax responses.
 * Apply your specific requirements for an error response and then call this method to take care of the rest.
 * @param response
 */
function handleApiError(response) {

    if (!response || response.status === 200)
        return;

    if (response.status === 403 || response.status === 401) {
        //sweetAlert('You are not logged in', 'Please refresh Florence and log back in.');
        logout();
    } else if (response.status === 504) {
        sweetAlert('This task is taking longer than expected', "It will continue to run in the background.", "info");
    } else {
        var message = 'An error has occurred, please contact an administrator.';

        if (response.responseJSON) {
            message = response.responseJSON.message;
        }

        console.log(message);
        sweetAlert("Error", message, "error");
    }
}

/* Unique error handling for the login screen */
function handleLoginApiError(response) {

    if (!response || response.status === 200)
        return;

    if (response.status === 403 || response.status === 401) {
        sweetAlert('Incorrect login details', 'These login credentials were not recognised. Please try again.', 'error');
        logout();
    } else {
        var message = 'An error has occurred, please contact an administrator.';

        if (response.responseJSON) {
            message = response.responseJSON.message;
        }

        console.log(message);
        sweetAlert("Error", message, "error");
    }
}

/**
 * Generic error handler method for ajax responses.
 * Apply your specific requirements for an error response and then call this method to take care of the rest.
 * @param response
 */
function handleApiError(response) {

    if (!response || response.status === 200)
        return;

    if (response.status === 403 || response.status === 401) {
        //sweetAlert('You are not logged in', 'Please refresh Florence and log back in.');
        logout();
    } else if (response.status === 504) {
        sweetAlert('This task is taking longer than expected', "It will continue to run in the background.", "info");
    } else {
        var message = 'An error has occurred, please contact an administrator.';

        if (response.responseJSON) {
            message = response.responseJSON.message;
        }

        console.log(message);
        sweetAlert("Error", message, "error");
    }
}

/* Unique error handling for the login screen */
function handleLoginApiError(response) {

    if (!response || response.status === 200)
        return;

    if (response.status === 400) {
        sweetAlert("Please enter a valid username and password");
        logout();
    } else if (response.status === 403 || response.status === 401) {
        sweetAlert('Incorrect login details', 'These login credentials were not recognised. Please try again.', 'error');
        logout();
    } else {
        var message = 'An error has occurred, please contact an administrator.';

        if (response.responseJSON) {
            message = response.responseJSON.message;
        }

        console.log(message);
        sweetAlert("Error", message, "error");
    }
}

Add alert and logout when no login details given


(function () {
  var moneyTracker = angular.module("moneyTracker");

  moneyTracker.service("ExpenseService", ["traverson", "$http", function (traverson, $http) {
    traverson.registerMediaType(TraversonJsonHalAdapter.mediaType, TraversonJsonHalAdapter);
    var myTraverson = traverson.from("http://localhost:8080/api").jsonHal().useAngularHttp();

    this.listCurrent = function () {
      return myTraverson
          .newRequest()
          .follow("expenses", "current")
          .getResource().result;
    };

    this.create = function (expense) {
      return myTraverson
          .newRequest()
          .follow("expenses", "current")
          .post(expense).result;
    };

    this.deleteExpense = function (expense) {
      return $http({
        method: "DELETE",
        url: expense._links.self.href
      });
    }
  }]);
}());

(function () {
  var moneyTracker = angular.module("moneyTracker");

  moneyTracker.service("ExpenseService", ["traverson", "$http", function (traverson, $http) {
    traverson.registerMediaType(TraversonJsonHalAdapter.mediaType, TraversonJsonHalAdapter);
    var myTraverson = traverson.from("/api").jsonHal().useAngularHttp();

    this.listCurrent = function () {
      return myTraverson
          .newRequest()
          .follow("expenses", "current")
          .getResource().result;
    };

    this.create = function (expense) {
      return myTraverson
          .newRequest()
          .follow("expenses", "current")
          .post(expense).result;
    };

    this.deleteExpense = function (expense) {
      return $http({
        method: "DELETE",
        url: expense._links.self.href
      });
    }
  }]);
}());

Use relative path for HTTP requests. This way it doesn't matter where the application is deployed.


import * as React from "react";
import {BuildSnapshot} from "./BuildSnapshot";

/**
 * Container Component for BuildSnapshots.
 *
 * @param {*} props input property containing an array of build data to be
 * rendered through BuildSnapshot.
 */
export const BuildSnapshotContainer = React.memo((props) =>
  {
    const SOURCE = '/builders';
    const [data, setData] = React.useState([]);

    /**
     * Fetch data when component is mounted.
     * Pass in empty array as second paramater to prevent
     * infinite callbacks as component refreshes.
     * @see Fetching
     */
    React.useEffect(() => {
      fetch(SOURCE)
      .then(res => res.json())
      .then(json => setData(json))
      .catch(setData([]));
    }, []);

    return (

        {data.map(snapshotData => <BuildSnapshot buildData={snapshotData}/>)}

    );
  }
);

Indent promise chain two space


import * as React from "react";
import {BuildSnapshot} from "./BuildSnapshot";

/**
 * Container Component for BuildSnapshots.
 *
 * @param {*} props input property containing an array of build data to be
 * rendered through BuildSnapshot.
 */
export const BuildSnapshotContainer = React.memo((props) =>
  {
    const SOURCE = '/builders';
    const [data, setData] = React.useState([]);

    /**
     * Fetch data when component is mounted.
     * Pass in empty array as second paramater to prevent
     * infinite callbacks as component refreshes.
     * @see Fetching
     */
    React.useEffect(() => {
      fetch(SOURCE).then(res => setData(res.json())).catch(setData([]));
    }, []);

    return (

        {data.map(snapshotData => <BuildSnapshot buildData={snapshotData}/>)}

    );
  }
);

import * as React from "react";
import {BuildSnapshot} from "./BuildSnapshot";

/**
 * Container Component for BuildSnapshots.
 *
 * @param {*} props input property containing an array of build data to be
 * rendered through BuildSnapshot.
 */
export const BuildSnapshotContainer = React.memo((props) =>
  {
    const SOURCE = '/builders';
    const [data, setData] = React.useState([]);

    /**
     * Fetch data when component is mounted.
     * Pass in empty array as second paramater to prevent
     * infinite callbacks as component refreshes.
     * @see Fetching
     */
    React.useEffect(() => {
      fetch(SOURCE)
      .then(res => res.json())
      .then(json => setData(json))
      .catch(setData([]));
    }, []);

    return (

        {data.map(snapshotData => <BuildSnapshot buildData={snapshotData}/>)}

    );
  }
);

Resolve promise before setting JSON


const db = function () {
    let localData = JSON.parse(localStorage.getItem("data"));
    return localData || { index: 0 };
};
let server = {
    add(item) {
        const data = db();
        data.index++;
        debugger;
        item.id = data.index;
        data[data.index] = item;
        localStorage.setItem("data", JSON.stringify(data));
        return data;
    },
    update(item) {
        const id = item.id;
        const data = db();
        data[id] = item;
        localStorage.setItem("data", JSON.stringify(data));
        return data;
    },
    delete(id) {
        const data = db();
        delete data[id];
        localStorage.setItem("data", JSON.stringify(data));
        return data;
    },
    getData(){
        return db();
    }
};

export default server;

const db = function () {
    let localData = JSON.parse(localStorage.getItem("data"));
    return localData || { index: 0 };
};
const save = function (data) {
    localStorage.setItem("data", JSON.stringify(data));
};
let server = {
    add(item) {
        const data = db();
        data.index++;
        item.id = data.index;
        data[data.index] = item;
        save(data);
        return data;
    },
    update(item) {
        const id = item.id;
        const data = db();
        data[id] = item;
        save(data);
        return data;
    },
    delete(id) {
        const data = db();
        delete data[id];
        save(data);
        return data;
    },
    getData() {
        return db();
    }
};

export default server;

Add save method to temp db serv


/**
 * The MIT License (MIT)
 * Copyright (c) 2015-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
 */

// To require local modules from root.
global.ROOT = __dirname + '/';

// Tokenizer.
export {default as Tokenizer} from './tokenizer';

// Grammar classes.
export {default as Grammar} from './grammar/grammar';
export {default as GrammarSymbol} from './grammar/grammar-symbol';
export {default as LexRule} from './grammar/lex-rule';
export {default as Production} from './grammar/production';

// Sets generator.
export {default as SetsGenerator} from './sets-generator';

// LR parsing.
export {default as CanonicalCollection} from './lr/canonical-collection';
export {default as Closure} from './lr/closure';
export {default as LRItem} from './lr/lr-item';
export {default as LRParser} from './lr/lr-parser';
export {default as LRParsingTable} from './lr/lr-parsing-table';

// LL parsing.
export {default as LLParsingTable} from './ll/ll-parsing-table';

/**
 * The MIT License (MIT)
 * Copyright (c) 2015-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
 */

// To require local modules from root.
global.ROOT = __dirname + '/';

// Tokenizer.
export {default as Tokenizer} from './tokenizer';

// Grammar classes.
export {default as Grammar} from './grammar/grammar';
export {default as GrammarSymbol} from './grammar/grammar-symbol';
export {default as LexRule} from './grammar/lex-rule';
export {default as Production} from './grammar/production';

// Sets generator.
export {default as SetsGenerator} from './sets-generator';

// LR parsing.
export {default as CanonicalCollection} from './lr/canonical-collection';
export {default as State} from './lr/state';
export {default as LRItem} from './lr/lr-item';
export {default as LRParser} from './lr/lr-parser';
export {default as LRParsingTable} from './lr/lr-parsing-table';

// LL parsing.
export {default as LLParsingTable} from './ll/ll-parsing-table';

Remove reference to Closure, expose State instead


process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const ora = require('ora')
const rm = require('rimraf')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('../config/webpack')

const spinner = ora(`Building for env:${process.env.NODE_ENV}...`)
spinner.start()

module.exports = () => rm(path.join(config.paths.output, config.paths.assets), err => {
  if (err) throw err

  webpack(webpackConfig, (err, stats) => {
    spinner.stop()
    if (err) throw err

    console.log(stats.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }))

    console.log(chalk.cyan('  Build complete.\n'))
    console.log(chalk.yellow(
      '  Tip: built files are meant to be served over an HTTP server.\n' +
      '  Opening index.html over file:// won\'t work.\n'
    ))
  })
})

// Execute when root
if (!module.parent) {
  module.exports()
}

process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const ora = require('ora')
const rm = require('rimraf')
const chalk = require('chalk')
const webpack = require('webpack')
const config = require('../config')
const webpackConfig = require('../config/webpack')

const spinner = ora(`Building for env:${process.env.NODE_ENV}...`)
spinner.start()

module.exports = () => rm(config.paths.output, err => {
  if (err) throw err

  webpack(webpackConfig, (err, stats) => {
    spinner.stop()
    if (err) throw err

    console.log(stats.toString({
      colors: true,
      modules: false,
      children: false,
      chunks: false,
      chunkModules: false
    }))

    console.log(chalk.cyan('  Build complete.\n'))
    console.log(chalk.yellow(
      '  Tip: built files are meant to be served over an HTTP server.\n' +
      '  Opening index.html over file:// won\'t work.\n'
    ))
  })
})

// Execute when root
if (!module.parent) {
  module.exports()
}

Update @ Mon Mar 13 2017 11:13:52 GMT+0800 (CST)


import Ember from 'ember';

const {
  computed
} = Ember;

export default Ember.Component.extend({
  username: null,

  role: computed('username', function() {
    if (this.get('username').startsWith('@')) {
      return 'op';
    } else {
      return 'normal';
    }
  }),

  usernameWithoutPrefix: computed('username', function() {
    if (this.get('username').startsWith('@')) {
      return this.get('username').replace('@', '');
    } else {
      return this.get('username');
    }
  }),
});

import Ember from 'ember';

const {
  computed
} = Ember;

export default Ember.Component.extend({
  username: null,

  role: computed('username', function() {
    if (this.get('username').startsWith('@')) {
      return 'op';
    } else if (this.get('username').startsWith('%')) {
      return 'half-op';
    } else if (this.get('username').startsWith('+')) {
      return 'voice';
    } else {
      return 'normal';
    }
  }),

  usernameWithoutPrefix: computed('username', function() {
    if (this.get('username').startsWith('@')) {
      return this.get('username').replace('@', '');
    } else if (this.get('username').startsWith('%')) {
      return this.get('username').replace('%', '');
    } else if (this.get('username').startsWith('+')) {
      return this.get('username').replace('+', '');
    } else {
      return this.get('username');
    }
  }),
});

Support voices and half operators as well


import Ember from 'ember';

export default Ember.Controller.extend({
  title: null,
  competency: null,
  needs: ['programyear'],
  programYear: Ember.computed.alias("controllers.programyear"),
  competencies: function(){
    return this.get('programYear.competencies');
  }.property('programYear.competencies.[]'),
  actions: {
    save: function() {
      var objective = this.store.createRecord('objective', {
        title: this.get('title'),
        programYear: this.get('programYear.model'),
        competency: this.get('competency'),
      });
      this.get('programYear').get('objectives').addObject(objective);
      this.set('title', null);
      this.set('programYear.isDirty', true);
      this.transitionToRoute(
        'programyearobjectives.new',
        this.get('programYear.program'),
        this.get('programYear.model')
      );
    }
  }
});

import Ember from 'ember';

export default Ember.Controller.extend({
  title: null,
  competency: null,
  needs: ['programyear'],
  programYear: Ember.computed.alias("controllers.programyear"),
  competencies: function(){
    return this.get('programYear.competencies');
  }.property('programYear.competencies.[]'),
  actions: {
    save: function() {
      var competency = this.get('competency');
      if(competency == null){
        competency = this.get('competencies').get('firstObject');
      }
      var objective = this.store.createRecord('objective', {
        title: this.get('title'),
        programYear: this.get('programYear.model'),
        competency: competency,
      });
      this.get('programYear').get('objectives').addObject(objective);
      this.set('title', null);
      this.set('programYear.isDirty', true);
      this.transitionToRoute(
        'programyearobjectives.new',
        this.get('programYear.program'),
        this.get('programYear.model')
      );
    }
  }
});

Fix save objectve to use a default competency.


var request = require( 'request' );
module.exports = {
	commands: {
		isup: {
			aliases: [ 'get', 'web' ],
			privileged: true,
			help: 'Performs a HTTP(S) request to an arbitrary host.',
			usage: [ 'host' ],
			command: function ( bot, msg ) {
				request( msg.args.host, function ( err, res, body ) {
					if ( err ) {
						bot.say( msg.to, msg.nick + ': ' + err.message );
					} else {
						var str = 'HTTP/' + res.httpVersion + ' ' + res.req.method;
						str += ' ' + res.req.method + ' ' + res.request.href;
						str += + ' → ' + res.statusCode;

						var flag = '';
						try {
							var headers = [
								res.headers['content-type'],
								res.headers.server,
								body.length
							];
							str += headers.join( ' · ' );
						} catch ( e ) {
							flag = '!';
						}
						bot.say( msg.to, msg.nick + ': ' + str + flag );
					}
				} );
			}
		}
	}
};

var request = require( 'request' );
module.exports = {
	commands: {
		isup: {
			aliases: [ 'get', 'web' ],
			privileged: true,
			help: 'Performs a HTTP(S) request to an arbitrary host.',
			usage: [ 'host' ],
			command: function ( bot, msg ) {
				request( msg.args.host, function ( err, res, body ) {
					if ( err ) {
						bot.say( msg.to, msg.nick + ': ' + err.message );
					} else {
						var str = 'HTTP/' + res.httpVersion;
						str += ' ' + res.req.method + ' ' + res.request.href;
						str += ' → ' + res.statusCode;

						var flag = '';
						try {
							var headers = [
								res.headers['content-type'],
								res.headers.server,
								body.length
							];
							str += ' ' + headers.join( ' · ' );
						} catch ( e ) {
							flag = '!';
						}
						bot.say( msg.to, msg.nick + ': ' + str + flag );
					}
				} );
			}
		}
	}
};

Remove dupe vars and bad syntax; tidy string


import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

class Icon extends PureComponent {
  render() {
    const { children, className, color, tint, opacity, ...others } = this.props;

    const classNames = cx(theme[color], theme[tint], className);

    return (
      <Box className={classNames} data-teamleader-ui="icon" element="span" {...others}>
        {React.Children.map(children, child => {
          // Check if child is an actual React component
          // if so, pass the needed props. If not, just render it.
          if (!child.type) {
            return child;
          }

          return React.cloneElement(child, {
            opacity,
          });
        })}
      </Box>
    );
  }
}

Icon.propTypes = {
  children: PropTypes.any,
  className: PropTypes.string,
  color: PropTypes.oneOf(['neutral', 'mint', 'violet', 'ruby', 'gold', 'aqua', 'teal']),
  opacity: PropTypes.number,
  tint: PropTypes.oneOf(['lightest', 'light', 'normal', 'dark', 'darkest']),
};

Icon.defaultProps = {
  color: 'teal',
  tint: 'normal',
  opacity: 0.84,
};

export default Icon;

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import Box from '../box';
import cx from 'classnames';
import theme from './theme.css';

class Icon extends PureComponent {
  render() {
    const { children, className, color, tint, opacity, ...others } = this.props;

    const classNames = cx(theme[color], theme[tint], className);

    return (
      <Box
        className={classNames}
        alignItems="center"
        data-teamleader-ui="icon"
        display="flex"
        element="span"
        {...others}
      >
        {React.Children.map(children, child => {
          // Check if child is an actual React component
          // if so, pass the needed props. If not, just render it.
          if (!child.type) {
            return child;
          }

          return React.cloneElement(child, {
            opacity,
          });
        })}
      </Box>
    );
  }
}

Icon.propTypes = {
  children: PropTypes.any,
  className: PropTypes.string,
  color: PropTypes.oneOf(['neutral', 'mint', 'violet', 'ruby', 'gold', 'aqua', 'teal']),
  opacity: PropTypes.number,
  tint: PropTypes.oneOf(['lightest', 'light', 'normal', 'dark', 'darkest']),
};

Icon.defaultProps = {
  color: 'teal',
  tint: 'normal',
  opacity: 0.84,
};

export default Icon;

Use flex to fix vertical alignment issue


import labels from '../../../lib/drawer/labels';

describe('Labels drawer', () => {
    const scales = {
        x: d3.time.scale(),
        y: d3.scale.ordinal(),
    };

    const config = {
        labelsWidth: 50,
    };

    const domain = [new Date('2014-01-01'), new Date('2014-05-01')];
    const data = [{ name: 'foo', dates: domain }];

    let svg;
    let container;

    beforeEach(() => {
        svg = d3.select('body').append('svg');
        svg.append('g').classed('extremum', true);

        container = svg
            .append('g')
            .classed('labels', true)
            .attr('transform', 'translate(0, 45)');
    });

    it('should apply labelsWidth config', () => {
        scales.x.domain(domain);
        labels(container, scales, config)(data);
        expect(+svg.select('.label').attr('x')).toBe(50);
    });
});

import labels from '../../../lib/drawer/labels';

describe('Labels drawer', () => {
    const scales = {
        x: d3.time.scale(),
        y: d3.scale.ordinal(),
    };

    const config = {
        labelsWidth: 50,
    };

    const domain = [new Date('2014-01-01'), new Date('2014-05-01')];
    const data = [{ name: 'foo', dates: domain }];

    let svg;
    let container;

    beforeEach(() => {
        d3.select('body').html('');
        svg = d3.select('body').append('svg');
        svg.append('g').classed('extremum', true);

        container = svg
            .append('g')
            .classed('labels', true)
            .attr('transform', 'translate(0, 45)');
    });

    it('should apply labelsWidth config', () => {
        scales.x.domain(domain);
        labels(container, scales, config)(data);
        expect(+svg.select('.label').attr('x')).toBe(50);
    });

    it('should show label count with complex data', () => {
        const config =  {
            date: d => d.date
        };
        const complexData = [{ name: 'foo', data: [{ test: 'bar', date: new Date('2014-02-01') }, { test: 'baz', date: new Date('2014-03-01') }]}];

        scales.x.domain(domain);
        labels(container, scales, config)(complexData);

        //expect(div.querySelector('.extremum .minimum').textContent).toBe('25 January 2010');
        expect(document.querySelector('.label').textContent).toBe('foo (2)');

    });
});

Add unit test for label event count (complex data)


'use strict';

angular.module('ccj16reg.view.registration', ['ngRoute', 'ngMaterial', 'ccj16reg.registration'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/registration/:securityKey', {
		templateUrl: 'views/registration/registration.html',
		controller: 'RegistrationCtrl',
		resolve: {
			'registrationData': function($route, $location, registration) {
				return registration.get({securityKey: $route.current.params.securityKey});
			},
		},
	});
}])

.controller('RegistrationCtrl', function($scope, $routeParams, $window, registrationData) {
	$scope.registration = registrationData;
	$scope.$emit('CurrentGroupInformationChanged', registrationData);
	$scope.printPage = function() {
		$window.print();
	};
});

'use strict';

angular.module('ccj16reg.view.registration', ['ngRoute', 'ngMaterial', 'ccj16reg.registration'])

.config(['$routeProvider', function($routeProvider) {
	$routeProvider.when('/registration/:securityKey', {
		templateUrl: 'views/registration/registration.html',
		controller: 'RegistrationCtrl',
		resolve: {
			'registrationData': function($route, $location, registration) {
				return registration.get({securityKey: $route.current.params.securityKey}).$promise;
			},
		},
	});
}])

.controller('RegistrationCtrl', function($scope, $routeParams, $window, registrationData) {
	$scope.registration = registrationData;
	$scope.$emit('CurrentGroupInformationChanged', registrationData);
	$scope.printPage = function() {
		$window.print();
	};
});

Make sure to return the promise when in a resolve function.


function Vnode(tag, key, attrs, children, text, dom) {
	return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false}
}
Vnode.normalize = function(node) {
	if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)
	if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node, undefined, undefined)
	return node
}
Vnode.normalizeChildren = function normalizeChildren(children) {
	for (var i = 0; i < children.length; i++) {
		children[i] = Vnode.normalize(children[i])
	}
	return children
}

module.exports = Vnode

function Vnode(tag, key, attrs, children, text, dom) {
	return {tag: tag, key: key, attrs: attrs, children: children, text: text, dom: dom, domSize: undefined, state: {}, events: undefined, instance: undefined, skip: false}
}
Vnode.normalize = function(node) {
	if (Array.isArray(node)) return Vnode("[", undefined, undefined, Vnode.normalizeChildren(node), undefined, undefined)
	if (node != null && typeof node !== "object") return Vnode("#", undefined, undefined, node === false ? "" : node, undefined, undefined)
	return node
}
Vnode.normalizeChildren = function normalizeChildren(children) {
	for (var i = 0; i < children.length; i++) {
		children[i] = Vnode.normalize(children[i])
	}
	return children
}

module.exports = Vnode

Return empty string node for `false` values


var express = require('express');
var Global = require('../global');
var search = require('../commands/search');

var router = express.Router();

router.get('/*', function(req, res) {
    var response = '';
    var arg = req.body.text;
console.log(req.body); //TODO delete
console.log(req.body.token); //TODO delete
    //validate token
    if(req.body.token === Global.authToken) {
        switch(req.body.command) {
            case '/searchin':
                response = search(arg, res);
                break;

            default:
            res.status('500');
            res.json({
                text: 'Unknown command'
            });
        }
    } else {
        res.status('403');
        res.json({
            text: 'Invalid token'
        });
    }
});

module.exports = router;

var express = require('express');
var Global = require('../global');
var search = require('../commands/search');

var router = express.Router();

router.get('/*', function(req, res) {
    var response = '';
    var arg = req.body.text;
console.log(req.body); //TODO delete
console.log(req.body.token); //TODO delete
    //validate token
    if(req.body.token === Global.authToken) {
        switch(req.body.command) {
            case '/searchin':
                response = search(arg, res);
                break;

            default:
            res.status('500');
            res.json({
                text: 'Unknown command'
            });
        }
    } else {
        res.status('403');
        res.json({
            text: 'Invalid token'
        });
    }
});

router.post('/*', function(req, res) {
    res.status('405');
    res.json({
        text: 'Method not allowed'
    });
});

module.exports = router;

Change HTTP method to GET


/*
 * Helper functions to integrate Python unittest test cases with QUnit
 */

;(function() {
  this.qunit_unittest_wrapper = function(test, result) {
    return function(assert) {
        test_call =  __BRYTHON__.builtins.getattr(test, '__call__')
        test_call(result);
        var msg = '';
        if (result.details !== __BRYTHON__.builtins.None) {
            msg = '[' + result.lastOutcome + '] - ' + result.details;
        }
        assert.ok(__BRYTHON__.builtins.getattr(result, 'wasSuccessful')(),
                  msg)
    }
  }

  if (this['define'] !== undefined && (typeof this.define['amd'] === 'object')) {
    // Running AMD loader
    define({
      qunit_unittest_wrapper : this.qunit_unittest_wrapper
    })
  }
})()

/*
 * Helper functions to integrate Python unittest test cases with QUnit
 */

;(function() {
  this.qunit_unittest_wrapper = function(test, result) {
    return function(assert) {
        test_call =  __BRYTHON__.builtins.getattr(test, '__call__')
        test_call(result);
        var msg = '';
        if (result.details !== __BRYTHON__.builtins.None) {
            msg = '[' + result.lastOutcome + '] - ' + result.details;
        }
        assert.js.ok(__BRYTHON__.builtins.getattr(result, 'wasSuccessful')(),
                  msg)
    }
  }

  if (this['define'] !== undefined && (typeof this.define['amd'] === 'object')) {
    // Running AMD loader
    define({
      qunit_unittest_wrapper : this.qunit_unittest_wrapper
    })
  }
})()

Fix CI (broken by commit 1ad75b346e97a19)


import Ember from 'ember';
import layout from '../templates/components/ember-favourite-heart';

export default Ember.Component.extend({
  layout: layout,
  liked: false,
  likeCount: 0,

  heartClass: function(){
    if(this.get('liked')){
      return "heart heartAnimation";
    }else{
      return "heart";
    }
  }.property('liked'),

  heartStyle: function(){
    if(this.get('liked')){
      return "";
    }else{
      return "background-position: 0% 50%;";
    }
  }.property('liked'),

  like: function(){
    this.set('liked', true);
    this.set('likeCount', this.get('likeCount') + 1);
  },

  unlike: function(){
    this.set('liked', false);
    this.set('likeCount', this.get('likeCount') - 1);
  },

  actions: {
    toggleFav: function(){
      if(this.get('liked')){
        this.unlike();
      }else{
        this.like();
      }
      this.sendAction();
    }
  }
});

import Ember from 'ember';
import layout from '../templates/components/ember-favourite-heart';

export default Ember.Component.extend({
  layout: layout,
  liked: false,
  likeCount: 0,

  heartClass: Ember.computed('liked', function() {
    if(this.get('liked')){
      return "heart heartAnimation";
    }else{
      return "heart";
    }
  }),

  heartStyle: Ember.computed('liked', function() {
    if(this.get('liked')){
      return "";
    }else{
      return "background-position: 0% 50%;";
    }
  }),

  like: function(){
    this.set('liked', true);
    this.set('likeCount', this.get('likeCount') + 1);
  },

  unlike: function(){
    this.set('liked', false);
    this.set('likeCount', this.get('likeCount') - 1);
  },

  actions: {
    toggleFav: function(){
      if(this.get('liked')){
        this.unlike();
      }else{
        this.like();
      }
      this.sendAction();
    }
  }
});

Use Ember.computed instead of using prototype extension


import axios from 'axios';

export const HTTP = axios.create({
});

import axios from 'axios';

// disable IE ajax request caching
axios.defaults.headers.get['If-Modified-Since'] = '0';

export const HTTP = axios.create({
});

Disable IE ajax request caching


function loadTheFrame() {
    document.getElementById('upper-left').src = window.localStorage.getItem('upper-left');
    document.getElementById('upper-right').src = window.localStorage.getItem('upper-right');
    document.getElementById('lower-left').src = window.localStorage.getItem('lower-left');
    document.getElementById('lower-right').src = window.localStorage.getItem('lower-right');
}

const BOXES = [
    'upper-right',
    'upper-left',
    'lower-right',
    'lower-left'
];

function loadTheFrame() {
    const searchParams = new URLSearchParams(location.search);

    BOXES.forEach(box => {
        if (searchParams.has(box)) {
            window.localStorage.setItem(box, searchParams.get(box))
        }
        document.getElementById(box).src = window.localStorage.getItem(box);
    });
}

Update with new functionality for quad view


// @flow

import PropTypes from 'prop-types';
import React from 'react';
import { StatusBar, Platform } from 'react-native';

import { globalLoadingStatusSelector } from 'lib/selectors/loading-selectors';
import type { LoadingStatus } from 'lib/types/loading-types';
import { connect } from 'lib/utils/redux-utils';

import type { AppState } from './redux/redux-setup';
import { type GlobalTheme, globalThemePropType } from './types/themes';

type Props = {|
  barStyle?: 'default' | 'light-content' | 'dark-content',
  animated?: boolean,
  // Redux state
  globalLoadingStatus: LoadingStatus,
  activeTheme: ?GlobalTheme,
|};
class ConnectedStatusBar extends React.PureComponent<Props> {
  static propTypes = {
    barStyle: PropTypes.oneOf(['default', 'light-content', 'dark-content']),
    animated: PropTypes.bool,
    globalLoadingStatus: PropTypes.string.isRequired,
    activeTheme: globalThemePropType,
  };

  render() {
    const {
      barStyle: inBarStyle,
      activeTheme,
      globalLoadingStatus,
      ...statusBarProps
    } = this.props;

    let barStyle = inBarStyle;
    if (!barStyle) {
      if (Platform.OS !== 'android' && this.props.activeTheme === 'light') {
        barStyle = 'dark-content';
      } else {
        barStyle = 'light-content';
      }
    }

    const fetchingSomething = this.props.globalLoadingStatus === 'loading';
    return (
      <StatusBar
        {...statusBarProps}
        barStyle={barStyle}
        networkActivityIndicatorVisible={fetchingSomething}
      />
    );
  }
}

export default connect((state: AppState) => ({
  globalLoadingStatus: globalLoadingStatusSelector(state),
  activeTheme: state.globalThemeInfo.activeTheme,
}))(ConnectedStatusBar);

// @flow

import React from 'react';
import { StatusBar, Platform } from 'react-native';

import { globalLoadingStatusSelector } from 'lib/selectors/loading-selectors';

import { useSelector } from './redux/redux-utils';

type Props = {|
  +barStyle?: 'default' | 'light-content' | 'dark-content',
  +animated?: boolean,
  +hidden?: boolean,
|};
export default function ConnectedStatusBar(props: Props) {
  const globalLoadingStatus = useSelector(globalLoadingStatusSelector);
  const activeTheme = useSelector((state) => state.globalThemeInfo.activeTheme);
  const { barStyle: inBarStyle, ...statusBarProps } = props;

  let barStyle = inBarStyle;
  if (!barStyle) {
    if (Platform.OS !== 'android' && activeTheme === 'light') {
      barStyle = 'dark-content';
    } else {
      barStyle = 'light-content';
    }
  }

  const fetchingSomething = globalLoadingStatus === 'loading';
  return (
    <StatusBar
      {...statusBarProps}
      barStyle={barStyle}
      networkActivityIndicatorVisible={fetchingSomething}
    />
  );
}

Use hook instead of connect functions and HOC in ConnectedStatusBar


// @flow
import React from 'react'
import {Box, CopyableText, Text} from '../../../common-adapters'
import {globalStyles, globalMargins} from '../../../styles'

export type Props = {
  conversationErrorText: string,
}

const ConversationError = ({conversationErrorText}: Props) => (
  <Box style={styleContainer}>
    <Text type="Header">There was an error loading this conversation.</Text>
    <Text style={styleBody} type="Body">The error is:</Text>
    <Box style={styleErrorBox}>
      <CopyableText style={styleErrorText} value={conversationErrorText} />
    </Box>
  </Box>
)

const styleContainer = {
  ...globalStyles.flexBoxColumn,
  padding: globalMargins.medium,
  width: '100%',
}

const styleBody = {
  marginTop: globalMargins.small,
}

const styleErrorBox = {
  ...globalStyles.flexBoxRow,
  marginTop: globalMargins.small,
}

const styleErrorText = {
  flexGrow: 1,
}

export default ConversationError

// @flow
import React from 'react'
import {Box, CopyableText, HeaderHoc, Text} from '../../../common-adapters'
import {globalStyles, globalMargins} from '../../../styles'

export type Props = {
  conversationErrorText: string,
}

const ConversationError = ({conversationErrorText}: Props) => (
  <Box style={styleContainer}>
    <Text type="Header">There was an error loading this conversation.</Text>
    <Text style={styleBody} type="Body">The error is:</Text>
    <Box style={styleErrorBox}>
      <CopyableText style={styleErrorText} value={conversationErrorText} />
    </Box>
  </Box>
)

const styleContainer = {
  ...globalStyles.flexBoxColumn,
  padding: globalMargins.medium,
  width: '100%',
}

const styleBody = {
  marginTop: globalMargins.small,
}

const styleErrorBox = {
  ...globalStyles.flexBoxRow,
  marginTop: globalMargins.small,
}

const styleErrorText = {
  flexGrow: 1,
}

export default HeaderHoc(ConversationError)

Add HeaderHoc to ConversationError component so you can navigate back


'use strict';

/**
 * Removes server error when user updates input
 */
angular.module('its110App')
  .directive('mongooseError', function () {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function (scope, element, attrs, ngModel) {
        element.on('keydown', function () {
          return ngModel.$setValidity('mongoose', true);
        });
      }
    };
  });

'use strict';

/**
 * Removes server error when user updates input
 */
angular.module('bitfit.directives.mongoose-error')
  .directive('mongooseError', function () {
    return {
      restrict: 'A',
      require: 'ngModel',
      link: function (scope, element, attrs, ngModel) {
        element.on('keydown', function () {
          return ngModel.$setValidity('mongoose', true);
        });
      }
    };
  });

Update mongoose error module name


/*
---

script: Grid.js

description: Filters and sort datasets (and widgets)

license: Public domain (http://unlicense.org).

requires:
  - LSD

provides:
  - LSD.Trait.Grid

...
*/

LSD.Trait.Grid = new Class({

  sort: function() {

  },

  filter: function() {

  }

});

Add grid trait file header