/* eslint-env jest */

import React from 'react';
import { mountWithTheme } from 'styled-enzyme';

import DatePicker from './DatePicker';

describe('DatePicker component', () => {
  let instance;
  let input;
  const handleOnChange = jest.fn();
  const handleOnChangeRaw = jest.fn();
  const mockOnChangeRawEvent = { target: { value: 'some date' } };
  const mockOnChangeEvent = { target: { value: '10/12/2017' } };
  /* eslint-disable jsx-a11y/use-onblur-not-onchange */
  beforeEach(() => {
    instance = mountWithTheme(
      <DatePicker
        labelText="Test Date"
        onChange={handleOnChange}
        onChangeRaw={handleOnChangeRaw}
      />
    );

    input = instance.find('input');
    handleOnChange.mockClear();
    handleOnChangeRaw.mockClear();
  });
  /* eslint-enable */
  it('executes the handleOnChange function when valid date is entered', () => {
    input.simulate('change', mockOnChangeEvent);
    expect(handleOnChange).toBeCalled();
  });

  it('does not execute handleOnChange unless date is valid', () => {
    input.simulate('change', mockOnChangeRawEvent);
    expect(handleOnChange).not.toBeCalled();
  });

  it('executes the handleOnChangeRaw function when any input is entered', () => {
    input.simulate('change', mockOnChangeRawEvent);
    expect(handleOnChangeRaw).toBeCalled();
  });
});

/* eslint-env jest */

import React from 'react';
import { render } from 'react-testing-library';
import { ThemeProvider } from 'styled-components';
import viaTheme from 'es-components-via-theme';
import moment from 'moment';

import DatePicker from './DatePicker';

it('renders DatePicker when textbox is focused', () => {
  const { getByLabelText, queryByText } = render(
    <ThemeProvider theme={viaTheme}>
      <DatePicker
        labelText="Test date"
        onChange={jest.fn()}
        selectedDate={moment(new Date(2018, 10, 7))}
      />
    </ThemeProvider>
  );
  getByLabelText('Test date').focus();
  expect(queryByText('November 2018')).not.toBeNull();
});

Change Datepicker to use react-testing-library


CKEDITOR.config.extraPlugins = "structuredheadings";

var initSample = ( function() {

    return function() {
      var editorElement = CKEDITOR.document.getById("editor");
      CKEDITOR.replace("editor");
    };
})();

/* exported initSample */
CKEDITOR.config.extraPlugins = "structuredheadings";

var initSample = function () {
  CKEDITOR.replace("editor");
  return;
};

Make ESLint happy with Main.js


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

module.exports = function() {

  db.serialize(function() {
    db.run("CREATE TABLE IF NOT EXISTS users (username TEXT, hashed_password BLOB, salt BLOB, name TEXT)");
  });

  //db.close();

};

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

module.exports = function() {

  db.serialize(function() {
    db.run("CREATE TABLE IF NOT EXISTS users ( \
      username TEXT UNIQUE, \
      hashed_password BLOB, \
      salt BLOB, \
      name TEXT \
    )");
  });

  //db.close();

};

Add unique constraint on username.


process.title = "note-my-strength-api";

const http = require("http");

const PORT = 8088;

http.createServer(function (req, res) {
    console.log("Listening on port: " + PORT);
    res.writeHead(200, {"Content-Type": "text/html"});
    res.write("<hi>Hello World!</hi>");
    res.end();
}).listen(PORT, function (err) {
    if (err) {
        console.log(err);
    } else {
        console.log("Listening on port: " + PORT);
    }
});

process.title = "note-my-strength-api";

const http = require("http");

const PORT = 8088;

http.createServer(function (req, res) {
    console.log("Listening on port: " + PORT);
    res.writeHead(200, {"Content-Type": "text/html"});
    res.write("
Hello World!
");
    res.end();
}).listen(PORT, function (err) {
    if (err) {
        console.log(err);
    } else {
        console.log("Listening on port: " + PORT);
    }
});

Update file to test Jenkins


var pstarter = require('pstarter');

pstarter.startMaster(__dirname + '/config', {}, function() {
	var config = require('./config');
	pstarter.statServer(config.http.statPort, config.http.statHost);
	if (process.env['NODE_ENV'] && process.env['NODE_ENV'] === 'development') {
		pstarter.startWatch(__dirname, [__dirname +'/node_modules'], ['.js', '.json', '.html', '.css']);
	}
}).startWorker(function() {
	var config = require('./config');
	var express = require('express');
	var app = express();
	var http = require('http');
	var server = http.createServer(app);
	var bootstrap = require('./app/bootstrap.js');
	bootstrap.setupApp(app, __dirname);
	bootstrap.bootstrap(app);
	bootstrap.postrun();
	server.listen(config.http.port, config.http.host);
	/* Counting request */
	server.on('request', function(req, res) {
		process.send({
			cmd : pstarter.cmd.requestCount
		});
	});
});

var worker = function() {
	var config = require('./config');
	var express = require('express');
	var app = express();
	var http = require('http');
	var server = http.createServer(app);
	var bootstrap = require('./app/bootstrap.js');
	bootstrap.setupApp(app, __dirname);
	bootstrap.bootstrap(app);
	bootstrap.postrun();
	server.listen(config.http.port, config.http.host);
};

/* run only one single process and worker for debug */
if('worker' in process.env) {
	worker();
} else {
	var pstarter = require('pstarter');
	pstarter.startMaster(__dirname + '/config', {}, function() {
		var config = require('./config');
		pstarter.statServer(config.http.statPort, config.http.statHost);
		if(process.env['NODE_ENV'] && process.env['NODE_ENV'] === 'development') {
			pstarter.startWatch(__dirname, [__dirname + '/node_modules'], ['.js', '.json', '.html', '.css']);
		}

	}).startWorker(function() {
		worker();
		/* Counting request */
		server.on('request', function(req, res) {
			process.send({
				cmd : pstarter.cmd.requestCount
			});
		});
	});
}

Add posibility to run only worker for debug


/**
 * @module server.config
 */

'use strict'

// A list with the folder name of the services to load
const defaultServices = [
  'routes',
  'user'
]

const readServices = () => {
  const services = process.env.NODEJS_API_SERVICES
  return services ? services.split(' ') : defaultServices
}

const config = {
  port: process.env.OPENSHIFT_NODEJS_PORT || process.env.NODEJS_API_PORT || 8080,
  ip: process.env.OPENSHIFT_NODEJS_IP || undefined,
  services: readServices()
}

// Test and log app settings
if (process.env.NODE_ENV !== 'test') {
  // eslint-disable-next-line no-console
  console.log('\nserver.config:', JSON.stringify(config, null, ' '))
}

module.exports = Object.freeze(config)

/**
 * @module server.config
 */

'use strict'

const fs = require('fs')
const path = require('path')

const getDirectories = srcpath => (
  fs.readdirSync(srcpath)
    .filter(file => fs.lstatSync(path.join(srcpath, file)).isDirectory())
)

// A list with the folder name of the services to load
const defaultServices = getDirectories(path.join(__dirname, 'functions'))

const readServices = () => {
  const services = process.env.NODEJS_API_SERVICES
  return services ? services.split(' ') : defaultServices
}

const config = {
  port: process.env.OPENSHIFT_NODEJS_PORT || process.env.NODEJS_API_PORT || 8080,
  ip: process.env.OPENSHIFT_NODEJS_IP || undefined,
  services: readServices()
}

// Test and log app settings
if (process.env.NODE_ENV !== 'test') {
  // eslint-disable-next-line no-console
  console.log('\nserver.config:', JSON.stringify(config, null, ' '))
}

module.exports = Object.freeze(config)

Implement detection of services in funcitons folder.


import React, { Component } from 'react';
import TwitterLogin from 'react-twitter-auth/lib/react-twitter-auth-component.js';

class App extends Component {

  constructor() {
    super();

    this.onFailed = this.onFailed.bind(this);
    this.onSuccess = this.onSuccess.bind(this);
  }

  onSuccess(response) {
    response.json().then(body => {
      alert(JSON.stringify(body));
    });
  }

  onFailed(error) {
    alert(error);
  }

  render() {
    const customHeader = {};
    customHeader['Test'] = 'test-header';
    return (

        <TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
                      onFailure={this.onFailed}
                      onSuccess={this.onSuccess}
                      requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
                      showIcon={true}
                      customHeaders={customHeader}
                      forceLogin={false}/>

        <TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
                      onFailure={this.onFailed}
                      onSuccess={this.onSuccess}
                      requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
                      showIcon={true}
                      customHeaders={customHeader}>
          Custom Twitter Login content
        </TwitterLogin>

    );
  }
}

export default App;

import React, { Component } from 'react';
import TwitterLogin from 'react-twitter-auth/lib/react-twitter-auth-component.js';

class App extends Component {

  constructor() {
    super();

    this.onFailed = this.onFailed.bind(this);
    this.onSuccess = this.onSuccess.bind(this);
  }

  onSuccess(response) {
    response.json().then(body => {
      alert(JSON.stringify(body));
    });
  }

  onFailed(error) {
    alert(error);
  }

  render() {
    const customHeader = {};
    customHeader['Test'] = 'test-header';
    return (

        <TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
                      onFailure={this.onFailed}
                      onSuccess={this.onSuccess}
                      requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
                      showIcon={true}
                      customHeaders={customHeader}
                      forceLogin={true}/>

        <TwitterLogin loginUrl="http://localhost:4000/api/v1/auth/twitter"
                      onFailure={this.onFailed}
                      onSuccess={this.onSuccess}
                      requestTokenUrl="http://localhost:4000/api/v1/auth/twitter/reverse"
                      showIcon={true}
                      customHeaders={customHeader}>
          Custom Twitter Login content
        </TwitterLogin>

    );
  }
}

export default App;

Improve example to showcase forceLogin


import dir from 'node-dir';
import watch from 'watch';
import path from 'path';
import commandLineArgs from 'command-line-args';

const cli = commandLineArgs([
    {
        name: 'dir',
        alias: 'd',
        type: String
    }
]);
const options = cli.parse();

function processFile(file) {
    console.log('file:', file);
    const [artist, album, songFile] = path.relative(options.dir, file).split(path.sep);
    console.log('artist:', artist);
    console.log('album:', album);
    console.log('song file:', songFile);
}

dir.files(options.dir, function(err, files) {
    if (err) {
        console.log(err);
        return;
    }

    if (files) {
        files.forEach((file) => {
            processFile(file);
        });
    }
});

watch.createMonitor(options.dir, function(monitor) {
    monitor.on('created', function(file) {
        processFile(file);
    });

    monitor.on('removed', function(file) {
        processFile(file);
    });
});

import dir from 'node-dir';
import watch from 'watch';
import path from 'path';
import commandLineArgs from 'command-line-args';

const cli = commandLineArgs([
    {
        name: 'dir',
        alias: 'd',
        type: String
    }
]);
const options = cli.parse();

const hostedFiles = {};

function processFile(file) {
    const [artist, album, songFile] = path.relative(options.dir, file).split(path.sep);
    hostedFiles[artist] = hostedFiles[artist] || {};
    hostedFiles[artist][album] = hostedFiles[artist][album] || [];
    hostedFiles[artist][album].push(songFile);
}

dir.files(options.dir, function(err, files) {
    if (err) {
        console.log(err);
        return;
    }

    if (files) {
        files.forEach((file) => {
            processFile(file);
        });
    }
    console.log(hostedFiles);
});

watch.createMonitor(options.dir, function(monitor) {
    monitor.on('created', function(file) {
        console.log('adding a new file:', file);
    });

    monitor.on('removed', function(file) {
        console.log('removing file:', file);
    });
});

Create a map of hosted files at client startup


import nodeFetch from 'node-fetch'
import app from '../server'

describe('server', () => {
  function fetch (path, init) {
    return nodeFetch(`http://localhost:3000${path}`, init)
  }

  let server

  beforeAll(done => {
    server = app.listen(3000, done)
  })

  afterAll(done => server.close(done))

  describe('GET /', () => {
    it('responds with success', () => {
      return expect(fetch('/')).resolves.toHaveProperty('status', 200)
    })
  })

  describe('GET /index.json', () => {
    it('responds with features', () => {
      return fetch('/index.json', {
        headers: { 'Content-Type': /json/ }
      }).then(response => {
        expect(response.status).toBe(200)
        return expect(response.json()).resolves.not.toHaveLength(0)
      })
    })
  })

  describe('GET /404', () => {
    it('responds with a 404 error', () => {
      return expect(fetch('/404')).resolves.toHaveProperty('status', 404)
    })
  })
})

import nodeFetch from 'node-fetch'
import app from '../server'

describe('server', () => {
  function fetch (path, init) {
    return nodeFetch(`http://localhost:3000${path}`, init)
  }

  let server

  beforeAll(done => {
    server = app.listen(3000, done)
  })

  afterAll(done => {
    server.close(done)
  })

  describe('GET /', () => {
    it('responds with success', () => {
      return expect(fetch('/')).resolves.toHaveProperty('status', 200)
    })
  })

  describe('GET /index.json', () => {
    it('responds with features', () => {
      return fetch('/index.json', {
        headers: { 'Content-Type': /json/ }
      }).then(response => {
        expect(response.status).toBe(200)
        return expect(response.json()).resolves.not.toHaveLength(0)
      })
    })
  })

  describe('GET /404', () => {
    it('responds with a 404 error', () => {
      return expect(fetch('/404')).resolves.toHaveProperty('status', 404)
    })
  })
})

Fix another incorrect test setup


import { mongo } from 'meteor/mongo';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';

class GraduationRequirementCollection extends Mongo.Collection {}

const GraduationRequirements = new GraduationRequirementCollection('gradiationRequirement');

const gradRequirementSchema = {
  requirementName: {
    type: String
  },
  requirementModules: {
    type: [object],
    optional: true
  }
}

GraduationRequirements.attachSchema(gradRequirementSchema);

import { mongo } from 'meteor/mongo';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';

/// This Component handles the initialization of the graduation requirement collection
/// requirementModule should be in he following format :
/// module code: boolean true/false
/// e.g : CS1231: false
/// the boolean is to indicate in the logic section if the following module requirement has been fulfilled

class GraduationRequirementCollection extends Mongo.Collection {}

const GraduationRequirements = new GraduationRequirementCollection('graduationRequirement');

const gradRequirementSchema = {
  requirementName: {
    type: String
  },
  requirementModules: {
    type: [Object],
    optional: true
  }
}

GraduationRequirements.attachSchema(gradRequirementSchema);

ADD collection description to the graduation Requirement database


import ciIcon from '../../vue_shared/components/ci_icon.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';

export default {
  props: {
    status: { type: String, required: true },
    showDisabledButton: { type: Boolean, required: false },
  },
  components: {
    ciIcon,
    loadingIcon,
  },
  computed: {
    statusObj() {
      return {
        group: this.status,
        icon: `icon_status_${this.status}`,
      };
    },
  },
  template: `

        <loading-icon />

      <ci-icon v-else :status="statusObj" />
      <button
        v-if="showDisabledButton"
        type="button"
        class="js-disabled-merge-button btn btn-success btn-sm"
        disabled="true">
        Merge
      </button>

  `,
};

import ciIcon from '../../vue_shared/components/ci_icon.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';

export default {
  props: {
    status: { type: String, required: true },
    showDisabledButton: { type: Boolean, required: false },
  },
  components: {
    ciIcon,
    loadingIcon,
  },
  computed: {
    statusObj() {
      return {
        group: this.status,
        icon: `status_${this.status}`,
      };
    },
  },
  template: `

        <loading-icon />

      <ci-icon v-else :status="statusObj" />
      <button
        v-if="showDisabledButton"
        type="button"
        class="js-disabled-merge-button btn btn-success btn-sm"
        disabled="true">
        Merge
      </button>

  `,
};

Fix missing MR widget status icons


document.addEventListener("DOMContentLoaded", function(event) {
    safari.self.addEventListener("message", messageHandler);
    safari.self.addEventListener("refreshVideoState",messageHandler);
});

safari.self.addEventListener("activate", tabChanged);

function messageHandler(event)
{
    if (event.name === "enablePiP") {
        document.querySelectorAll("video")[0].webkitSetPresentationMode("picture-in-picture");
    }

    else if (event.name == "checkForVideo"){
        lookForVideo();
    }
}

function lookForVideo(){
    if (window == window.top){
        if (isAVideoOnPage()){
            console.log("Found a video on top");
            safari.extension.dispatchMessage("videoFound");
        }
        else{
            console.log("Found no video on top");
            safari.extension.dispatchMessage("noVideoFound");
        }
    }
    else {
        if (isAVideoOnPage()){
            console.log("Found video somewhere else");
            safari.extension.dispatchMessage("videoFound");
        }
    }
}

function tabChanged(event)
{
    console.log("Changed a tab");
    safari.extension.dispatchMessage("tabChange");
}

//checks if there is a video on the page and returns true if there is one
function isAVideoOnPage(){
    if (document.querySelectorAll("video").length > 0){
        return true;
    }
    else{
        return false;
    }
}

document.addEventListener("DOMContentLoaded", function(event) {
    safari.self.addEventListener("message", messageHandler);
    safari.self.addEventListener("refreshVideoState",messageHandler);
});

safari.self.addEventListener("activate", tabChanged);

function messageHandler(event)
{
    if (event.name === "enablePiP") {
        document.querySelectorAll('video')[0].webkitSetPresentationMode('picture-in-picture');
    }

    else if (event.name == "checkForVideo"){
        lookForVideo();
    }
}

function lookForVideo(){
    if (window == window.top){
        if (isAVideoOnPage()){
            console.log("Found a video on top");
            safari.extension.dispatchMessage("videoFound");
        }
        else{
            console.log("Found no video on top");
            safari.extension.dispatchMessage("noVideoFound");
        }
    }
    else {
        if (isAVideoOnPage()){
            console.log("Found video somewhere else");
            safari.extension.dispatchMessage("videoFound");
        }
    }
}

function tabChanged(event)
{
    console.log("Changed a tab");
    safari.extension.dispatchMessage("tabChange");
}

//checks if there is a video on the page and returns true if there is one
function isAVideoOnPage(){
    if (document.querySelectorAll("video").length > 0){
        return true;
    }
    else{
        return false;
    }
}

Fix problem with english system


/* eslint-env node */
module.exports = {
  extends: ["@vue/typescript", "./typescript.js"],
  rules: {}
};

/* eslint-env node */
module.exports = {
  extends: ["./typescript.js", "@vue/typescript"],
  rules: {}
};

Fix order of TS extends for Vue


module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  graphQLRoot: (process.env.NODE_ENV === 'production') ? '//localhost:5000/graphql' : '//catapp-console.herokuapp.com/graphql',
};

module.exports = {
  backendRoot: 'https://obscure-woodland-71302.herokuapp.com/',
  graphQLRoot: (process.env.NODE_ENV === 'production') ? '//localhost:5000/graphql' : '//catappdatabase.herokuapp.com/graphql',
};
// Alternative: //catapp-console.herokuapp.com/graphql

Switch to using actual backend for now


var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: ["./js/main.js", "./css/main.scss"],
    output: {
        path: __dirname + "/build",
        filename: "main.js",
        publicPath: "/build"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" },
            { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel' },
            { test: /node_modules\/admin-config\/.*\.jsx?$/, loader: 'babel' },
            { test: /\.html$/, loader: 'html' },
            { test: /\.css$/, loader: ExtractTextPlugin.extract('css') },
            { test: /\.scss$/, loader: ExtractTextPlugin.extract('css!sass') }
        ]
    },
    plugins: [
        new ExtractTextPlugin('[name].css', {
            allChunks: true
        })
    ]
};

var ExtractTextPlugin = require('extract-text-webpack-plugin');
var sep = require('path').sep;

module.exports = {
    entry: ["./js/main.js", "./css/main.scss"],
    output: {
        path: __dirname + "/build",
        filename: "main.js",
        publicPath: "/build"
    },
    module: {
        loaders: [
            { test: /\.css$/, loader: "style!css" },
            { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, loader: 'babel' },
            { test: new RegExp('node_modules' + sep + 'admin-config' + sep + '.*\\.jsx?$'), loader: 'babel' },
            { test: /\.html$/, loader: 'html' },
            { test: /\.css$/, loader: ExtractTextPlugin.extract('css') },
            { test: /\.scss$/, loader: ExtractTextPlugin.extract('css!sass') }
        ]
    },
    plugins: [
        new ExtractTextPlugin('[name].css', {
            allChunks: true
        })
    ]
};

MAke build work on Windows platform


'use strict'

var path = require('path')
var node_modules = path.resolve(__dirname, 'node_modules')

// var production = process.argv.indexOf('--production') > -1

module.exports = {
  entry: path.resolve(__dirname, 'src/js/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: node_modules, loader: 'babel-loader' },
      { test: /\.scss$/, exclude: node_modules, loader: 'style!css!sass' }
    ]
  },
  devServer: { contentBase: './dist' }
}

'use strict'

var path = require('path')
var node_modules = path.resolve(__dirname, 'node_modules')

module.exports = {
  entry: path.resolve(__dirname, 'src/js/index.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: node_modules, loader: 'babel-loader?stage=0' },
      { test: /\.scss$/, exclude: node_modules, loader: 'style!css!sass' }
    ]
  },
  devServer: { contentBase: './dist' }
}

Add stage 0 to babel


Jobs = new Mongo.Collection('jobs'); //both on client and server
Applications = new Mongo.Collection('applications');

// added repoz channel

Meteor.startup(function() {
  // console.log('Jobs.remove({})');
  // Jobs.remove({});
  if (Jobs.find({}).count() === 0) {
    console.log('job count === ', Jobs.find({}).count(), 'inserting jobs');
    Jobs.insert({_id: '0', title: 'Select a job position...'});
    Jobs.insert({_id: '1', title: 'Haiti Village Photographer'});
    Jobs.insert({_id: '2', title: 'Rapallo On The Beach'});
  } else {
    console.log('server/getreel.js:', 'job count > 0 (', Jobs.find({}).count(), '): no insert needed');
  }
});

Meteor.methods({
  apply: function(args) {
    if (!Meteor.userId()) {
      throw new Meteor.Error('not-authorized');
    }

    console.log(args);

    Applications.insert({
      createdAt: new Date(),
      applicant: Meteor.userId(),
      firstname: args.firstname,
      lastname: args.lastname,
      job: args.job,
      resume: args.resume,
      videofile: args.videofile,
      videolink: args.videolink
    });
  }
});

Jobs = new Mongo.Collection('jobs'); //both on client and server
Applications = new Mongo.Collection('applications');

// added repoz channel

Meteor.startup(function() {
  // console.log('Jobs.remove({})');
  // Jobs.remove({});
  var jobCount = Jobs.find({}).count();
  if (jobCount === 0) {
    console.log('job count === ', jobCount, 'inserting jobs');
    Jobs.insert({_id: '0', title: 'Select a job position...'});
    Jobs.insert({_id: '1', title: 'Haiti Village Photographer'});
    Jobs.insert({_id: '2', title: 'Rapallo On The Beach'});
  } else {
    console.log('server/getreel.js:', 'job count > 0 (', jobCount, '): no insert needed');
  }
});

Meteor.methods({
  apply: function(args) {
    if (!Meteor.userId()) {
      throw new Meteor.Error('not-authorized');
    }

    console.log(args);

    Applications.insert({
      createdAt: new Date(),
      applicant: Meteor.userId(),
      firstname: args.firstname,
      lastname: args.lastname,
      job: args.job,
      resume: args.resume,
      videofile: args.videofile,
      videolink: args.videolink
    });
  }
});

Improve flexibility, readability and performance


import settings from './helpers/settings'
import {findDistance, limitPositions, chooseOne, randomInt, getAvgPostion} from './helpers/general'
import {applyLimbForces, updateBodyPartPositions} from './helpers/movement'
import {createEveData, deriveEveData} from './helpers/eveCreation'
import {killEve, collectStats, saveStateToDB} from './helpers/lifeCycle'

//Create initial data:
var Eves = [];
for(var i = 0; i < settings.eveCount; i ++) {
  Eves.push(createEveData());
}

//Animate:
setInterval(() => {
  applyLimbForces(Eves);
  updateBodyPartPositions(Eves);
  // console.log('YO!',chooseOne.valueOf())
}, settings.stepTime)

//Selective Pressure:
setInterval(() => {
  killEve(Eves);
  var eve = chooseOne(Eves);
  deriveEveData(eve);
}, settings.killTime)

// //Check progress
// setInterval(() => {
//   console.log('Eve 1, limb1:', Eves[0].limbs[0])
// }, 1000)

// setTimeout(animate, 1000);
// setInterval(collectStats, 10000);
// setInterval(function() {
//   killEves();
//   Eves.push(deriveEveData(chooseOne(Eves)));
//   generateEves();
// }, 10000);

//setInterval(saveStateToDB, 10000)

import settings from './helpers/settings'
import {findDistance, limitPositions, chooseOne, randomInt, getAvgPostion} from './helpers/general'
import {applyLimbForces, updateBodyPartPositions} from './helpers/movement'
import {createEveData, deriveEveData} from './helpers/eveCreation'
import {killEve, collectStats, saveStateToDB} from './helpers/lifeCycle'

//Create initial data:
var Eves = [];
for(var i = 0; i < settings.eveCount; i ++) {
  Eves.push(createEveData());
}

//Animate:
setInterval(() => {
  applyLimbForces(Eves);
  updateBodyPartPositions(Eves);
}, settings.stepTime)

//Selective Pressure:
setInterval(() => {
  killEve(Eves);
  var eve = chooseOne(Eves);
  Eves.push(deriveEveData(eve));
}, settings.killTime)

// //Check progress
// setInterval(() => {
//   console.log('Eve 1, limb1:', Eves[0].limbs[0])
// }, 1000)

// setTimeout(animate, 1000);
// setInterval(collectStats, 10000);
// setInterval(function() {
//   killEves();
//   Eves.push(deriveEveData(chooseOne(Eves)));
//   generateEves();
// }, 10000);

//setInterval(saveStateToDB, 10000)

Add derived eves to Eves array


W.TableSections = function () {
  var win = UI.Win({title:'Table Sections'});

  // Create the first TableViewSections.
  var section1 = Ti.UI.createTableViewSection({headerTitle:'Header 1'});
  // Add some rows to this table.
  for (var i = 0; i < 4; i++) {
    section1.add(Ti.UI.createTableViewRow({
      title:'Row ' + i
    }));
  }

  // Create the second TableViewSections.
  var section2 = Ti.UI.createTableViewSection({headerTitle:'Header 2'});
  // Add some rows to this table.
  for (var i = 4; i < 20; i++) {
    section2.add(Ti.UI.createTableViewRow({
      title:'Row ' + i
    }));
  }

  // Create a normal table view and add the sections as data.
  var table = Ti.UI.createTableView({
    data:[section1,section2]
  });

  win.add(table);

  return win;
}

W.TableSections = function () {
  var win = UI.Win({title:'Table Sections'});

  // Create the first TableViewSections.
  var section1 = Ti.UI.createTableViewSection({headerTitle:'Header 1'});
  // Add some rows to this table.
  for (var i = 0; i < 4; i++) {
    section1.add(Ti.UI.createTableViewRow({
      title:'Row ' + i
    }));
  }

  // Create the second TableViewSections.
  var section2 = Ti.UI.createTableViewSection({headerTitle:'Header 2'});
  // Add some rows to this table.
  for (var i = 4; i < 20; i++) {
    var backgroundColor = (i % 2 == 0) ? '#FFFFFF' : '#EEEEEE';
    section2.add(Ti.UI.createTableViewRow({
      title:'Row ' + i,
      backgroundColor:backgroundColor
    }));
  }

  // Create a normal table view and add the sections as data.
  var table = Ti.UI.createTableView({
    data:[section1,section2]
  });

  win.add(table);

  return win;
}

Add zebra background color for table section.


/**
 * @file
 * Text reporter
 */
var Colors = require('colors/safe');
var _ = require('lodash');

/**
 * Text reporter
 * @param {Object} validationData
 * @param {Object} [options]
 * @param {Boolean} options.noColors
 * @returns {String}
 */
module.exports = function textReporter(validationData, options) {
    options = options || {};

    function mapItem(item) {
        return [
            'At line: ' + item.line + ', column: ' + item.column,
            item.type,
            item.text
        ].join('\t');
    }

    function prepareString(str, color) {
        return options.noColors ? str : Colors[color](str);
    }

    return _([
        prepareString('Validation results', 'magenta'),
        prepareString('Feed:', 'green'),
        validationData.feedXml,
        '',
        validationData.errors.length ? [
            prepareString('Errors:', 'red'),
            _.map(validationData.errors, mapItem),
            ''
        ] : null,
        validationData.warnings.length ? [
            prepareString('Warnings:', 'blue'),
            _.map(validationData.warnings, mapItem),
            ''
        ] : null,
        validationData.info.length ? [
            prepareString('Info:', 'yellow'),
            _.map(validationData.info, mapItem),
            ''
        ] : null,
        validationData.isValid ? prepareString('All correct', 'green') : null
    ])
        .flatten()
        .filter(function (item) { return item !== null; })
        .run()
        .join('\n');
};

/**
 * @file
 * Text reporter
 */
var Colors = require('colors/safe');
var _ = require('lodash');

/**
 * Text reporter
 * @param {Object} validationData
 * @param {Object} [options]
 * @param {Boolean} options.noColors
 * @returns {String}
 */
module.exports = function textReporter(validationData, options) {
    options = options || {};

    function mapItem(item) {
        return [
            item.line ?
                'At line: ' + item.line + ', column: ' + item.column :
                'At path: ' + item.path,
            item.type,
            item.text
        ].join('\t');
    }

    function prepareString(str, color) {
        return options.noColors ? str : Colors[color](str);
    }

    return _([
        prepareString('Validation results', 'magenta'),
        prepareString('Feed:', 'green'),
        validationData.feedXml,
        '',
        validationData.errors.length ? [
            prepareString('Errors:', 'red'),
            _.map(validationData.errors, mapItem).join('\n'),
            ''
        ] : null,
        validationData.warnings.length ? [
            prepareString('Warnings:', 'blue'),
            _.map(validationData.warnings, mapItem).join('\n'),
            ''
        ] : null,
        validationData.info.length ? [
            prepareString('Info:', 'yellow'),
            _.map(validationData.info, mapItem).join('\n'),
            ''
        ] : null,
        validationData.isValid ? prepareString('All correct', 'green') : null
    ])
        .flatten()
        .filter(function (item) { return item !== null; })
        .run()
        .join('\n');
};

Fix arrays and add path support


// inject the main script from the latest github source
var s = document.createElement('script');
s.src = 'https://raw.github.com/apottere/DripBot/master/dripBot.js';
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
    s.parentNode.removeChild(s);
};

// add a variable so the script knows it is running from the extension (and can reload the window and still work)
var actualCode = '(' + function() {
   window.dripBotPro = true;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

// inject the main script from the latest github source
var s = document.createElement('script');
s.src = 'https://raw.githack.com/apottere/DripBot/master/dripBot.js';
(document.head||document.documentElement).appendChild(s);
s.onload = function() {
    s.parentNode.removeChild(s);
};

// add a variable so the script knows it is running from the extension (and can reload the window and still work)
var actualCode = '(' + function() {
   window.dripBotPro = true;
} + ')();';
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

Update extension with mime type workaround.


var path = require('path');
var webpack = require('webpack');

module.exports = {
  devtool: 'eval',
  entry: [
    'webpack-dev-server/client?http://localhost:3000',
    'webpack/hot/only-dev-server',
    './index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  module: {
    loaders: [{
      test: /\.js?$/,
      loaders: ['react-hot', 'babel'],
      exclude: /node_modules/
    }, {
      test: /\.css?$/,
      loaders: ['style', 'raw']
    }]
  }
};

var path = require('path');
var webpack = require('webpack');

module.exports = {
  devtool: 'eval',
  entry: [
    'webpack-dev-server/client?http://localhost:3000',
    'webpack/hot/only-dev-server',
    './index'
  ],
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: '/static/'
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      loaders: ['react-hot', 'babel'],
      exclude: /node_modules/
    }, {
      test: /\.css?$/,
      loaders: ['style', 'raw']
    }]
  }
};

Fix regex to include .jsx


GLClient.controller('toolTipCtrl',
  ['$scope', '$rootScope', 'Authentication',
   '$location', '$cookies', 'Translations', 'Node', '$route',
function($scope, $rootScope, Authentication, $location,
         $cookies, Translations, Node, $route) {
  if (!$cookies['language'])
    $cookies['language'] = 'en';

  $scope.session_id = $cookies['session_id'];
  $scope.auth_landing_page = $cookies['auth_landing_page'];
  $scope.role = $cookies['role'];
  $scope.language = $cookies['language'];
  $rootScope.selected_language = $scope.language;

  Node.get(function(node_info) {
    $rootScope.available_languages = {};
    $rootScope.languages_supported = Translations.supported_languages;
    $.each(node_info.languages_enabled, function(idx, lang) {
      $rootScope.available_languages[lang] = Translations.supported_languages[lang];
    });
  });

  $scope.logout = Authentication.logout;

  $scope.$watch("language", function(){
    $cookies['language'] = $scope.language;
    $route.reload();
  });

  $scope.$watch(function(scope){
    return $cookies['session_id'];
  }, function(newVal, oldVal){
    $scope.session_id = $cookies['session_id'];
    $scope.auth_landing_page = $cookies['auth_landing_page'];
    $scope.role = $cookies['role'];
  });

}]);

GLClient.controller('toolTipCtrl',
  ['$scope', '$rootScope', 'Authentication',
   '$location', '$cookies', 'Translations', 'Node', '$route',
function($scope, $rootScope, Authentication, $location,
         $cookies, Translations, Node, $route) {
  if (!$cookies['language'])
    $cookies['language'] = 'en';

  $scope.session_id = $cookies['session_id'];
  $scope.auth_landing_page = $cookies['auth_landing_page'];
  $scope.role = $cookies['role'];
  $scope.language = $cookies['language'];
  $rootScope.selected_language = $scope.language;

  Node.get(function(node_info) {
    $rootScope.available_languages = {};
    $rootScope.languages_supported = Translations.supported_languages;
    $.each(node_info.languages_enabled, function(idx, lang) {
      $rootScope.available_languages[lang] = Translations.supported_languages[lang];
    });
  });

  $scope.logout = Authentication.logout;

  $scope.$watch("language", function(){
    $.cookie('language', $scope.language);
    $rootScope.selected_language = $scope.language;
    $route.reload();
  });

  $scope.$watch(function(scope){
    return $cookies['session_id'];
  }, function(newVal, oldVal){
    $scope.session_id = $cookies['session_id'];
    $scope.auth_landing_page = $cookies['auth_landing_page'];
    $scope.role = $cookies['role'];
  });

}]);

Fix bug in language selection switching


/* jshint expr:true */
import { expect } from 'chai';
import {
  describe,
  it,
  beforeEach
} from 'mocha';
import Ember from 'ember';
import { initialize } from '<%= dasherizedPackageName %>/initializers/<%= dasherizedModuleName %>';

describe('<%= classifiedModuleName %>Initializer', function() {
  var container, application;

  beforeEach(function() {
    Ember.run(function() {
      container = new Ember.Container();
      application = Ember.Application.create();
      application.deferReadiness();
    });
  });

  // Replace this with your real tests.
  it('works', function() {
    initialize(container, application);

    // you would normally confirm the results of the initializer here
    expect(true).to.be.ok;
  });
});

/* jshint expr:true */
import { expect } from 'chai';
import {
  describe,
  it,
  beforeEach
} from 'mocha';
import Ember from 'ember';
import { initialize } from '<%= dasherizedPackageName %>/initializers/<%= dasherizedModuleName %>';

describe('<%= classifiedModuleName %>Initializer', function() {
  var container, application;

  beforeEach(function() {
    Ember.run(function() {
      application = Ember.Application.create();
      container = application.__container__;
      application.deferReadiness();
    });
  });

  // Replace this with your real tests.
  it('works', function() {
    initialize(container, application);

    // you would normally confirm the results of the initializer here
    expect(true).to.be.ok;
  });
});

Use Ember.Application's container in initializers blueprint


'use strict';

angular.module('impactApp')
  .config(function($stateProvider) {
    var index = 'espace_perso.mes_profils.profil.vie_scolaire';
    $stateProvider
      .state(index, {
        url: '/vie_scolaire',
        templateUrl: 'app/espace_perso/mes_profils/profil/section.html',
        controller: 'SectionCtrl',
        redirectTo: index + '.situation',
        resolve: {
          sections: function($http) {
            return $http.get('/api/sections').then(function(result) {
              return result.data;
            });
          },

          sectionId: function() {
            return 'vie_scolaire';
          },

          section: function(sections, sectionId) {
            return _.find(sections, {id: sectionId});
          },

          sectionModel: function(profile, sectionId) {
            if (!profile[sectionId]) {
              profile[sectionId] = {};
            }

            return profile[sectionId];
          },

          saveSection: function($state, currentUser, profile, sectionId, sectionModel) {
            return function() {
              profile[sectionId] = sectionModel;
              profile.$save({userId: currentUser._id}, function() {
                $state.go('espace_perso.mes_profils.profil', {}, {reload: true});
              });
            };
          }
        }
      });
  });

'use strict';

angular.module('impactApp')
  .config(function($stateProvider) {
    var index = 'espace_perso.mes_profils.profil.vie_scolaire';
    $stateProvider
      .state(index, {
        url: '/vie_scolaire',
        templateUrl: 'app/espace_perso/mes_profils/profil/section.html',
        controller: 'SectionCtrl',
        redirectTo: index + '.situation',
        resolve: {
          sections: function($http) {
            return $http.get('/api/sections').then(function(result) {
              return result.data;
            });
          },

          sectionId: function() {
            return 'vie_scolaire';
          },

          section: function(sections, sectionId) {
            return _.find(sections, {id: sectionId});
          },

          sectionModel: function(profile, sectionId) {
            if (!profile[sectionId]) {
              profile[sectionId] = {};
            }

            return profile[sectionId];
          },

          saveSection: function($state, currentUser, profile, sectionId, sectionModel) {
            return function() {
              profile[sectionId] = sectionModel;
              profile.saveSection(sectionId, sectionModel, currentUser, function() {
                $state.go('espace_perso.mes_profils.profil', {}, {reload: true});
              });
            };
          }
        }
      });
  });

Add __completion and updatedAt to 'Vie scolaire'


/**
 * bit.ly access library code.
 */
Shortener = {
    displayName: 'Shortener',

    shorten: function() {
        var uri, callback, name;

        if (typeof arguments[0] == 'string') {
            uri      = arguments[0];
            callback = arguments[1];
        } else {
            uri      = window.location.href;
            callback = arguments[0];
        }

        name = this._registerCallback(callback);

        if (name && this.CLIENT) {
            this.CLIENT.call('shorten', {'longUrl': uri}, 'BitlyCB.' + name);
        }
    },

    _dispatcher: function(callback, data) {
        var result, p;

        // Results are keyed by longUrl, so we need to grab the first one.
        for (p in data.results) {
            result = data.results[p];
            break;
        }

        callback.call(null, result, data);
    },

    _registerCallback: function(callback) {
        if (!this.NAMESPACE) return false;

        var name = 'abbr' + this.callbackCount,
            self = this;

        this.callbackCount += 1;

        this.NAMESPACE[name] = function(data) {
            self._dispatcher(callback, data);
        };

        return name;
    },

    callbackCount: 0,

    CLIENT:        BitlyClient,
    NAMESPACE:     BitlyCB
};

/**
 * bit.ly access library code.
 */
Shortener = {
    displayName: 'Shortener',

    shorten: function() {
        var uri, callback, name;

        if (typeof arguments[0] == 'string') {
            uri      = arguments[0];
            callback = arguments[1];
        } else {
            uri      = window.location.href;
            callback = arguments[0];
        }

        name = this._registerCallback(callback);

        if (name && this.CLIENT) {
            this.CLIENT.call('shorten', {'longUrl': uri}, 'BitlyCB.' + name);
        }
    },

    _dispatcher: function(callback, data) {
        var result, p;

        // Results are keyed by longUrl, so we need to grab the first one.
        for (p in data.results) {
            result = data.results[p];
            if (typeof result == 'object') break;
        }

        callback.call(null, result, data);
    },

    _registerCallback: function(callback) {
        if (!this.NAMESPACE) return false;

        var name = 'abbr' + this.callbackCount,
            self = this;

        this.callbackCount += 1;

        this.NAMESPACE[name] = function(data) {
            self._dispatcher(callback, data);
        };

        return name;
    },

    callbackCount: 0,

    CLIENT:        BitlyClient,
    NAMESPACE:     BitlyCB
};

Check we've got a result object before exiting the results loop.


import { startServer } from "./server";
startServer();

import _ from "lodash";
import express from "express";
import http from "http";
import Config from "config";

const app = express();
const server = http.createServer(app);
const serverPort = _.get(Config, "server.port", 3000);

// Include server routes as a middleware
app.use(function(req, res, next) {
  require("./server")(req, res, next);
});

server.listen(serverPort, "localhost", function(err) {
  if (err) throw err;
  const addr = server.address();
  // eslint-disable-next-line
  console.log("Listening at http://%s:%d", addr.address, addr.port);
});

Update server.js to run after compilation


#!/usr/bin/env node

const fs = require('fs');
const credentialsPath = __dirname + '/../credentials.json');
if(fs.existsSync(credentialsPath) || (process.argv[2] === '--config')) {
	require('../lib/config.js')();
} else {
	const api = require('../lib/freesmsapi.js');
	const credentials = require('../credentials.json');

	if(!credentials.user) throw ReferenceError('Invalid user credential.');
	if(!credentials.password) throw ReferenceError('Invalid password credential.');

	const message = process.argv.slice(2).join(' ');
	if(!message) throw SyntaxError('Invalid message.');

	api.send(message, credentials)
	.catch(statusCode => {
		process.exit(statusCode);
	});
}

#!/usr/bin/env node

const fs = require('fs');
const credentialsPath = __dirname + '/../credentials.json';
if(fs.existsSync(credentialsPath) || (process.argv[2] === '--config')) {
	require('../lib/config.js')();
} else {
	const api = require('../lib/freesmsapi.js');
	const credentials = require('../credentials.json');

	if(!credentials.user) throw ReferenceError('Invalid user credential.');
	if(!credentials.password) throw ReferenceError('Invalid password credential.');

	const message = process.argv.slice(2).join(' ');
	if(!message) throw SyntaxError('Invalid message.');

	api.send(message, credentials)
	.catch(statusCode => {
		process.exit(statusCode);
	});
}

Fix credentials path - 2


import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),

  sessionData: Ember.computed('session.session.content.authenticated', function() {
    return JSON.stringify(this.get('session.session.content.authenticated'), null, '\t');
  }),

  tokenData: Ember.computed('session.session.content.authenticated', function() {
    var authenticator = this.container.lookup('authenticator:jwt'),
        session = this.get('session.session.content.authenticated'),
        tokenData = {};

    if(session && Ember.keys(session).length > 0) {
      tokenData = authenticator.getTokenData(session.token);
    }

    return JSON.stringify(tokenData, null, '\t');
  })
});

import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),

  sessionData: Ember.computed('session.session.content.authenticated', function() {
    return JSON.stringify(this.get('session.session.content.authenticated'), null, '\t');
  }),

  tokenData: Ember.computed('session.session.content.authenticated', function() {
    var authenticator = this.container.lookup('authenticator:jwt'),
        session = this.get('session.session.content.authenticated'),
        tokenData = {};

    if(session && Object.keys(session).length > 0) {
      tokenData = authenticator.getTokenData(session.token);
    }

    return JSON.stringify(tokenData, null, '\t');
  })
});

Use Object.keys instead of Ember.keys


/**
Copyright 2016 Autodesk,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.

*/
import 'hig.web/dist/hig.css';

import '../elements/basics/Button.story';
import '../elements/components/GlobalNav/TopNav/Search.story.js';
import '../elements/components/GlobalNav/TopNav/Profile.story';
import '../elements/components/GlobalNav/GlobalNav.story';
import '../elements/components/GlobalNav/TopNav/TopNav.story';
import '../elements/components/GlobalNav/TopNav/ProjectAccountSwitcher.story';

/**
Copyright 2016 Autodesk,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.

*/
import 'hig.web/dist/hig.css';

import '../elements/basics/Button.story';
import '../elements/components/GlobalNav/TopNav/Search.story.js';
import '../elements/components/GlobalNav/TopNav/Profile.story';
import '../elements/components/GlobalNav/GlobalNav.story';
import '../elements/components/GlobalNav/TopNav/ProjectAccountSwitcher.story';

Fix merge conflict - Remove TopNav story


import * as _ from "../deps/underscore-1.10.2-esm.js"
import { to_write } from "./_writer.js"
import { BiwaError } from "./error.js"
//
// assertions - type checks
//

const make_assert = function(check){
  return function(/*args*/){
    var fname = arguments.callee.caller
                  ? arguments.callee.caller.fname
                  : "";
    check.apply(this, [fname].concat(_.toArray(arguments)));
  }
}

const make_simple_assert = function(type, test, _fname){
  return make_assert(function(fname, obj, opt){
    if(_fname) fname = _fname;
    const option = opt ? ("("+opt+")") : ""
    if(!test(obj)){
      throw new BiwaError(fname + option + ": " +
                          type + " required, but got " +
                          to_write(obj));
    }
  })
}

export { make_assert, make_simple_assert }

import * as _ from "../deps/underscore-1.10.2-esm.js"
import { to_write } from "./_writer.js"
import { BiwaError } from "./error.js"
//
// assertions - type checks
//

const make_assert = function(check){
  return function(/*args*/){
    // We cannot use callee/caller in ESM (=JS strict mode)
    //var fname = arguments.callee.caller
    //              ? arguments.callee.caller.fname
    //              : "";
    const fname = "";
    check.apply(this, [fname].concat(_.toArray(arguments)));
  }
}

const make_simple_assert = function(type, test, _fname){
  return make_assert(function(fname, obj, opt){
    if(_fname) fname = _fname;
    const option = opt ? ("("+opt+"): ") : ""
    if(!test(obj)){
      throw new BiwaError(option +
                          type + " required, but got " +
                          to_write(obj));
    }
  })
}

export { make_assert, make_simple_assert }

Remove fname from error msg


Package.describe({
  name: "practicalmeteor:loglevel",
  summary: "Simple logger with app and per-package log levels and line number preserving output.",
  version: "1.2.0_1",
  git: "https://github.com/practicalmeteor/meteor-loglevel.git"
});

Package.onUse(function (api) {
  api.versionsFrom('0.9.3');

  api.use(['meteor', 'coffeescript']);

  api.use(['practicalmeteor:chai']);

  api.addFiles('loglevel-1.2.0.js');
  api.addFiles('LoggerFactory.coffee');
  api.addFiles('ObjectLogger.coffee');

  api.export(['loglevel', 'ObjectLogger']);
});

Package.onTest(function(api) {
  api.use(['coffeescript', 'practicalmeteor:loglevel', 'practicalmeteor:munit@2.1.2']);

  api.addFiles('tests/LoggerFactoryTest.coffee');
  api.addFiles('tests/ObjectLoggerTest.coffee');
});

Package.describe({
  name: "practicalmeteor:loglevel",
  summary: "Simple logger with app and per-package log levels and line number preserving output.",
  version: "1.2.0_1",
  git: "https://github.com/practicalmeteor/meteor-loglevel.git"
});

Package.onUse(function (api) {
  api.versionsFrom('0.9.3');

  api.use(['meteor', 'coffeescript']);

  api.use(['practicalmeteor:chai@2.1.0_1']);

  api.addFiles('loglevel-1.2.0.js');
  api.addFiles('LoggerFactory.coffee');
  api.addFiles('ObjectLogger.coffee');

  api.export(['loglevel', 'ObjectLogger']);
});

Package.onTest(function(api) {
  api.use(['coffeescript', 'practicalmeteor:loglevel@1.2.0_1', 'practicalmeteor:munit@2.1.2']);

  api.addFiles('tests/LoggerFactoryTest.coffee');
  api.addFiles('tests/ObjectLoggerTest.coffee');
});

Set chai dependency to latest version - v2.1.0_1


module.exports = {
    networks: {
        development: {
            host: "localhost",
            port: 8545,
            network_id: "*" // Match any network id
        }
    }
    ,
    mocha: {
       reporter: 'mocha-junit-reporter'
    }
};

module.exports = {
    networks: {
        development: {
            host: "localhost",
            port: 8545,
            network_id: "*" // Match any network id
        }
    }
    ,
    mocha: {
       //reporter: 'mocha-junit-reporter'
       reporter: 'spec'
    }
};

Change mocha reporter to default cli


/* global require, describe, before, after, it */

var io = require('socket.io-client');
var should = require('should');

describe('server-cdp', function () {
  var server = require('../lib/server.js');

  before(function (done) {
    server.start(3000, '', {}, done);
  });

  it('should send init message on connection', function (done) {
    var socket = io('http://localhost:3000', { 'force new connection': true });
    socket.on('connect', function () {
      socket.on('init', function () { done(); });
    });
  });

  it('should send diffs to other clients', function (done) {
    var s1 = io('http://localhost:3000', { 'force new connection': true });
    var s2 = io('http://localhost:3000', { 'force new connection': true });

    s1.on('connect', function () {
      s1.on('init', function () {
        s1.emit('msg', { hello: 'world' });
      });
    });

    s2.on('connect', function () {
      s2.on('msg', function (data) {
        data.should.have.property('hello', 'world');
        done();
      });
    });
  });

  after(server.kill);
});

/* global require, describe, before, after, it */

var io = require('socket.io-client');
var should = require('should');

describe('server-cdp', function () {
  var server = require('../lib/server.js');

  before(function (done) {
    server.start(3000, '', {}, done);
  });

  it('should send init message on connection', function (done) {
    var socket = io('http://localhost:3000', { 'forceNew': true });
    socket.on('connect', function () {
      socket.on('init', function () { done(); });
    });
  });

  it('should send diffs to other clients', function (done) {
    var s1 = io('http://localhost:3000', { 'forceNew': true });
    var s2 = io('http://localhost:3000', { 'forceNew': true });

    s1.on('connect', function () {
      s1.on('init', function () {
        s1.emit('msg', { hello: 'world' });
      });
    });

    s2.on('connect', function () {
      s2.on('msg', function (data) {
        data.should.have.property('hello', 'world');
        done();
      });
    });
  });

  after(server.kill);
});

Use 'forceNew' instead of 'force new connection'


const path = require('path');
module.exports = {
  webpack: (config, env) => {
    if (env === 'development') {
      config.resolve.alias = {
        'react': path.resolve('node_modules/react'),
        'react-dom': path.resolve('node_modules/react-dom'),
        'react-redux': path.resolve('node_modules/react-redux'),
        'redux': path.resolve('node_modules/redux'),
        'redux-saga': path.resolve('node_modules/redux-saga'),
        'redux-form': path.resolve('node_modules/redux-form'),
        '@material-ui': path.resolve('node_modules/@material-ui'),
        '@openchemistry': path.resolve('node_modules/@openchemistry')
      };
    }
    return config;
  },
};

const path = require('path');
module.exports = {
  webpack: (config, env) => {
    config.resolve.alias = {
      'react': path.resolve('node_modules/react'),
      'react-dom': path.resolve('node_modules/react-dom'),
      'react-redux': path.resolve('node_modules/react-redux'),
      'redux': path.resolve('node_modules/redux'),
      'redux-saga': path.resolve('node_modules/redux-saga'),
      'redux-form': path.resolve('node_modules/redux-form'),
      '@material-ui': path.resolve('node_modules/@material-ui'),
      '@openchemistry': path.resolve('node_modules/@openchemistry')
    };
    return config;
  },
};

Enable resolve.alias for production build too


var path = require('path')

function createPattern (pattern) {
  return {
    pattern: pattern,
    included: true,
    served: true,
    watched: false
  }
}

function initQUnit (files, qunit) {
  files.unshift(createPattern(path.join(__dirname, 'adapter.js')))
  files.unshift(createPattern(require.resolve('qunit')))
  if (qunit && qunit.showUI) {
    files.unshift(createPattern(require.resolve('qunitjs/qunit/qunit.css')))
  }
}

initQUnit.$inject = ['config.files', 'config.client.qunit']

module.exports = {
  'framework:qunit': ['factory', initQUnit]
}

var path = require('path')

function createPattern (pattern) {
  return {
    pattern: pattern,
    included: true,
    served: true,
    watched: false
  }
}

function initQUnit (files, qunit) {
  files.unshift(createPattern(path.join(__dirname, 'adapter.js')))
  files.unshift(createPattern(require.resolve('qunit')))
  if (qunit && qunit.showUI) {
    files.unshift(createPattern(require.resolve('qunit/qunit/qunit.css')))
  }
}

initQUnit.$inject = ['config.files', 'config.client.qunit']

module.exports = {
  'framework:qunit': ['factory', initQUnit]
}

Update the path to QUnit css


Package.describe({
  summary: "Use Bower packages in your Meteor app",
  name: "mquandalle:bower",
  git: "https://github.com/mquandalle/meteor-bower.git",
  version: "0.1.11"
});

Package._transitional_registerBuildPlugin({
  name: "bower",
  use: [
    "meteor",
    "underscore",
  ],
  sources: [
    "plugin/bower.js",
    "plugin/handler.js",
  ],
  npmDependencies: {
    "bower": "1.3.8",
    "glob": "3.2.9"
  }
});

// XXX Tests?

Package.describe({
  summary: "Use Bower packages in your Meteor app",
  name: "mquandalle:bower",
  git: "https://github.com/mquandalle/meteor-bower.git",
  version: "0.1.11"
});

Package._transitional_registerBuildPlugin({
  name: "bower",
  use: [
    "meteor",
    "underscore",
  ],
  sources: [
    "plugin/bower.js",
    "plugin/handler.js",
  ],
  npmDependencies: {
    "bower": "1.3.9",
    "glob": "3.2.9"
  }
});

// XXX Tests?

Bump bower version to 1.3.9


const { expect } = require('chai');
const { generateTitle } = require('../lib/utils');

describe('utils', function() {
  describe('.generateTitle()', function() {
    it('should generate a valid title', function () {
      const result = generateTitle('Base', 'First', 'Second');
      expect(result).to.equal('Base | First | Second');
    });

    it('should generate a valid title when some arguments missing', function () {
      const result = generateTitle('Base');
      expect(result).to.equal('Base');
    });

    it('should return an empty string when all arguments missing', function () {
      const result = generateTitle();
      expect(result).to.eq('');
    });

    it('should combine titles correctly', function () {
      const result = generateTitle('Title', 'Generated | Title');
      expect(result).to.eq('Title | Generated | Title');
    });
  });
});

const { expect } = require('chai');
const { generateTitle } = require('../lib/utils');

describe('utils', function() {
  describe('.generateTitle()', function() {
    it('generates valid title', function () {
      const result = generateTitle('Base', 'First', 'Second');
      expect(result).to.equal('Base | First | Second');
    });

    it('generates valid title when single part used', function () {
      const result = generateTitle('Base');
      expect(result).to.equal('Base');
    });

    it('returns empty string without args', function () {
      const result = generateTitle();
      expect(result).to.eq('');
    });

    it('combines titles correctly', function () {
      const result = generateTitle('Title', 'Generated | Title');
      expect(result).to.eq('Title | Generated | Title');
    });
  });
});

Change wording in utils test


(function($) {
  $.fn.extend({
    requireConfirmation: function() {
      return this.each(function() {
        return $(this).on('click', function(event) {
          event.preventDefault();

          var actionButton = $(this);

          if (actionButton.is('a')) {
            $('#confirmation-button').attr('href', actionButton.attr('href'));
          }
          if (actionButton.is('button')) {
            $('#confirmation-button').on('click', function(event) {
              event.preventDefault();

              return actionButton.closest('form').submit();
            });
          }

          return $('#confirmation-modal').modal('show');
        });
      });
    }
  });

  $(document).ready(function() {
    $('#sidebar')
        .first()
        .sidebar('attach events', '#sidebar-toggle', 'show')
    ;

    $('.ui.checkbox').checkbox();
    $('.ui.accordion').accordion();
    $('.link.ui.dropdown').dropdown({action: 'hide'});
    $('.button.ui.dropdown').dropdown({action: 'hide'});
    $('.menu .item').tab();

    $('.form button').on('click', function() {
      return $(this).closest('form').addClass('loading');
    });
    $('.message .close').on('click', function() {
      return $(this).closest('.message').transition('fade');
    });
    $('.loadable.button').on('click', function() {
      return $(this).addClass('loading');
    });

    $('[data-requires-confirmation]').requireConfirmation();

    $('.special.cards .image').dimmer({
      on: 'hover'
    });
  });
})(jQuery);

(function($) {
  $.fn.extend({
    requireConfirmation: function() {
      return this.each(function() {
        return $(this).on('click', function(event) {
          event.preventDefault();

          var actionButton = $(this);

          if (actionButton.is('a')) {
            $('#confirmation-button').attr('href', actionButton.attr('href'));
          }
          if (actionButton.is('button')) {
            $('#confirmation-button').on('click', function(event) {
              event.preventDefault();

              return actionButton.closest('form').submit();
            });
          }

          return $('#confirmation-modal').modal('show');
        });
      });
    }
  });

  $(document).ready(function() {
    $('#sidebar')
        .first()
        .sidebar('attach events', '#sidebar-toggle', 'show')
    ;

    $('.ui.checkbox').checkbox();
    $('.ui.accordion').accordion();
    $('.link.ui.dropdown').dropdown({action: 'hide'});
    $('.button.ui.dropdown').dropdown({action: 'hide'});
    $('.menu .item').tab();

    $('.form button').on('click', function() {
      return $(this).closest('form').addClass('loading');
    });
    $('.message .close').on('click', function() {
      return $(this).closest('.message').transition('fade');
    });
    $('.loadable.button').on('click', function() {
      return $(this).addClass('loading');
    });
    $('.popups').popup();

    $('[data-requires-confirmation]').requireConfirmation();

    $('.special.cards .image').dimmer({
      on: 'hover'
    });
  });
})(jQuery);

Improve the shipment ship form


var React = require('react');
var Songs = require('./components/songs.js');

React.render(
  <Songs />,
  document.getElementById('app')
);

var React = require('react');
var Songs = require('./components/songsList.js');

React.render(
  <Songs />,
  document.getElementById('app')
);

Fix wrong reference to songsList.js


const express = require('express')
const users = require('../Controllers/userCtrl')
const jwt = require('../Lib/jwt.js')

const router = express.Router()

const isAuthenticated = function(req, res, next) {
  const token = req.get("Authorization")

  const decoded = jwt.decode(token)

  if (typeof decoded === 'object') {
    console.log("token successfuly decoded: ", decoded)
    res.status(200)
    next()
  } else {
    console.log('ERROR, INCORRECT ACCESS TOKEN')
    res.status(400).end()
  }

}

router.use(isAuthenticated)

router.route('/')
  .post(users.createUser) //add user

router.route('/:userId')
  .get(users.getUser) //get user
  .put(users.updateUser) //update user information

router.route('/:userId/saved')
  .post(users.createPin) //add new pin
  .delete(users.deletePin) //delete pin

router.route('/:userId/created')
  .post(users.createSpot) //add new spot
  .delete(users.deleteSpot) //delete spot

module.exports = router

const express = require('express')
const users = require('../Controllers/userCtrl')
const jwt = require('../Lib/jwt.js')

const router = express.Router()

const isAuthenticated = function(req, res, next) {
  const token = req.get("Authorization")

  const decoded = jwt.decode(token)

  if (typeof decoded === 'object') {
    console.log("token successfuly decoded: ", decoded)
    res.status(200)
    next()
  } else {
    console.log('ERROR, INCORRECT ACCESS TOKEN')
    res.status(400).end()
  }

}

router.use(isAuthenticated)

router.route('/')
  .post(users.createUser) //add user

router.route('/:userId')
  .get(users.getUser) //get user
  .put(users.updateUser) //update user information

router.route('/:userId/saved')
  .get(users.getSavedPins)
  .post(users.createPin) //add new pin
  .delete(users.deletePin) //delete pin

router.route('/:userId/created')
  .get(users.getCreatedPins)
  .post(users.createSpot) //add new spot
  .delete(users.deleteSpot) //delete spot

module.exports = router

Add routes to get created and saved pins


import Knex from 'knex';
import Bookshelf from 'bookshelf';

export default function initBookshelf(config) {
  let knex = Knex(config);
  let bookshelf = Bookshelf(knex);

  bookshelf.plugin('registry');
  bookshelf.plugin('visibility');

  let User, Post, Following;

  User = bookshelf.Model.extend({
    tableName: 'users',
    posts: function() {
      return this.hasMany(Post, 'user_id');
    },
    following: function() {
      return this.hasMany(Following, 'user_id');
    },
    followers: function() {
      return this.hasMany(Following, 'following_user_id');
    },
    hidden: ['hashed_password', 'email']  // exclude from json-exports
  });

  Following = bookshelf.Model.extend({
    tableName: 'followers',
    user: function() {
      return this.belongsTo(User, 'user_id');
    },
    following: function() {
      return this.hasOne(User, 'following_user_id');
    },
    hidden: ['hashed_password', 'email']  // exclude from json-exports
  });

  Post = bookshelf.Model.extend({
    tableName: 'posts',
    user: function() {
      return this.belongsTo(User, 'user_id');
    }
  });

  let Posts

  Posts = bookshelf.Collection.extend({
    model: Post
  });

  // adding to registry
  bookshelf.model('User', User);
  bookshelf.model('Post', Post);
  bookshelf.model('Following', Following);
  bookshelf.collection('Posts', Posts);

  return bookshelf;
}

import Knex from 'knex';
import Bookshelf from 'bookshelf';

export default function initBookshelf(config) {
  let knex = Knex(config);
  let bookshelf = Bookshelf(knex);

  bookshelf.plugin('registry');
  bookshelf.plugin('visibility');

  let User, Post;

  User = bookshelf.Model.extend({
    tableName: 'users',
    posts: function() {
      return this.hasMany(Post, 'user_id');
    },
    following: function() {
      return this.belongsToMany(User, 'user_id', 'followers', 'user_id');
    },
    followers: function() {
      return this.belongsToMany(User, 'user_id', 'followers', 'following_user_id');
    },
    hidden: ['hashed_password', 'email']  // exclude from json-exports
  });

  Post = bookshelf.Model.extend({
    tableName: 'posts',
    user: function() {
      return this.belongsTo(User, 'user_id');
    }
  });

  let Posts

  Posts = bookshelf.Collection.extend({
    model: Post
  });

  // adding to registry
  bookshelf.model('User', User);
  bookshelf.model('Post', Post);
  bookshelf.collection('Posts', Posts);

  return bookshelf;
}

Implement following via many-to-many relation


// require all modules ending in ".tests.ts" from source and all subdirectories

var testsContext = require.context('./source', true, /filters.*\.tests\.ts$/);
testsContext.keys().forEach(testsContext);

// require all modules ending in ".tests.ts" from source and all subdirectories

var testsContext = require.context('./source', true, /\.tests\.ts$/);
testsContext.keys().forEach(testsContext);

Remove filters restriction so that all tests are run.


import React from 'react';
import Game from './game';
import DevTools from './devTools';
import { connect } from 'redux';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import store from '../stores/index';

export default class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>

          <DevTools />

hello

          <Game />

      </Provider>
    );
  }
}

import React from 'react';
import Game from './game';
import DevTools from './devTools';
import { connect } from 'redux';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import store from '../stores/index';

import getMuiTheme from 'material-ui/lib/styles/getMuiTheme';
import MuiThemeProvider from 'material-ui/lib/MuiThemeProvider';

export default class Root extends React.Component {
  render() {
    return (
      <Provider store={store}>
        <MuiThemeProvider muiTheme={getMuiTheme()}>

            <DevTools />

hello

            <Game />

        </MuiThemeProvider>
      </Provider>
    );
  }
}

Install MuiThemeProvider in Root component.


import { useMoralis } from 'react-moralis';
import { navigate } from 'gatsby-link';

export function GuestbookAuth() {
  const { authenticate, logout, Moralis } = useMoralis();

  return {
    login: async () => {
      Moralis.Web3.getSigningData = () =>
        'Sign the web3 guestbook on iammatthias.com';
      try {
        await authenticate({
          provider: 'walletconnect',
          onSuccess: () => {
            navigate('/guestbook');
            logout();
          },
        });
      } catch (e) {
        console.error(e.message, e);
      }
    },
  };
}

import { useMoralis } from 'react-moralis';
import { navigate } from 'gatsby-link';

export function GuestbookAuth() {
  const { authenticate, logout, Moralis } = useMoralis();

  return {
    login: async () => {
      Moralis.Web3.getSigningData = () =>
        'Sign the web3 guestbook on iammatthias.com';
      try {
        await authenticate({
          provider: 'walletconnect',
          onSuccess: () => {
            navigate('/guestbook');
            logout();
            alert('yay');
          },
        });
      } catch (e) {
        console.error(e.message, e);
      }
    },
  };
}

Add alert post guestbook sign (remove this later)


let db;
try {
    db = require("rethinkdbdash")(require("./config.json").connectionOpts);
} catch (err) {
    console.error("You haven't installed rethinkdbdash npm module or you don't have configured the bot yet! Please do so.");
}
(async function () {
    if (!db) return;
    const dbs = await db.tableList();
    if (!dbs.includes("blacklist")) await db.tableCreate("blacklist");
    if (!dbs.includes("session")) await db.tableCreate("session");
    if (!dbs.includes("configs")) await db.tableCreate("configs");
    if (!dbs.includes("feedback")) await db.tableCreate("feedback");
    if (!dbs.includes("tags")) await db.tableCreate("tags");
    if (!dbs.includes("profile")) await db.tableCreate("profile");
    if (!dbs.includes("modlog")) await db.tableCreate("modlog");
    if (!dbs.includes("extensions")) await db.tableCreate("extensions");
    return console.log("All set up!");
})();

let db;
try {
    db = require("rethinkdbdash")(require("./config.json").connectionOpts);
} catch (err) {
    console.error("You haven't installed rethinkdbdash npm module or you don't have configured the bot yet! Please do so.");
}
(async function () {
    if (!db) return;
    const dbs = await db.tableList();
    if (!dbs.includes("blacklist")) await db.tableCreate("blacklist");
    if (!dbs.includes("session")) await db.tableCreate("session");
    if (!dbs.includes("configs")) await db.tableCreate("configs");
    if (!dbs.includes("feedback")) await db.tableCreate("feedback");
    if (!dbs.includes("tags")) await db.tableCreate("tags");
    if (!dbs.includes("profile")) await db.tableCreate("profile");
    if (!dbs.includes("modlog")) await db.tableCreate("modlog");
    return console.log("All set up!");
})();

Revert the extension table reservation


// Matching the public exports in husl-colors/husl
module['exports'] = {};
module['exports']["fromRGB"] = husl.Husl.rgbToHusl;
module['exports']["fromHex"] = husl.Husl.hexToHusl;
module['exports']["toRGB"] = husl.Husl.huslToRgb;
module['exports']["toHex"] = husl.Husl.huslToHex;
module['exports']['p'] = {};
module['exports']['p']["fromRGB"] = husl.Husl.rgbToHuslp;
module['exports']['p']["fromHex"] = husl.Husl.hexToHuslp;
module['exports']['p']["toRGB"] = husl.Husl.huslpToRgb;
module['exports']['p']["toHex"] = husl.Husl.huslpToHex;

// Matching the public exports in husl-colors/husl
function expandParams(f) {
	return function(c1, c2, c3) {
		return f([c1, c2, c3])
	}
}
module['exports'] = {};
module['exports']["fromRGB"] = expandParams(husl.Husl.rgbToHusl);
module['exports']["fromHex"] = husl.Husl.hexToHusl;
module['exports']["toRGB"] = expandParams(husl.Husl.huslToRgb);
module['exports']["toHex"] = expandParams(husl.Husl.huslToHex);
module['exports']['p'] = {};
module['exports']['p']["fromRGB"] = expandParams(husl.Husl.rgbToHuslp);
module['exports']['p']["fromHex"] = husl.Husl.hexToHuslp;
module['exports']['p']["toRGB"] = expandParams(husl.Husl.huslpToRgb);
module['exports']['p']["toHex"] = expandParams(husl.Husl.huslpToHex);

Add adaptor for multiple argument functions


import Task from './task';
import DownloadRecords from './download-records';
import DownloadPhotos from './download-photos';
import DownloadVideos from './download-videos';
import DownloadAudio from './download-audio';
import DownloadSignatures from './download-signatures';
// import DownloadPhotos from './download-photos';

export default class DownloadAllRecords extends Task {
  async run({account, dataSource}) {
    const forms = await account.findActiveForms();

    for (const form of forms) {
      await new Promise((resolve, reject) => {
        form.load(dataSource, resolve);
      });

      this.synchronizer.addTask(new DownloadRecords({form: form, ...this.synchronizer.taskParams}));
    }

    // download media here to make sure the tasks are ordered after the records
    this.synchronizer.addTask(new DownloadPhotos(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadVideos(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadAudio(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadSignatures(this.synchronizer.taskParams));
  }
}

import Task from './task';
import DownloadRecords from './download-records';
import DownloadPhotos from './download-photos';
import DownloadVideos from './download-videos';
import DownloadAudio from './download-audio';
import DownloadSignatures from './download-signatures';
import app from '../../app';

export default class DownloadAllRecords extends Task {
  async run({dataSource}) {
    const forms = await this.account.findActiveForms();

    const includedForms = this.includedForms;

    for (const form of forms) {
      if (includedForms != null && includedForms.indexOf(form.id) === -1) {
        continue;
      }

      await new Promise((resolve, reject) => {
        form.load(dataSource, resolve);
      });

      this.synchronizer.addTask(new DownloadRecords({form: form, ...this.synchronizer.taskParams}));
    }

    // download media here to make sure the tasks are ordered after the records
    this.synchronizer.addTask(new DownloadPhotos(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadVideos(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadAudio(this.synchronizer.taskParams));
    this.synchronizer.addTask(new DownloadSignatures(this.synchronizer.taskParams));
  }

  get includedForms() {
    if (app.args.form) {
      return Array.isArray(app.args.form) ? app.args.form : [ app.args.form ];
    }

    return null;
  }
}

Add --form <id> --form <id> --form <id> support to sync command to limit the forms that are sync'd.


var errors  = require('../errors'),
    storage = {};

function getStorage(storageChoice) {
    // TODO: this is where the check for storage apps should go
    // Local file system is the default.  Fow now that is all we support.
    storageChoice = 's3';

    if (storage[storageChoice]) {
        return storage[storageChoice];
    }

    try {
        // TODO: determine if storage has all the necessary methods.
        storage[storageChoice] = require('./' + storageChoice);
    } catch (e) {
        errors.logError(e);
    }

    // Instantiate and cache the storage module instance.
    storage[storageChoice] = new storage[storageChoice]();

    return storage[storageChoice];
}

module.exports.getStorage = getStorage;

var errors  = require('../errors'),
    storage;

function getStorage(storageChoice) {
    // TODO: this is where the check for storage apps should go
    // Local file system is the default.  Fow now that is all we support.
    storageChoice = 's3';

    if (storage) {
        return storage;
    }

    try {
        // TODO: determine if storage has all the necessary methods.
       storage = require('./' + storageChoice);
    } catch (e) {
        errors.logError(e);
    }
    return storage;
}

module.exports.getStorage = getStorage;

Support just one storage as in kimar's patch


import areObjectValuesDefined from '../utils/areObjectValuesDefined';
import pickVariablesFromJson from '../utils/pickVariablesFromJson';

/**
 * "parseJson" Express middelware
 * @see https://github.com/danistefanovic/hooka/blob/master/docs/webhooks.md#parsejson
 * @param {Array} parseJson Config for "parseJson"
 * @return {void}
 */
export default function parseJsonValidator(parseJson) {
    return (req, res, next) => {
        const env = pickVariablesFromJson(req.body, parseJson);
        if (parseJson && !areObjectValuesDefined(env)) {
            return res.status(400).send('JSON path does not match');
        }
        next();
    };
}

import areObjectValuesDefined from '../utils/areObjectValuesDefined';
import pickVariablesFromJson from '../utils/pickVariablesFromJson';

/**
 * "parseJson" Express middelware
 * @see https://github.com/danistefanovic/hooka/blob/master/docs/webhooks.md#parsejson
 * @param {Array} parseJson Config for "parseJson"
 * @return {void}
 */
export default function parseJsonValidator(parseJson) {
    return (req, res, next) => {
        const env = pickVariablesFromJson(req.body, parseJson);
        if (parseJson && !areObjectValuesDefined(env)) {
            const variables = JSON.stringify(env, replaceUndefined, '  ');
            return res.status(400).send(`A JSON path does not match: ${variables}`);
        }
        next();
    };
}

function replaceUndefined(key, value) {
    return (value === undefined) ? 'not found' : value;
}

Add variables to 'parseJson' error message


/**
 * @author Arnold Koh <arnold@kohded.com>
 * Developed: 4/10/2017
 * File: bubble-sort-test.js
 */

const expect = require('chai').expect;
const bubbleSort = require('../../../algorithms/sorting/bubble-sort');

describe('BubbleSort', () => {
  describe('#bubbleSort', () => {
    it('should return sorted array', () => {
      const unsorted = [9, 3, 7, 1, 8, 2, 9, 5, 4, 6, 0];

      expect(bubbleSort(unsorted)).to.eql([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9]);
    });
  });
});

/**
 * @author Arnold Koh <arnold@kohded.com>
 * Developed: 4/10/2017
 * File: bubble-sort-test.js
 */

const expect = require('chai').expect;
const bubbleSort = require('../../../algorithms/sorting/bubble-sort');

describe('BubbleSort', () => {
  describe('#bubbleSort(array)', () => {
    it('should return sorted array', () => {
      const unsorted = [9, 3, 7, 1, 8, 2, 9, 5, 4, 6, 0];

      expect(bubbleSort(unsorted)).to.eql([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9]);
    });
  });
});

Update bubble sort test title


'use strict';

var d        = require('es5-ext/lib/Object/descriptor')
  , DOMInput = require('../_controls/input')

  , StringLine = require('dbjs/lib/objects')._get('StringLine')
  , Input;

require('../');

Input = function (document, ns/*, options*/) {
	DOMInput.apply(this, arguments);
	this.dom.setAttribute('type', 'text');
	if (ns.pattern) {
		this.dom.setAttribute('pattern', ns.pattern.source.slice(1, -1));
	}
	if (ns.max) this.dom.setAttribute('maxlength', ns.max);
	this.dom.addEventListener('input', this.onchange.bind(this), false);
};
Input.prototype = Object.create(DOMInput.prototype, {
	constructor: d(Input),
	knownAttributes: d({ class: true, id: true, required: true, style: true,
		placeholder: true })
});

module.exports = Object.defineProperty(StringLine, 'DOMInput', d(Input));

'use strict';

var d        = require('es5-ext/lib/Object/descriptor')
  , Db       = require('dbjs')
  , DOMInput = require('../_controls/input')

  , StringLine = require('dbjs/lib/objects')._get('StringLine')
  , Input;

require('../');

Input = function (document, ns/*, options*/) {
	var options = Object(arguments[2]), pattern;
	DOMInput.call(this, document, ns, options);
	this.dom.setAttribute('type', 'text');
	if (options.relation && options.relation.__pattern.__value) {
		pattern = Db.RegExp(options.relation.__pattern.__value);
	}
	if (!pattern) pattern = ns.pattern;
	this.dom.setAttribute('pattern', pattern.source.slice(1, -1));
	if (ns.max) this.dom.setAttribute('maxlength', ns.max);
	this.dom.addEventListener('input', this.onchange.bind(this), false);
};
Input.prototype = Object.create(DOMInput.prototype, {
	constructor: d(Input),
	knownAttributes: d({ class: true, id: true, required: true, style: true,
		placeholder: true })
});

module.exports = Object.defineProperty(StringLine, 'DOMInput', d(Input));

Support pattern provided on relation


'use strict';

// test MemberLookupExpression
function f(a) {
  var b = [42];
  return (a||b)[0];
}

assert.equal(42, f(null));
assert.equal(43, f([43]));

// test NewExpression
var a, b = function() { this.ans = 42; };
assert.equal(new (a||b)().ans, 42);

a = function() { this.ans = 43; };
assert.equal(new (a||b)().ans, 43);

// test CallExpression
a = undefined;
b = function() { return 42; }
assert.equal((a||b)(), 42);

a = function() { return 43; }
assert.equal((a||b)(), 43);

'use strict';

(function() {

// test MemberLookupExpression
function f(a) {
  var b = [42];
  return (a||b)[0];
}

assert.equal(42, f(null));
assert.equal(43, f([43]));

// test NewExpression
var a, b = function() { this.ans = 42; };
assert.equal(new (a||b)().ans, 42);

a = function() { this.ans = 43; };
assert.equal(new (a||b)().ans, 43);

// test CallExpression
a = undefined;
b = function() { return 42; }
assert.equal((a||b)(), 42);

a = function() { return 43; }
assert.equal((a||b)(), 43);

})();

Fix test that has conflicting globals


'use strict'

const _ = require('lodash')

module.exports = function createError (message, status) {
  let props
  let Constructor = Error

  if (_.isPlainObject(message)) {
    props = _.omit(message, 'message')

    if (message.constructor) {
      Constructor = props.constructor
    }

    message = message.message || 'Error'
  } else {
    props = {}
  }

  if (_.isPlainObject(status)) {
    Object.assign(props, status)
  } else if (typeof status === 'number') {
    props.status = status
  }

  const err = new Constructor(message)

  Object.assign(err, props)

  return err
}

'use strict'

const _ = require('lodash')

module.exports = function createError (message, status) {
  let props
  let ErrorConstructor = Error

  if (_.isPlainObject(message)) {
    props = _.omit(message, 'message')

    if (message.errorConstructor) {
      ErrorConstructor = props.errorConstructor
    }

    message = message.message || 'Error'
  } else {
    props = {}
  }

  if (_.isPlainObject(status)) {
    Object.assign(props, status)
  } else if (typeof status === 'number') {
    props.status = status
  }

  const err = new ErrorConstructor(message)

  Object.assign(err, props)

  return err
}

Rename constructor option to avoid collision with prototype constructor


var request = require('request');
var url = require('url');

var messageJson = function (token, message, cb) {

  if (!token) {
    cb(new Error('Needs token'));
    return;
  }

  var result = {'token':token};
  if (message) {
    result.message = message;
  }
  cb(null,result);
};

module.exports.sendMessage = function (endpoint, token, message, cb) {

  var urlObject = url.parse(endpoint);
  if (urlObject.protocol !== 'https:') {
    cb(new Error('Requires https'));
    return;
  }

  messageJson(token,message,function(err,result){
    if (err) {
      cb(err);
      return;
    }
    request.post(endpoint,{
      formData:result,
      json:true
    },function(err, res, body){
      cb(err,res);
    });
  });
};

module.exports.messageJson = messageJson;

var request = require('request');
var url = require('url');

var messageJson = function (token, message, cb) {

  if (!token) {
    cb(new Error('Needs token'));
    return;
  }

  var result = {'token':token, 'type': 'message'};
  if (message) {
    result.message = message;
  }
  cb(null,result);
};

module.exports.sendMessage = function (endpoint, token, message, cb) {

  var urlObject = url.parse(endpoint);
  if (urlObject.protocol !== 'https:') {
    cb(new Error('Requires https'));
    return;
  }

  messageJson(token,message,function(err,result){
    if (err) {
      cb(err);
      return;
    }
    request.post(endpoint,{
      formData:result,
      json:true
    },function(err, res, body){
      cb(err,res);
    });
  });
};

module.exports.messageJson = messageJson;

Add type=message for high priority notifications


export default function render(vnode, parent) {
	if (typeof vnode==='string') return document.createTextNode(vnode);

  let n = document.createElement(vnode.nodeName);

  let a = vnode.attributes || {};
  Object.keys(a).forEach( k => n.setAttribute(k, a[k]) );

  (vnode.children || []).forEach( c => n.appendChild(render(c)) );

  parent.appendChild(n);

  return n;
}

export default function render(vnode, parent) {
	if (typeof vnode==='string') return document.createTextNode(vnode);

  if (typeof vnode === 'function') vnode = vnode();

  let n = document.createElement(vnode.nodeName);

  let a = vnode.attributes || {};
  Object.keys(a).forEach( k => n.setAttribute(k, a[k]) );

  (vnode.children || []).forEach( c => n.appendChild(render(c)) );

  parent.appendChild(n);

  return n;
}

Check if vnode is function


contract('Ownable', function(accounts) {
  it("should have an owner", function(done) {
    var ownable = Ownable.deployed();
    return ownable.owner()
    .then(function(owner) {
      assert.isTrue(owner != 0);
    })
    .then(done)
  });

  it("changes owner after transfer", function(done) {
    var ownable = Ownable.deployed();
    var other = '0xe682569efa3752a07fdc09885007c47beee803a7';
    return ownable.transfer(other)
    .then(function() {
      return ownable.owner();
    })
    .then(function(owner) {
      assert.isTrue(owner === other);
    })
    .then(done)
  });
});

contract('Ownable', function(accounts) {
  it("should have an owner", function(done) {
    var ownable = Ownable.deployed();
    return ownable.owner()
    .then(function(owner) {
      assert.isTrue(owner != 0);
    })
    .then(done)
  });

  it("changes owner after transfer", function(done) {
    var ownable = Ownable.deployed();
    var other = accounts[1];
    return ownable.transfer(other)
    .then(function() {
      return ownable.owner();
    })
    .then(function(owner) {
      assert.isTrue(owner === other);
    })
    .then(done)
  });

  it("should prevent non-owners from transfering" ,function(done) {
    var ownable = Ownable.deployed();
    var other = accounts[2];
    return ownable.transfer(other, {from: accounts[2]})
    .then(function() {
      return ownable.owner();
    })
    .then(function(owner) {
      assert.isFalse(owner === other);
    })
    .then(done)
  });

});

Test that Ownable prevents non-owners from changing ownership.


#!/usr/bin/env node
// Usage:  ghw <input> <output dir>
// where <input> is either a file or a dir.
var VERSION = '0.0.1'

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

var args = process.argv.splice(2);
var input = args[0];
var output = args[1];

console.log('ghw ' + VERSION);

if(!input) {
    console.log('Missing input and output!');

    return;
}

if(!output) {
    console.log('Missing output!');

    return;
}

console.log(input, output);

parseFile(input);

function parseFile(path) {
    fs.readFile(path, 'utf-8', function(err, data) {
        if (err) throw err;

        var tokens = marked.lexer(data);
        console.log(tokens);

        // TODO: convert links to something sensible
        // TODO: write to HTML
    });
}

#!/usr/bin/env node
// Usage:  ghw <input> <output dir>
// where <input> is either a file or a dir.
var VERSION = '0.0.1'

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

var args = process.argv.splice(2);
var input = args[0];
var output = args[1];

console.log('ghw ' + VERSION);

if(!input) {
    console.log('Missing input and output!');

    return;
}

if(!output) {
    console.log('Missing output!');

    return;
}

transform(input, output);

function transform(f, o) {
    fs.readFile(f, 'utf-8', function(err, data) {
        if (err) throw err;

        var tokens = marked(data); //marked.lexer(data);

        // TODO: convert links to something sensible
        //console.log(tokens);

        // TODO: mkdir if necessary
        var target = o + f.substring(f.lastIndexOf('/'), f.length).substring(0, f.indexOf('.')) + 'html';
        fs.writeFile(target, tokens, function(err) {
            if (err) throw err;

            console.log('Wrote ' + target);
        })
    });
}

Make naive HTML output work


import Ember from 'ember';
import layout from '../templates/components/smd-form';

export default Ember.Component.extend({
  // Services
  toaster: Ember.inject.service('smd-toaster'),
  // Attributes
  layout,
  tagName: 'form',
  model: null,
  errorMessage: 'Please correct the errors in the form',
  // Computed
  childFormControls: Ember.computed('childViews', function() {
    var childViews = this.get('childViews');
    if (childViews) {
      return childViews.filter(function(currentChildView) {
        return currentChildView.constructor.toString().indexOf('smd-form-control') !== -1;
      });
    }
  }),
  // Events
  submit(e) {
    e.preventDefault();

    var errorMessages = [];

    var formControls = this.get('childFormControls');

    formControls.forEach(
      function(formControl) {
        if (!formControl.get('validation.isValid')) {
          errorMessages.addObjects(formControl.get('validation.errors').mapBy('message'));
        }
        formControl.set('didValidate', true);
      }
    );

    if (errorMessages.length !== 0) {
      var errorMessage = errorMessages.join(', ');
      Ember.Logger.log("Errors: " + errorMessage);
      this.get('toaster').setMessage(this.get('errorMessage'));
      return;
    }
    this.sendAction('action', this.get('model'));
  },
  didInsertElement() {
    this._super(...arguments);
  }
});

import Ember from 'ember';
import layout from '../templates/components/smd-form';

export default Ember.Component.extend({
  // Services
  toaster: Ember.inject.service('smd-toaster'),
  // Attributes
  layout,
  tagName: 'form',
  model: null,
  errorMessage: 'Please correct the errors in the form',
  // Computed
  childFormControls: Ember.computed('childViews', function() {
    var childViews = this.get('childViews');
    if (childViews) {
      return childViews.filter(function(currentChildView) {
        return currentChildView.constructor.toString().indexOf('smd-form-control') !== -1;
      });
    }
  }),
  // Events
  submit(e) {
    e.preventDefault();

    var errorMessages = [];

    var formControls = this.get('childFormControls');

    formControls.forEach(
      function(formControl) {
        if (formControl.get('validation') && !formControl.get('validation.isValid')) {
          errorMessages.addObjects(formControl.get('validation.errors').mapBy('message'));
        }
        formControl.set('didValidate', true);
      }
    );

    if (errorMessages.length !== 0) {
      var errorMessage = errorMessages.join(', ');
      Ember.Logger.log("Errors: " + errorMessage);
      this.get('toaster').setMessage(this.get('errorMessage'));
      return;
    }
    this.sendAction('action', this.get('model'));
  },
  didInsertElement() {
    this._super(...arguments);
  }
});

Handle fields without validation objects attached


'use strict';

var https = require('https');

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

var url = 'https://gulpjs.com/plugins/blackList.json';

function collect(stream, cb) {
  stream.on('error', cb);
  stream.pipe(concat(onSuccess));

  function onSuccess(result) {
    cb(null, result);
  }
}

function parse(str, cb) {
  try {
    cb(null, JSON.parse(str));
  } catch (err) {
    /* istanbul ignore next */
    cb(new Error('Invalid Blacklist JSON.'));
  }
}

// TODO: Test this impl
function getBlacklist(cb) {
  https.get(url, onRequest);

  function onRequest(res) {
    /* istanbul ignore if */
    if (res.statusCode !== 200) {
      // TODO: Test different status codes
      return cb(new Error('Request failed. Status Code: ' + res.statusCode));
    }

    res.setEncoding('utf8');

    collect(res, onCollect);
  }

  function onCollect(err, result) {
    /* istanbul ignore if */
    if (err) {
      return cb(err);
    }

    parse(result, onParse);
  }

  function onParse(err, blacklist) {
    /* istanbul ignore if */
    if (err) {
      return cb(err);
    }

    cb(null, blacklist);
  }
}

module.exports = getBlacklist;

'use strict';

var https = require('https');

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

var url = 'https://raw.githubusercontent.com/gulpjs/plugins/master/src/blackList.json';

function collect(stream, cb) {
  stream.on('error', cb);
  stream.pipe(concat(onSuccess));

  function onSuccess(result) {
    cb(null, result);
  }
}

function parse(str, cb) {
  try {
    cb(null, JSON.parse(str));
  } catch (err) {
    /* istanbul ignore next */
    cb(new Error('Invalid Blacklist JSON.'));
  }
}

// TODO: Test this impl
function getBlacklist(cb) {
  https.get(url, onRequest);

  function onRequest(res) {
    /* istanbul ignore if */
    if (res.statusCode !== 200) {
      // TODO: Test different status codes
      return cb(new Error('Request failed. Status Code: ' + res.statusCode));
    }

    res.setEncoding('utf8');

    collect(res, onCollect);
  }

  function onCollect(err, result) {
    /* istanbul ignore if */
    if (err) {
      return cb(err);
    }

    parse(result, onParse);
  }

  function onParse(err, blacklist) {
    /* istanbul ignore if */
    if (err) {
      return cb(err);
    }

    cb(null, blacklist);
  }
}

module.exports = getBlacklist;

Use the raw GitHub URL for old blacklist


/*
 * Setup for browser-based dig.
 */
(function() {
  if (typeof require === undefined) {
    function require() {};
  }

/*
 * Setup for browser-based dig.
 */
(function() {
  if (typeof require === "undefined") {
    function require() {};
  }

Fix bug with check for require()


/**
 * @author {{{author}}}
 * @since {{{date}}}
 */

(function () {
    'use strict';

    angular
        .module(moduleName)
        .service('{{{elementName}}}', {{{elementName}}});

    /* @ngInject */
    function {{{elementName}}} ($log) {
        var service = {};

        /// Service Public API ///
        service.method = method;
        ///////////////

        return service;

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

        function method() {
            // TODO autogenerated method stub...
        }

    }
})();

/**
 * @author {{{author}}}
 * @since {{{date}}}
 */

(function () {
    'use strict';

    angular
        .module({{{moduleName}}})
        .service('{{{elementName}}}', {{{elementName}}});

    /* @ngInject */
    function {{{elementName}}} ($log) {
        var service = {};

        /// Service Public API ///
        service.method = method;
        ///////////////

        return service;

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

        function method() {
            // TODO autogenerated method stub...
        }

    }
})();

Fix module name not being wrapped to read from variable