import axios from 'axios';

export default itemIdentifier => axios.get(`items`, {
  baseURL: `https://track.bpost.be/btr/api/`,
  responseType: `json`,
  params: { itemIdentifier },
}).then(res => res.data.items[0])
.catch(e => e);

const axios = require(`axios`);

export default itemIdentifier => axios.get(`items`, {
  baseURL: `https://track.bpost.be/btr/api/`,
  responseType: `json`,
  params: { itemIdentifier },
}).then(res => res.data.items[0])
.catch(e => e);

Revert using es6 import for axios


/*
  -- utils.js
  This file contains generic functions for other javascript files to use.
  Like returnTime(), capitalize() etc.

*/

/**
 * Get unix time
 * @returns {number}
 */
export function returnTime() {
  let d = new Date();
  return d.getTime();
}

/**
 * Updates the current phrase's scroll amount
 * called after a new word pushed to current phrase
 */
export function updateCurrentPhraseScroll() {
  return setTimeout(function () {
    let element = document.getElementById('cPhrase');
    if (element) {
      element.scrollLeft = element.scrollWidth - window.innerWidth;
    }
  }, 1);
}

/**
 * capitalize first letter
 * @param {string} str
 * @returns {string}
 */
export function capitalize(str) {
  return str.charAt(0)
    .toLocaleUpperCase() + str.slice(1);
}

/**
 * Find the device the types
 *
 * @param {number} w Width
 * @param {number} h Height
 * @returns {string} the device types which can be 'phone' or 'tablet'
 */
export function deviceType(w, h) {
  let type;
  let total;
  if (w && h) {
    total = w + h;
  } else {
    total = window.innerWidth + window.innerHeight;
  }

  if (total < 1500) {
    type = 'phone';
  } else {
    type = 'tablet';
  }
  return type;
}

/*
  -- utils.js
  This file contains generic functions for other javascript files to use.
  Like returnTime(), capitalize() etc.

*/

/**
 * Get unix time
 * @returns {number}
 */
export function returnTime() {
	let d = new Date();
	return d.getTime();
}

/**
 * Updates the current phrase's scroll amount
 * called after a new word pushed to current phrase
 */
export function updateCurrentPhraseScroll() {
	setTimeout(() => {
		let element = document.getElementById('cPhrase');
		element.scrollLeft = element.scrollWidth;
	}, 1);
}

/**
 * capitalize first letter
 * @param {string} str
 * @returns {string}
 */
export function capitalize(str) {
	return str.charAt(0)
		.toLocaleUpperCase() + str.slice(1);
}

/**
 * Find the device the types
 *
 * @param {number} w Width
 * @param {number} h Height
 * @returns {string} the device types which can be 'phone' or 'tablet'
 */
export function deviceType(w, h) {
	let type;
	let total;
	if (w && h) {
		total = w + h;
	} else {
		total = window.innerWidth + window.innerHeight;
	}

	if (total < 1500) {
		type = 'phone';
	} else {
		type = 'tablet';
	}
	return type;
}

Fix scrolling to the end of the current phrase


'use strict'

const { ApolloServer } = require('apollo-server-lambda')
const { UnsignedIntResolver, UnsignedIntTypeDefinition, DateTimeResolver, DateTimeTypeDefinition } = require('graphql-scalars')

const connect = require('../src/utils/connect')
const isDemoMode = require('../src/utils/isDemoMode')
const isDevelopmentMode = require('../src/utils/isDevelopmentMode')
const { createServerlessContext } = require('../src/utils/createContext')

const allowOrigin = process.env.ACKEE_ALLOW_ORIGIN || ''
const dbUrl = process.env.ACKEE_MONGODB || process.env.MONGODB_URI

if (dbUrl == null) {
	throw new Error('MongoDB connection URI missing in environment')
}

connect(dbUrl)

const apolloServer = new ApolloServer({
	introspection: isDemoMode === true || isDevelopmentMode === true,
	playground: isDemoMode === true || isDevelopmentMode === true,
	debug: isDevelopmentMode === true,
	cors: {
		origin: allowOrigin.split(','),
		methods: 'GET,POST,PATCH,OPTIONS',
		allowedHeaders: 'Content-Type'
	},
	typeDefs: [
		UnsignedIntTypeDefinition,
		DateTimeTypeDefinition,
		require('../src/types')
	],
	resolvers: {
		UnsignedInt: UnsignedIntResolver,
		DateTime: DateTimeResolver,
		...require('../src/resolvers')
	},
	context: createServerlessContext
})

exports.handler = apolloServer.createHandler()

'use strict'

const { ApolloServer } = require('apollo-server-lambda')
const { UnsignedIntResolver, UnsignedIntTypeDefinition, DateTimeResolver, DateTimeTypeDefinition } = require('graphql-scalars')

const connect = require('../src/utils/connect')
const isDemoMode = require('../src/utils/isDemoMode')
const isDevelopmentMode = require('../src/utils/isDevelopmentMode')
const { createServerlessContext } = require('../src/utils/createContext')

const allowOrigin = process.env.ACKEE_ALLOW_ORIGIN || ''
const dbUrl = process.env.ACKEE_MONGODB || process.env.MONGODB_URI

if (dbUrl == null) {
	throw new Error('MongoDB connection URI missing in environment')
}

connect(dbUrl)

const apolloServer = new ApolloServer({
	introspection: isDemoMode === true || isDevelopmentMode === true,
	playground: isDemoMode === true || isDevelopmentMode === true,
	debug: isDevelopmentMode === true,
	cors: {
		origin: allowOrigin === '*' ? true : allowOrigin.split(','),
		methods: 'GET,POST,PATCH,OPTIONS',
		allowedHeaders: 'Content-Type'
	},
	typeDefs: [
		UnsignedIntTypeDefinition,
		DateTimeTypeDefinition,
		require('../src/types')
	],
	resolvers: {
		UnsignedInt: UnsignedIntResolver,
		DateTime: DateTimeResolver,
		...require('../src/resolvers')
	},
	context: createServerlessContext
})

exports.handler = apolloServer.createHandler()

Support CORS wildcard for serverless function


'use strict';

var assert = require('assert');
var path = require('path');
var execFileSync = require('child_process').execFileSync;

var root = path.resolve(__dirname, '..');
var hook = path.relative(root, 'bin/commit-msg');
var validFile = path.relative(root,
    path.resolve(__dirname, 'resources/COMMIT_EDITMSG'));
var invalidFile = path.relative(root,
    path.resolve(__dirname, 'resources/COMMIT_EDITMSG-invalid'));

describe('commig-msg', function() {

    describe('valid', function() {
        it('should exit with status 0', function() {
            assert.doesNotThrow(
                function() {
                    execFileSync('node', [hook, validFile], {
                        cwd: root,
                        encoding: 'utf8',
                        stdio: [null]
                    });
                }
            );
        });
    });

    describe('invalid', function() {
        it('should exit with error status 9', function() {
            assert.throws(
                function() {
                    execFileSync('node', [hook, invalidFile], {
                        cwd: root,
                        encoding: 'utf8',
                        stdio: [null]
                    });
                },
                function(e) {
                    return e.status === 9;
                }
            );
        });
    });

});

'use strict';

var assert = require('assert');
var path = require('path');
var execFileSync = require('child_process').execFileSync;

var root = path.resolve(__dirname, '..');
var hook = path.relative(root, 'bin/commit-msg');
var validFile = path.relative(root,
    path.resolve(__dirname, 'resources/COMMIT_EDITMSG'));
var invalidFile = path.relative(root,
    path.resolve(__dirname, 'resources/COMMIT_EDITMSG-invalid'));

describe('commig-msg', function() {
    this.timeout(5000); // allow enough time

    describe('valid', function() {
        it('should exit with status 0', function() {
            assert.doesNotThrow(
                function() {
                    execFileSync('node', [hook, validFile], {
                        cwd: root,
                        encoding: 'utf8',
                        stdio: [null]
                    });
                }
            );
        });
    });

    describe('invalid', function() {
        it('should exit with error status 9', function() {
            assert.throws(
                function() {
                    execFileSync('node', [hook, invalidFile], {
                        cwd: root,
                        encoding: 'utf8',
                        stdio: [null]
                    });
                },
                function(e) {
                    return e.status === 9;
                }
            );
        });
    });

});

Increase test timeout again for Travis


var data = require('../lib/data')
var test = require('tape')
var needleman = require('../lib/index')

test('run', function (t) {
  let v = 'GCATGCU'
  let w = 'GATTACA'
  let scores = { match: +1, mismatch: -1 }
  let scoringMatrix = data.scoringMatrix({ v, w, scores })
  let res = needleman.run(v, w, { scoringMatrix })
  t.equal(res.score, 0)
  t.equal(res.vAligned, 'GCA-TGCU')
  t.equal(res.wAligned, 'G-ATTACA')
  t.end()
})

var data = require('../lib/data')
var test = require('tape')
var needleman = require('../lib/index')

test('run', function (t) {
  let v = 'GCATGCU'
  let w = 'GATTACA'
  let scores = { match: +1, mismatch: -1 }
  let scoringMatrix = data.scoringMatrix({ v, w, scores })
  let res = needleman.run(v, w, { scoringMatrix })
  t.equal(res.score, 0)
  t.equal(res.vAligned, 'GCA-TGCU')
  t.equal(res.wAligned, 'G-ATTACA')

  scoringMatrix = data.scoringMatrix({ v, w, name: 'PAM250' })
  res = needleman.run(v, w, { scoringMatrix })
  t.equal(res.score, 20)
  t.equal(res.vAligned, 'GCA-TGCU')
  t.equal(res.wAligned, 'G-ATTACA')

  t.end()
})

Test a run with PAM250


const { expect } = require('chai');
const Plexacious = require('../src/Plexacious');
const config = {
  hostname: 'macedonia.ketsugi.com',
  token: process.env.PLEX_AUTH_TOKEN
}

const plex = new Plexacious();

describe('Plexacious:', () => {
});

const { expect } = require('chai');
const Plexacious = require('../src/Plexacious');
const config = {
  hostname: 'macedonia.ketsugi.com',
  token: process.env.PLEX_AUTH_TOKEN
}

const plex = new Plexacious();

describe('Plexacious:', () => {
  describe('Environment:', () => {
    it('should read the environment variable correctly', () => {
      expect(config.token).to.not.be.null;
    });
  });
});

Add a quick test to make sure the test is loading the environment var correctly in the Travis CI environment


Array.prototype.stride = function(callback) {
	var stride_length = callback.length;
	var ret = [];
	for (var i=0; i<this.length; i+=stride_length) {
		ret.push(callback.apply(i,this.slice(i,i+stride_length)));
	}
	return ret;
}

Array.prototype.stride = function(callback,undef) {
	var stride_length = callback.length;
	var ret = [];
	var l=0;
	for (var i=0; i<this.length; i+=stride_length) {
		var slice = this.slice(i,i+stride_length);
		if (i+stride_length >= this.length) {
			for (var j=this.length%stride_length; j<stride_length; j++) {
				slice[j] = undef;
			}
		}
		ret.push(callback.apply(l,slice));
		l++;
	}
	return ret;
}

Allow valued to be specified for undefined


#!/usr/bin/env node

var oust = require('../index');
var pkg = require('../package.json');
var fs = require('fs');

var argv = require('minimist')(process.argv.slice(2));

var printHelp = function() {
    console.log('oust');
    console.log(pkg.description);
    console.log('');
    console.log('Usage:');
    console.log('  $ oust <filename> <selector>');
};

if(argv.h || argv.help) {
    printHelp();
    return;
}

if(argv.v || argv.version) {
    console.log(pkg.version);
    return;
}

var file = argv._[0];
var selector = argv._[1];

fs.readFile(file, function(err, data) {
    if(err) {
        console.error('Error opening file:', err.message);
        process.exit(1);
    }
    var res = oust(data, selector);
    console.log(res.join("\n"));
});

#!/usr/bin/env node

var oust = require('../index');
var pkg = require('../package.json');
var fs = require('fs');

var argv = require('minimist')(process.argv.slice(2));

var printHelp = function() {
    console.log('oust');
    console.log(pkg.description);
    console.log('');
    console.log('Usage:');
    console.log('  $ oust <filename> <selector>');
};

if(argv.h || argv.help) {
    printHelp();
    return;
}

if(argv.v || argv.version) {
    console.log(pkg.version);
    return;
}

var file = argv._[0];
var type = argv._[1];

fs.readFile(file, function(err, data) {
    if(err) {
        console.error('Error opening file:', err.message);
        process.exit(1);
    }
    var res = oust(data, type);
    console.log(res.join("\n"));
});

Rename selector variable to type


module.exports = api => {
    api.cache(true);

    const presets = [
        [
            '@babel/preset-env',
            process.env.NODE_ENV === 'test'
                ? {}
                : {
                      modules: false,
                  },
        ],
        '@babel/preset-react',
        '@babel/preset-typescript',
    ];

    const plugins = ['@babel/plugin-proposal-class-properties'];

    return {
        presets,
        plugins,
    };
};

module.exports = api => {
    api.cache(true);

    const presets = [
        [
            '@babel/preset-env',
            process.env.NODE_ENV === 'test'
                ? {
                      useBuiltIns: 'usage', // for regeneratorRuntime
                  }
                : {
                      modules: false,
                  },
        ],
        '@babel/preset-react',
        '@babel/preset-typescript',
    ];

    const plugins = ['@babel/plugin-proposal-class-properties'];

    return {
        presets,
        plugins,
    };
};

Fix regeneratorRuntime missing in tests


function (doc) {
  if ('document' in doc && 'link' in doc.document) {
    emit(doc.document.link[0].href, 1);
  } else if ('uri' in doc) {
    emit(doc.uri);
  }
}

function (doc) {
  if ('document' in doc && 'link' in doc.document) {
    emit(doc.document.link[0].href, 1);
  } else if ('uri' in doc) {
    emit(doc.uri, 1);
  }
}

Fix value output for doc.uri URIs


'use strict';

var util = require('lib/util.js');

module.exports = {
	getTypeMessages: function(request, typeOptions) {
		var result = {};
		for (var key in typeOptions) {
			var callback = typeOptions[key];
			result[util.toCamelCase(key)] = callback(request, key)
		}

		return result;
	},
	getTypeMessageItem: function(request, type) {
		var messageIds = request.types[type];
		if (messageIds)	{
			return request.messages[messageIds[0]].payload;
		}
	},
	getTypeMessageList: function(request, type) {
		var messageIds = request.types[type];
		if (messageIds)	{
			return messageIds.map(function(id) { return request.messages[id].payload; });
		}
	}
};

'use strict';

var util = require('lib/util.js');

module.exports = {
	getTypeMessages: function(index, typeOptions) {
		var result = {};
		for (var key in typeOptions) {
			var callback = typeOptions[key];
			result[util.toCamelCase(key)] = callback(index, key)
		}

		return result;
	},
	getTypeMessageItem: function(index, type) {
		var messages = index[type];
		if (messages)	{
			return messages[0].payload;
		}
	},
	getTypeMessageList: function(index, type) {
		var messages = index[type];
		if (messages)	{
			return messages.map(function(message) { return message.payload; });
		}
	}
};

Update message processor to deal with list of messages rather than requests


'use strict';

var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var gutil = require('gulp-util');

var config = {
  js: ['src/**/*.js']
};

gulp.task('js', function () {
  // set up the browserify instance on a task basis
  var b = browserify({
    entries: './public/js/app.js',
    debug: true
  });

  return b.bundle()
    .pipe(source('bundle.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init({loadMaps: true}))
        // Add transformation tasks to the pipeline here.
        .pipe(uglify())
        .on('error', gutil.log)
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./public/js/'));
});

gulp.task('develop', ['js'], function() {
  gulp.watch(config.js, ['js']);
});

'use strict';

var browserify = require('browserify');
var gulp = require('gulp');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var sourcemaps = require('gulp-sourcemaps');
var gutil = require('gulp-util');

var config = {
  js: ['src/**/*.js', 'public/js/app.js']
};

gulp.task('js', function () {
  // set up the browserify instance on a task basis
  var b = browserify({
    entries: './public/js/app.js',
    debug: true
  });

  return b.bundle()
    .pipe(source('bundle.js'))
    .pipe(buffer())
    .pipe(sourcemaps.init({loadMaps: true}))
        // Add transformation tasks to the pipeline here.
        .pipe(uglify())
        .on('error', gutil.log)
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./public/js/'));
});

gulp.task('develop', ['js'], function() {
  gulp.watch(config.js, ['js']);
});

Add public/js/app.js to watched source files


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

var clientConfig = require('./config/webpack.prod.client.js')
var serverConfig = require('./config/webpack.prod.server.js')

gulp.task('bundle-client', function(done) {
    webpack( clientConfig ).run(onBundle(done))
});

gulp.task('bundle-server', function(done) {
    webpack( serverConfig ).run(onBundle(done))
});

gulp.task('copy-html', function() {
	gulp.src('./src/index.html').pipe(gulp.dest('./app'))
});

gulp.task('bundle', ['bundle-client', 'bundle-server', 'copy-html']);

function onBundle(done) {
    return function(err, stats) {
        if (err) console.log('Error', err);
        else console.log(stats.toString());
        done()
    }
}

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

var clientConfig = require('./config/webpack.prod.client.js')
var serverConfig = require('./config/webpack.prod.server.js')

gulp.task('bundle-client', function(done) {
    webpack( clientConfig ).run(onBundle(done))
});

gulp.task('bundle-server', function(done) {
    webpack( serverConfig ).run(onBundle(done))
});

gulp.task('move-index', function() {
	gulp.src('./src/index.html').pipe(gulp.dest('./app'))
});

gulp.task('move-assets', ['move-index'], function() {
	gulp.src('./src/assets/**/*', {base: './src'}).pipe(gulp.dest('./app/'))
});

gulp.task('bundle', ['bundle-client', 'bundle-server']);
gulp.task('build', ['bundle', 'move-assets'])

function onBundle(done) {
    return function(err, stats) {
        if (err) console.log('Error', err);
        else console.log(stats.toString());
        done()
    }
}

Add tasks for asset moving on build


var gulp = require('gulp');
var cssmin = require('gulp-cssmin');
var uglify = require('gulp-uglify');
var nodemon = require('gulp-nodemon');
var gif = require('gulp-if');

var inProduction = process.env['NODE_ENV'] == 'production';

gulp.task('asset-css', function() {
  gulp.src('assets/css/main.css')
    .pipe(gif(inProduction, cssmin()))
    .pipe(gulp.dest('production/css'));
});

gulp.task('asset-js', function() {
  gulp.src('assets/js/*')
    .pipe(gif(inProduction, uglify()))
    .pipe(gulp.dest('production/js'));
});

gulp.task('build', ['asset-css', 'asset-js']);

gulp.task('watch-app', function() {
  nodemon({
    script: 'app.js',
    ext: 'js json',
    env: {'NODE_ENV': 'development'}
  });
});

var gulp = require('gulp');
var cssmin = require('gulp-cssmin');
var uglify = require('gulp-uglify');
var nodemon = require('gulp-nodemon');
var gif = require('gulp-if');

var inProduction = process.env['NODE_ENV'] == 'production';

gulp.task('build-assets-css', function() {
  gulp.src('assets/css/main.css')
    .pipe(gif(inProduction, cssmin()))
    .pipe(gulp.dest('production-assets/css'));
});

gulp.task('build-assets-js', function() {
  gulp.src('assets/js/*')
    .pipe(gif(inProduction, uglify()))
    .pipe(gulp.dest('production-assets/js'));
});

gulp.task('build-assets', ['build-assets-css', 'build-assets-js']);

gulp.task('watch-app', function() {
  nodemon({
    script: 'app.js',
    ext: 'js json',
    env: {'NODE_ENV': 'development'}
  });
});

Standardize the gulp task names (build-type-name)


define({
    "web": {
        "client_id": "745152835189.apps.googleusercontent.com",
        "client_secret": "notasecret",
        "redirect_uris": [],
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://accounts.google.com/o/oauth2/token"
    }
});

Use a new client ID


module.exports = function(grunt, config, parameters, done) {
	var workFolder = parameters.releaseWorkFolder || './release/source';
	function endForError(error) {
		process.stderr.write(error.message || error);
		done(false);
	}
	try {
		var path = require('path'),
			exec = require('child_process').exec,
			fs = require('fs');
		process.stdout.write('Installng PHP dependencies with Composer... ');
		exec(
			'composer install --prefer-dist --no-dev',
			{
				cwd: path.join(workFolder, 'concrete')
			},
			function(error, stdout, stderr) {
				if(error) {
					endForError(stderr || error);
					return;
				}
				process.stdout.write('done.\n');
				done();
			}
		);
	}
	catch(e) {
		endForError(e);
		return;
	}
};

module.exports = function(grunt, config, parameters, done) {
	var workFolder = parameters.releaseWorkFolder || './release/source';
	function endForError(error) {
		process.stderr.write(error.message || error);
		done(false);
	}
	try {
		var path = require('path'),
			exec = require('child_process').exec,
			fs = require('fs');
		process.stdout.write('Installng PHP dependencies with Composer... ');
		exec(
			'composer install --prefer-dist --no-dev',
			{
				cwd: workFolder
			},
			function(error, stdout, stderr) {
				if(error) {
					endForError(stderr || error);
					return;
				}
				process.stdout.write('done.\n');
				done();
			}
		);
	}
	catch(e) {
		endForError(e);
		return;
	}
};

Call composer from the webroot


import React, {Component} from 'react';
import {Table} from 'react-bootstrap';
import {connect} from 'react-redux';
import _ from 'lodash';

class UsersTable extends Component {

  render() {
    return (

             {this.props.heading}

          {this.props.users.map(_.startCase).sort().map((x) => _renderUserRow(x))}

    );
  }
}

function _renderUserRow(data) {
  return (

      {data}

  )
}

function mapStateToProps(state) {
  return {
    users: state.users
  };
}

export default connect(mapStateToProps)(UsersTable);

import React, {Component} from 'react';
import {Table} from 'react-bootstrap';
import {connect} from 'react-redux';
import _ from 'lodash';

class UsersTable extends Component {

  render() {
    return (

             {this.props.heading}

          {_.union(this.props.playerName, this.props.users)
            .map(_.startCase).sort().map((x) => _renderUserRow(x))}

    );
  }
}

function _renderUserRow(data) {
  return (

      {data}

  )
}

function mapStateToProps(state) {
  return {
    users: state.users,
    playerName: state.game.playerName,
  };
}

export default connect(mapStateToProps)(UsersTable);

Update current user from props


define(['moment', 'nvd3', 'underscore', 'views/chart-view'],
    function(moment, nvd3, _, ChartView) {
        'use strict';

        /**
         * TrendsView renders several threads of timeline data over a period of
         * time on the x axis.
         */
        var TrendsView = ChartView.extend({

            defaults: _.extend({}, ChartView.prototype.defaults, {
                showLegend: false
            }),

            getChart: function() {
                return nvd3.models.lineChart();
            },

            initChart: function(chart) {
                var self = this;
                ChartView.prototype.initChart.call(this, chart);

                chart.showLegend(this.options.showLegend)
                    .useInteractiveGuideline(true);

                if (_(self.options).has('interactiveTooltipHeaderTemplate')) {
                    self.chart.interactiveLayer.tooltip.headerFormatter(function(d) {
                        return self.options.interactiveTooltipHeaderTemplate({value: d});
                    });
                }
            },

            formatXTick: function(d) {
                // overriding default to display a formatted date
                return moment.utc(d).format('D MMM YYYY');
            },

            parseXData: function(d) {
                var self = this;
                return Date.parse(d[self.options.x.key]);
            }

        });

        return TrendsView;
    }
);

define(['moment', 'nvd3', 'underscore', 'views/chart-view'],
    function(moment, nvd3, _, ChartView) {
        'use strict';

        /**
         * TrendsView renders several threads of timeline data over a period of
         * time on the x axis.
         */
        var TrendsView = ChartView.extend({

            defaults: _.extend({}, ChartView.prototype.defaults, {
                showLegend: false
            }),

            getChart: function() {
                return nvd3.models.lineChart();
            },

            initChart: function(chart) {
                var self = this;
                ChartView.prototype.initChart.call(this, chart);

                chart.showLegend(this.options.showLegend)
                    .useInteractiveGuideline(true);

                if (_(self.options).has('interactiveTooltipHeaderTemplate')) {
                    self.chart.interactiveLayer.tooltip.headerFormatter(function(d) {
                        return self.options.interactiveTooltipHeaderTemplate({value: self.formatXTick(d)});
                    });
                }
            },

            formatXTick: function(d) {
                // overriding default to display a formatted date
                return moment.utc(d).format('D MMM YYYY');
            },

            parseXData: function(d) {
                var self = this;
                return Date.parse(d[self.options.x.key]);
            }

        });

        return TrendsView;
    }
);

Format date when tooltip template is used.


import { get, set, setProperties } from '@ember/object';
import { hash } from 'rsvp';
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';

export default Route.extend({
  globalStore:  service(),
  clusterStore: service(),
  scope:        service(),

  model(params) {
    const clusterStore = get(this, 'clusterStore');

    const namespace = clusterStore.createRecord({
      type:      'namespace',
      name:      '',
      clusterId: get(this, 'scope.currentCluster.id'),
    });

    if (params.addTo) {
      set(namespace, 'projectId', get(params, 'addTo'));
    }

    return hash({
      namespace,
      namespaces:        get(this, 'clusterStore').findAll('namespace'),
      allProjects:       get(this, 'globalStore').findAll('project'),
    });
  },

  resetController(controller, isExiting/* , transition*/) {
    if ( isExiting ) {
      setProperties(controller, {
        errors:         null,
        istioInjection: false
      });
    }
  },
  queryParams: {
    addTo: { refreshModel: true },
    from:  { refreshModel: false }
  },

});

import { get, set, setProperties } from '@ember/object';
import { hash } from 'rsvp';
import { inject as service } from '@ember/service';
import Route from '@ember/routing/route';

export default Route.extend({
  globalStore:  service(),
  clusterStore: service(),
  scope:        service(),

  model(params) {
    const clusterStore = get(this, 'clusterStore');

    const namespace = clusterStore.createRecord({
      type:      'namespace',
      name:      '',
      clusterId: get(this, 'scope.currentCluster.id'),
    });

    if (params.addTo) {
      set(namespace, 'projectId', get(params, 'addTo'));
      const containerDefaultResourceLimit = get(namespace, 'project.containerDefaultResourceLimit');

      if ( containerDefaultResourceLimit ) {
        set(namespace, 'containerDefaultResourceLimit', containerDefaultResourceLimit);
      }
    }

    return hash({
      namespace,
      namespaces:        get(this, 'clusterStore').findAll('namespace'),
      allProjects:       get(this, 'globalStore').findAll('project'),
    });
  },

  resetController(controller, isExiting/* , transition*/) {
    if ( isExiting ) {
      setProperties(controller, {
        errors:         null,
        istioInjection: false
      });
    }
  },
  queryParams: {
    addTo: { refreshModel: true },
    from:  { refreshModel: false }
  },

});

Fix default container limit issue


/*****************************************************************************/
/* Client and Server Routes */
/*****************************************************************************/
Router.configure({
  layoutTemplate: 'MasterLayout',
  loadingTemplate: 'Loading',
  notFoundTemplate: 'NotFound'
});

Router.route('/', {
  name: 'marketing'
});

Router.route('/pages', {
  name: 'pages.index'
});

Router.route('/pages/new', {
  name: 'pages.new'
});

Router.route('/pages/:_id', {
  name: 'pages.show'
});

Router.route('/settings', {
  name: 'settings.index'
});

Router.route('/users/:_id', {
  name: 'users.show'
});

var requireLogin = function () {
  if (!Meteor.user()) {
    if (Meteor.loggingIn()) {
      this.render(this.loadingTemplate);
    } else {
      this.render('AccessDenied');
    }
  } else {
    this.next();
  }
};

Router.onBeforeAction('dataNotFound');
Router.onBeforeAction(requireLogin, {
  except: [
    'marketing',
    'pages.show'
  ]
});

/*****************************************************************************/
/* Client and Server Routes */
/*****************************************************************************/
Router.configure({
  layoutTemplate: 'MasterLayout',
  loadingTemplate: 'Loading',
  notFoundTemplate: 'NotFound'
});

Router.route('/', {
  name: 'marketing'
});

Router.route('/pages', {
  name: 'pages.index'
});

Router.route('/pages/new', {
  name: 'pages.new'
});

Router.route('/pages/:_id', {
  name: 'pages.show',
  fastRender: true
});

Router.route('/settings', {
  name: 'settings.index'
});

Router.route('/users/:_id', {
  name: 'users.show'
});

var requireLogin = function () {
  if (!Meteor.user()) {
    if (Meteor.loggingIn()) {
      this.render(this.loadingTemplate);
    } else {
      this.render('AccessDenied');
    }
  } else {
    this.next();
  }
};

Router.onBeforeAction('dataNotFound');
Router.onBeforeAction(requireLogin, {
  except: [
    'marketing',
    'pages.show'
  ]
});

Add fastRender flag to pages/:_id


var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');

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

gulp.task('sass', function () {
    return gulp.src('./src/main.scss')
        .pipe(sourcemaps.init())
        .pipe(sass().on('error', sass.logError))
        .pipe(sourcemaps.write())
        .pipe(gulp.dest('./static/styles'));
});

gulp.task('watch', function () {
    gulp.watch('./src/*.scss', ['sass']);
});

var gulp = require('gulp');
var sass = require('gulp-sass');
var sourcemaps = require('gulp-sourcemaps');

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

gulp.task('sass', function () {
    return gulp.src('./src/main.scss')
        .pipe(sourcemaps.init())
        .pipe(sass().on('error', sass.logError))
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest('./static/styles'));
});

gulp.task('watch', function () {
    gulp.watch('./src/*.scss', ['sass']);
});

Create separate sourcemaps file and not include into main.css


import {connect as connectToState} from 'react-redux';
import compose from 'lodash/flowRight';
import Button from './components/button';
import React, {Component, PropTypes} from 'react';
import map from 'lodash/map';
import SearchComponent from './searchComponent'
import OtherSearchComponent from './otherSearchComponent'
import SearchWithComponent from './searchWithComponent'

import FacetPanel from '../../components/facet';

const Home = () =>  {
  return <div style={{color: 'orange'}}>
    {/*<SearchComponent/>*/}
    {/*<OtherSearchComponent/>*/}
    {/*<SearchWithComponent/>*/}
    <FacetPanel title='My awesome facets'/>
  </div>;
}

const ConnectedComponentHome = compose(
  connectToState(s => ({reduxState: s}))
)(Home)
export default ConnectedComponentHome;

import {connect as connectToState} from 'react-redux';
import compose from 'lodash/flowRight';
import Button from './components/button';
import React, {Component, PropTypes} from 'react';
import map from 'lodash/map';
import SearchComponent from './searchComponent'
import OtherSearchComponent from './otherSearchComponent'
import SearchWithComponent from './searchWithComponent'
import ResultPanel from '../../components/results';

import FacetPanel from '../../components/facet';

const Home = () =>  {
  return <div style={{color: 'orange'}}>
    {/*<SearchComponent/>*/}
    {/*<OtherSearchComponent/>*/}
    {/*<SearchWithComponent/>*/}
    <ResultPanel />
    <FacetPanel title='My awesome facets'/>
  </div>;
}

const ConnectedComponentHome = compose(
  connectToState(s => ({reduxState: s}))
)(Home)
export default ConnectedComponentHome;

Update the example to use results.


const BaseDataview = require('./base');

const TYPE = 'list';

const listSqlTpl = ctx => `select ${ctx._columns} from (${ctx._query}) as _cdb_list`;

/**
{
    type: 'list',
    options: {
        columns: ['name', 'description']
    }
}
*/
module.exports = class List extends BaseDataview{
    constructor (query, options = {}) {
        super();

        this._checkOptions(options);

        this.query = query;
        this.columns = options.columns;
    }

    _checkOptions (options) {
        if (!Array.isArray(options.columns)) {
            throw new Error('List expects `columns` array in dataview options');
        }
    }

    sql (psql, override, callback) {
        if (!callback) {
            callback = override;
        }

        const listSql = listSqlTpl({
            _query: this.query,
            _columns: this.columns.join(', ')
        });

        return callback(null, listSql);
    }

    format (result) {
        return {
            rows: result.rows
        };
    }

    getType () {
        return TYPE;
    }

    toString () {
        return JSON.stringify({
            _type: TYPE,
            _query: this.query,
            _columns: this.columns.join(', ')
        });
    };
}

const BaseDataview = require('./base');
const debug = require('debug')('windshaft:dataview:list');

const TYPE = 'list';

const listSqlTpl = ctx => `select ${ctx._columns} from (${ctx._query}) as _cdb_list`;

/**
{
    type: 'list',
    options: {
        columns: ['name', 'description']
    }
}
*/
module.exports = class List extends BaseDataview {
    constructor (query, options = {}) {
        super();

        this._checkOptions(options);

        this.query = query;
        this.columns = options.columns;
    }

    _checkOptions (options) {
        if (!Array.isArray(options.columns)) {
            throw new Error('List expects `columns` array in dataview options');
        }
    }

    sql (psql, override, callback) {
        if (!callback) {
            callback = override;
        }

        const listSql = listSqlTpl({
            _query: this.query,
            _columns: this.columns.join(', ')
        });

        debug(listSql);

        return callback(null, listSql);
    }

    format (result) {
        return {
            rows: result.rows
        };
    }

    getType () {
        return TYPE;
    }

    toString () {
        return JSON.stringify({
            _type: TYPE,
            _query: this.query,
            _columns: this.columns.join(', ')
        });
    };
}

Use debug module to print sql for debugging purposes


define([

  'Backbone',

  //Collection
  'app/collections/tasks',

  //Template
  'text!templates/project-page/taskItemTemplate.html',
], function(

  Backbone,

  //Collection
  Tasks,

  //Template
  itemTemplate
){

  var TaskController = Backbone.View.extend({

    template: _.template(itemTemplate),

    initialize: function(){
      this.collection =  new Tasks(this.options.projectId);
      this.collection.bind('reset', this.render, this);
      this.collection.bind('search', this.searchResult, this);
    },

    searchResult: function(result){
      this.$el.html('');

      var template = this.template;
      var $list    = this.$el;
      var title;

      _.each(result, function(model){
        title = model.get('title');

        if(title){
          $list.append(template({title: model.get('title')}));
        }
      });
    },

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

      var template = this.template;
      var $list    = this.$el;

      _.each(this.collection.models, function(model){
        $list.append(template({title: model.get('title')}));
      });
    }
  });

  return TaskController;

});

define([

  'Backbone',

  //Collection
  'app/collections/tasks',

  //View
  'app/views/taskItemView',

  //Template
  'text!templates/project-page/taskItemTemplate.html',
], function(

  Backbone,

  //Collection
  Tasks,

  //View
  taskItemView,

  //Template
  itemTemplate
){

  var TaskController = Backbone.View.extend({

    template: _.template(itemTemplate),

    initialize: function(){
      this.collection =  new Tasks(this.options.projectId);
      this.collection.bind('reset', this.render, this);
      this.collection.bind('search', this.searchResult, this);
    },

    searchResult: function(result){
      this.$el.html('');

      var template = this.template;
      var $list    = this.$el;
      var title;

      _.each(result, function(model){
        title = model.get('title');

        if(title){
          $list.append(template({title: model.get('title')}));
        }
      });
    },

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

      var template = this.template;
      var $list    = this.$el;
      var task;

      _.each(this.collection.models, function(model){
        task = new taskItemView({ model: model });
        $list.append(task.el);
      });
    }
  });

  return TaskController;

});

Extend task list to a nested view


const encodings = require('encodings'),
      asserts = require('test').asserts,
      util = require('util');

require.paths.unshift('test/js/lib');

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

exports.test_generatorsInMoudles = function() {
  var a = require('./generator_test').run();

  var it = (k for (k in [1,2,3]) );
  asserts.same(a.toString(), "[object Generator]", "got a generator");
  asserts.same(typeof it.next, typeof a.next, "both generators have a 'next' method");
}

exports.test_utilRange = function() {
  var r = Util.Range(1,10,2);
  var a1 = [];

  for (let i in r) { a1.push(i) };

  asserts.same(a1, [1,3,5,7,9], "Util.Range works");
}

require('test').runner(exports);

const encodings = require('encodings'),
      asserts = require('test').asserts,
      util = require('util');

require.paths.unshift('test/js/lib');

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

exports.test_generatorsInMoudles = function() {
  var a = require('generator_test').run();

  var it = (k for (k in [1,2,3]) );
  asserts.same(a.toString(), "[object Generator]", "got a generator");
  asserts.same(typeof it.next, typeof a.next, "both generators have a 'next' method");
}

exports.test_utilRange = function() {
  var r = require('util').Range(1,10,2);
  var a1 = [];

  for (let i in r) { a1.push(i) };

  asserts.same(a1, [1,3,5,7,9], "Util.Range works");
}

require('test').runner(exports);

Fix old style causing test to fail.


/* eslint-env jasmine, mocha, chai */

import { define, vdom } from '../../../src';
import afterMutations from '../../lib/after-mutations';
import fixture from '../../lib/fixture';

const [svg] = vdom.builder('svg');

describe('vdom/svg', () => {
  it.only('#825 - should not error if window.SVGElement is undefined', done => {
    const oldSVGElement = window.SVGElement;
    window.SVGElement = undefined;
    const Elem = define('x-test', {
      render() {
        return svg({ width: '100px' });
      }
    });
    fixture(new Elem());
    afterMutations(
      () => (window.SVGElement = oldSVGElement),
      done
    );
  });
});

/* eslint-env jasmine, mocha, chai */

import { define, vdom } from '../../../src';
import afterMutations from '../../lib/after-mutations';
import fixture from '../../lib/fixture';

const [svg] = vdom.builder('svg');

describe('vdom/svg', () => {
  it('#825 - should not error if window.SVGElement is undefined', done => {
    const oldSVGElement = window.SVGElement;
    window.SVGElement = undefined;
    const Elem = define('x-test', {
      render () {
        return svg({ width: '100px' });
      }
    });
    fixture(new Elem());
    afterMutations(
      () => (window.SVGElement = oldSVGElement),
      done
    );
  });
});

Remove .only() and fix standards errors.


const log = require('../util/log');

/**
 * Load a sound's asset into memory asynchronously.
 * @param {!object} sound - the Scratch sound object.
 * @property {string} md5 - the MD5 and extension of the sound to be loaded.
 * @property {Buffer} data - sound data will be written here once loaded.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @returns {!Promise} - a promise which will resolve to the sound when ready.
 */
const loadSound = function (sound, runtime) {
    if (!runtime.storage) {
        log.error('No storage module present; cannot load sound asset: ', sound.md5);
        return Promise.resolve(sound);
    }
    if (!runtime.audioEngine) {
        log.error('No audio engine present; cannot load sound asset: ', sound.md5);
        return Promise.resolve(sound);
    }
    const idParts = sound.md5.split('.');
    const md5 = idParts[0];
    return runtime.storage.load(runtime.storage.AssetType.Sound, md5).then(soundAsset => {
        sound.data = soundAsset.data;
        return runtime.audioEngine.decodeSound(sound).then(() => sound);
    });
};

module.exports = loadSound;

const log = require('../util/log');

/**
 * Load a sound's asset into memory asynchronously.
 * @param {!object} sound - the Scratch sound object.
 * @property {string} md5 - the MD5 and extension of the sound to be loaded.
 * @property {Buffer} data - sound data will be written here once loaded.
 * @param {!Runtime} runtime - Scratch runtime, used to access the storage module.
 * @returns {!Promise} - a promise which will resolve to the sound when ready.
 */
const loadSound = function (sound, runtime) {
    if (!runtime.storage) {
        log.error('No storage module present; cannot load sound asset: ', sound.md5);
        return Promise.resolve(sound);
    }
    if (!runtime.audioEngine) {
        log.error('No audio engine present; cannot load sound asset: ', sound.md5);
        return Promise.resolve(sound);
    }
    const idParts = sound.md5.split('.');
    const md5 = idParts[0];
    return runtime.storage.load(runtime.storage.AssetType.Sound, md5)
        .then(soundAsset => {
            sound.assetId = soundAsset.assetId;
            sound.assetType = runtime.storage.AssetType.Sound;
            return runtime.audioEngine.decodeSound(Object.assign(
                {},
                sound,
                {data: soundAsset.data}
            ));
        })
        .then(() => sound);
};

module.exports = loadSound;

Use asset id reference on sounds


module.exports = {
  //apiUrl: 'https://fast-dawn-4805.herokuapp.com'
  apiUrl: 'http://localhost:4000'
};

module.exports = {
  apiUrl: 'https://fast-dawn-4805.herokuapp.com'
  //apiUrl: 'http://localhost:4000'
};

Change api url back to fast dawn


/* PlayerController test */

describe('PlayersController', function () {
  describe('#view', function() {
    it('should respond ok with valid player id', function(done) {
      request(sails.hooks.http.app)
        .get('/player/1')
        .expect(200)
        .end(done);
    });

    it("should 400 if player doesn't exist", function(done) {
      request(sails.hooks.http.app)
        .get('/player/1000000')
        .expect(404)
        .end(done);
    });
  });
});

/* PlayerController test */

describe('PlayersController', function () {
  describe('#view', function() {
    it('should respond ok with valid player id', function(done) {
      request(sails.hooks.http.app)
        .get('/player/1')
        .expect(200)
        .end(done);
    });

    it("should 404 if player doesn't exist", function(done) {
      request(sails.hooks.http.app)
        .get('/player/1000000')
        .expect(404)
        .end(done);
    });
  });
});

Fix test name: 400 -> 404


app.controller("ItemsController", function($scope, $state, $window, $timeout, $modal, allItems, UserService, ItemService) {

    if(!UserService.isLoggedIn()) {
        $state.go("frontpage");
    }

    $scope.items = [];
    $scope.limit = 12;

    updateView(allItems);

    $scope.$on("items:change", function(event, data) {
        updateView(ItemService.allItems);
    });

    function updateView(items) {
        $window.scrollTo(0,0)
        $timeout(function() {
            $scope.items = items.slice().reverse();
        },1);
    }

    $scope.addItems = function(files) {
        var items = ItemService.createItems(files);
        ItemService.saveItems(items);
    }

    $scope.editItem = function(item) {
        var modalInstance = $modal.open({
            templateUrl: "modules/templates/edititem.html",
            controller: "EditItemModalController",
            size: "lg",
            resolve: {
                item: function() { return item; }
            }
        });
    }

    $scope.showMore = function(event) {
        event.preventDefault();
        $scope.limit += 12;
    }

});

app.controller("ItemsController", function($scope, $state, $window, $timeout, $modal, allItems, UserService, ItemService) {

    if(!UserService.isLoggedIn()) {
        $state.go("frontpage");
    }

    $scope.items = [];
    $scope.limit = 12;

    updateView(allItems);

    $scope.$on("items:change", function(event, data) {
        updateView(ItemService.allItems);
    });

    function updateView(items) {
        $window.scrollTo(0,0)
        $timeout(function() {
            $scope.items = items.slice().sort(function(a, b) {
                return b.created.getTime() - a.created.getTime();
            });
        },1);
    }

    $scope.addItems = function(files) {
        var items = ItemService.createItems(files);
        ItemService.saveItems(items);
    }

    $scope.editItem = function(item) {
        var modalInstance = $modal.open({
            templateUrl: "modules/templates/edititem.html",
            controller: "EditItemModalController",
            size: "lg",
            resolve: {
                item: function() { return item; }
            }
        });
    }

    $scope.showMore = function(event) {
        event.preventDefault();
        $scope.limit += 12;
    }

});

Sort mybox items by created date.


const getCaseProgress = require('../services/get-case-progress')
const getSubNav = require('../services/get-sub-nav')

module.exports = function (router) {
  router.get('/:organisationLevel/:id/case-progress', function (req, res, next) {
    var id = req.params.id
    var organisationLevel = req.params.organisationLevel

    var caseProgressPromise = getCaseProgress(id, organisationLevel)

    return caseProgressPromise.then(function (result) {
      return res.render('case-progress', {
        title: result.title,
        subTitle: result.subTitle,
        breadcrumbs: result.breadcrumbs,
        subNav: getSubNav(id, organisationLevel, req.path),
        caseProgress: result.caseProgress
      })
    })
  })
}

const getCaseProgress = require('../services/get-case-progress')
const getSubNav = require('../services/get-sub-nav')
const organisationUnit = require('../constants/organisation-unit')

module.exports = function (router) {
  router.get('/:organisationLevel/:id/case-progress', function (req, res, next) {
    var organisationLevel = req.params.organisationLevel
    var id

    if (organisationLevel !== organisationUnit.NATIONAL.name) {
      id = req.params.id
    }

    var caseProgressPromise = getCaseProgress(id, organisationLevel)

    return caseProgressPromise.then(function (result) {
      return res.render('case-progress', {
        title: result.title,
        subTitle: result.subTitle,
        breadcrumbs: result.breadcrumbs,
        subNav: getSubNav(id, organisationLevel, req.path),
        caseProgress: result.caseProgress
      })
    })
  })
}

Add national id logic to case progress routes


import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Thumbnail, CardItem } from 'native-base';
import CardImageHeaderStyle from './cardImageHeaderStyle';
import GlobalStyle from '../../common/globalStyle';

// Card header with image and icon.
export default class CardImageHeader extends Component {
  static propTypes = {
    cover: React.PropTypes.string.isRequired,
    icon: React.PropTypes.string,
    toNextScreen: React.PropTypes.func,
  };

  static defaultProps = {
    icon: undefined,
    toNextScreen: () => alert('hej!'),
  };

  render() {
    // Only show icon if it is provided as a prop
    let iconIfProvided = [];
    if (this.props.icon !== undefined) {
      iconIfProvided = (
        <Thumbnail source={{ uri: this.props.icon }} />
      );
    }

    return (
      <CardItem
        style={StyleSheet.flatten(GlobalStyle.noPadding)}
        onPress={this.props.toNextScreen}
      >
        <Thumbnail
          square resizeMode="cover" style={StyleSheet.flatten(CardImageHeaderStyle.coverPhoto)}
          source={{ uri: this.props.cover }}
        >
          {iconIfProvided}
        </Thumbnail>
      </CardItem>
    );
  }
}

import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { Thumbnail, CardItem } from 'native-base';
import CardImageHeaderStyle from './cardImageHeaderStyle';
import GlobalStyle from '../../common/globalStyle';
import { imageProp } from '../../common/propTypes';

// Card header with image and icon.
export default class CardImageHeader extends Component {
  static propTypes = {
    cover: imageProp.isRequired,
    icon: imageProp.isRequired,
    toNextScreen: React.PropTypes.func,
  };

  static defaultProps = {
    icon: undefined,
    toNextScreen: () => alert('hej!'),
  };

  render() {
    // Only show icon if it is provided as a prop
    let iconIfProvided = [];
    if (this.props.icon !== undefined) {
      iconIfProvided = (
        <Thumbnail source={this.props.icon} />
      );
    }

    return (
      <CardItem
        style={StyleSheet.flatten(GlobalStyle.noPadding)}
        onPress={this.props.toNextScreen}
      >
        <Thumbnail
          square resizeMode="cover" style={StyleSheet.flatten(CardImageHeaderStyle.coverPhoto)}
          source={this.props.cover}
        >
          {iconIfProvided}
        </Thumbnail>
      </CardItem>
    );
  }
}

Make CardImageHeader use imageProp from propTypes


Tinytest.add('Validators - Order', function(test) {
  Astro.classes = [];

  ValidatorItem = Astro.Class({
    name: 'ValidatorItem',
    fields: [
      'first',
      'second',
      'third'
    ],
    validators: {
      'first': Validators.string(),
      'second': Validators.string(),
      'third': Validators.string()
    },
    validationOrder: [
      'third',
      'second',
      'first'
    ]
  });

  var validatorItem = new ValidatorItem();
  validatorItem.validate();
  var errors = validatorItem.getValidationErrors();

  test.isTrue(_.has(errors, 'third'),
    'The "third" validator should be run first');

  validatorItem.validateAll();
  var keys = _.keys(validatorItem.getValidationErrors());
  test.equal(keys, ['third', 'second', 'first'],
    'Validators should be run in the following order ' +
    '"third", "second", "first"'
  );
});

Tinytest.add('Validators - Order', function(test) {
  Astro.classes = [];

  ValidatorItem = Astro.Class({
    name: 'ValidatorItem',
    fields: [
      'first',
      'second',
      'third'
    ],
    validators: {
      'first': Validators.string(),
      'second': Validators.string(),
      'third': Validators.string()
    },
    validationOrder: [
      'third',
      'second',
      'first'
    ]
  });

  var validatorItem = new ValidatorItem();
  validatorItem.validate();
  var errors = validatorItem.getValidationErrors();

  test.isTrue(_.has(errors, 'third'),
    'The "third" validator should be run first');

  validatorItem.validate(false);
  var keys = _.keys(validatorItem.getValidationErrors());
  test.equal(keys, ['third', 'second', 'first'],
    'Validators should be run in the following order ' +
    '"third", "second", "first"'
  );
});

Replace validateAll with validate function


"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = require("core/application-storage");

/**
 * Insert an update into list
 * @param type
 * @param region
 * @param realm
 * @param name
 * @param priority
 * @param callback
 */
module.exports.insert = function (type, region, realm, name, priority, callback) {
    var redis = applicationStorage.redis;

    //Create object to insert
    var value = JSON.stringify({region: region, realm: realm, name: name, priority: priority});

    //Create or update auctionUpdate
    redis.zadd(type, priority + '' + new Date().getTime(), value, function (error) {
        callback(error);
    });
};

/**
 * Return the number of updates in list
 * @param type
 * @param callback
 */
module.exports.getCount = function (type, callback) {
    var redis = applicationStorage.redis;
    redis.zcount(type, "-inf", "+inf", function (error, value) {
        callback(error, value);
    });
};

"use strict";

//Load dependencies
var async = require("async");
var applicationStorage = require("core/application-storage");

/**
 * Insert an update into list
 * @param type
 * @param region
 * @param realm
 * @param name
 * @param priority
 * @param callback
 */
module.exports.insert = function (type, region, realm, name, priority, callback) {
    var redis = applicationStorage.redis;

    //Concat priority with timestamp
    priority = priority + '' + new Date().getTime();

    //Create object to insert
    var value = JSON.stringify({region: region, realm: realm, name: name, priority: priority});

    //Create or update auctionUpdate
    redis.zadd(type, priority, value, function (error) {
        callback(error);
    });
};

/**
 * Return the number of updates in list
 * @param type
 * @param callback
 */
module.exports.getCount = function (type, callback) {
    var redis = applicationStorage.redis;
    redis.zcount(type, "-inf", "+inf", function (error, value) {
        callback(error, value);
    });
};

Fix update model priority on api call


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

var ObjectId = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var IndustrySectorSchema   = new Schema({
	name: String,
	_owner_id: ObjectId,
	_deleted: { type: Boolean, default: false, index: true },
}, {
	timestamps: true
});

IndustrySectorSchema.index({name: 1, type: 1}, {unique: true});

IndustrySectorSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "cr"
});

module.exports = mongoose.model('IndustrySector', IndustrySectorSchema);

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

var ObjectId = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var IndustrySectorSchema   = new Schema({
	name: { type: String, unique: true },
	_owner_id: ObjectId,
	_deleted: { type: Boolean, default: false, index: true },
}, {
	timestamps: true
});

IndustrySectorSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "cr"
});

module.exports = mongoose.model('IndustrySector', IndustrySectorSchema);

Move index up to single line


import React from 'react';
import { IndexLink } from 'react-router';
import './Header.scss';

export const Header = () => (

      <IndexLink to="/" className="navbar-brand">
        Athenen ilmomasiina
      </IndexLink>

);

export default Header;

Remove wrong class name from header


import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import StyleSheet from './StyleSheet';

// allow component styles to be editable in React Dev Tools
if (process.env.NODE_ENV !== 'production') {
  if (canUseDOM && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
    window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = StyleSheet.flatten;
  }
}

export default StyleSheet;

import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
import StyleSheet from './StyleSheet';

// allow original component styles to be inspected in React Dev Tools
if (canUseDOM && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
  window.__REACT_DEVTOOLS_GLOBAL_HOOK__.resolveRNStyle = StyleSheet.flatten;
}

export default StyleSheet;

Support style inspection in production


// gulpfile.js

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var karma = require('gulp-karma');

var testFiles;
require('./.karma.js')({set: function (config) { testFiles = config['files']; }});

var exec = require('child_process').exec;

/**
 * Lint source code and specs
 */
gulp.task('lint', function () {

    return gulp.src(['./straw-ios.js', './straw-ios-spec.js'])

        .pipe(jshint())

        .pipe(jshint.reporter('default'));

});

/**
 * Run test using karma and output code coverage
 */
gulp.task('test', function () {

    return gulp.src(testFiles).pipe(karma({

        configFile: '.karma.js',
        action: 'start'

    })).on('error', function (err) {

        throw err;

    });

});

gulp.task('doc', function (cb) {
    exec('jsduck', function (err, stdout, stderr) {
        console.log(stdout);
        console.log(stderr);
        cb(err);
    });
});

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

// gulpfile.js

var gulp = require('gulp');
var jshint = require('gulp-jshint');
var karma = require('gulp-karma');

var testFiles;
require('./.karma.js')({set: function (config) { testFiles = config['files']; }});

var exec = require('child_process').exec;

/**
 * Lint source code and specs
 */
gulp.task('lint', function () {

    return gulp.src(['./straw-ios.js', './straw-ios-spec.js'])

        .pipe(jshint())

        .pipe(jshint.reporter('default'));

});

/**
 * Run test using karma and output code coverage
 */
gulp.task('test', ['lint'], function () {

    return gulp.src(testFiles).pipe(karma({

        configFile: '.karma.js',
        action: 'start'

    })).on('error', function (err) {

        throw err;

    });

});

gulp.task('doc', function (cb) {
    exec('jsduck', function (err, stdout, stderr) {
        console.log(stdout);
        console.log(stderr);
        cb(err);
    });
});

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

Make test task depend on lint task


'use strict';

const gulp        = require('gulp');
const browserSync = require('browser-sync');
const reload      = browserSync.reload;

gulp.task('sass:dev', require('./tasks/sass-dev'));
gulp.task('jade:dev', require('./tasks/jade-dev'));

gulp.task('serve', ['sass:dev', 'jade:dev'], function __serve__() {
  browserSync.init({
    browser: 'google chrome',
    server: {
      baseDir: ['.tmp']
    }
  });

  gulp.watch(['library/**/*.scss'], ['sass:dev'])
  gulp.watch(['src/**/*.jade'], ['jade:dev', reload]);
});

'use strict';

const gulp        = require('gulp');
const browserSync = require('browser-sync');
const reload      = browserSync.reload;

gulp.task('sass:dev', require('./tasks/sass-dev'));
gulp.task('jade:dev', require('./tasks/jade-dev'));

gulp.task('serve', ['sass:dev', 'jade:dev'], function __serve__() {
  browserSync.init({
    browser: 'google chrome',
    server: {
      baseDir: ['.tmp', 'src']
    }
  });

  gulp.watch(['library/**/*.scss'], ['sass:dev'])
  gulp.watch(['src/**/*.jade'], ['jade:dev', reload]);
});

Add src as a base directory for browser sync.


var gulp = require('gulp');
var apigen = require('gulp-apigen');
var phpunit = require('gulp-phpunit');
var spawn = require('child_process').spawn;
var jasmine = require('gulp-jasmine');
var cover = require('gulp-coverage');

gulp.task('apigen', function() {
  gulp.src('apigen.neon').pipe(apigen('./vendor/bin/apigen'));
});

gulp.task('phpunit', function() {
  gulp.src('phpunit.xml').pipe(phpunit('./vendor/bin/phpunit'));
});

gulp.task('phpcs', function () {
  spawn('vendor/bin/phpcs', [], {stdio: 'inherit'});
});

gulp.task('php', ['phpcs','apigen','phpunit'], function () {
});

gulp.task('jasmine', function() {
    gulp.src('test/js/*Spec.js')
        .pipe(cover.instrument({
            pattern: ['src/webroot/js/*.js']//,
//            debugDirectory: 'debug'
        }))
        .pipe(jasmine())
        .pipe(cover.gather())
        .pipe(cover.format())
        .pipe(gulp.dest('test/js/cover'));;
});

gulp.task('default', function() {
  // place code for your default task here
});

var gulp = require('gulp');
var apigen = require('gulp-apigen');
var phpunit = require('gulp-phpunit');
var spawn = require('child_process').spawn;
var jasmine = require('gulp-jasmine');
var cover = require('gulp-coverage');

gulp.task('apigen', function() {
  gulp.src('apigen.neon').pipe(apigen('./vendor/bin/apigen'));
});

gulp.task('phpunit', function() {
  gulp.src('phpunit.xml').pipe(phpunit('./vendor/bin/phpunit'));
});

gulp.task('phpcs', function () {
  spawn('vendor/bin/phpcs', [], {stdio: 'inherit'});
});

gulp.task('php', ['phpcs','apigen','phpunit'], function () {
});

gulp.task('jasmine', function() {
    gulp.src(['test/js/*Spec.js'])
        .pipe(cover.instrument({
            pattern: ['src/webroot/js/*.js']
        }))
        .pipe(jasmine({'config': {'spec_dir': './', 'helpers': ['src/webroot/js/organismDetails.js']}}))
        .pipe(cover.gather())
        .pipe(cover.format())
        .pipe(gulp.dest('test/js/cover'));;
});

gulp.task('default', function() {
  // place code for your default task here
});

Load src file as helper for jasmine


var docco, gulp, jslint, nodeunit;

docco = require('gulp-docco');
gulp = require('gulp');
jslint = require('gulp-jslint');
nodeunit = require('gulp-nodeunit');

gulp.task('docs', function () {
  'use strict';
  return gulp
    .src('./leslie.js')
    .pipe(docco())
    .pipe(gulp.dest('./docs/'));
});

gulp.task('test', function () {
  'use strict';
  return gulp
    .src('./tests/*.js')
    .pipe(nodeunit());
});

gulp.task('lint', function () {
  'use strict';
  return gulp
    .src(['./leslie.js', './gulpfile.js'])
    .pipe(jslint({ indent: 2, node: true }));
});

gulp.task('watch', function () {
  'use strict';
  gulp.watch('./leslie.js', [ 'test', 'lint' ]);
  gulp.watch('./gulpfile.js', [ 'lint' ]);
});

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

var docco, gulp, jslint, nodeunit;

docco = require('gulp-docco');
gulp = require('gulp');
jslint = require('gulp-jslint');
nodeunit = require('gulp-nodeunit');

gulp.task('docs', function () {
  'use strict';
  return gulp
    .src('./leslie.js')
    .pipe(docco())
    .pipe(gulp.dest('./docs/'));
});

gulp.task('test', function () {
  'use strict';
  return gulp
    .src('./tests/*.js')
    .pipe(nodeunit());
});

gulp.task('lint', function () {
  'use strict';
  return gulp
    .src(['./leslie.js', './gulpfile.js'])
    .pipe(jslint({ indent: 2, node: true }));
});

gulp.task('watch', function () {
  'use strict';
  gulp.watch('./leslie.js', [ 'test', 'lint' ]);
  gulp.watch('./gulpfile.js', [ 'lint' ]);
});

gulp.task('dev', [ 'test', 'lint', 'watch' ]);
gulp.task('ci', [ 'test', 'lint' ]);

Add ci target for travis.


import UTILS from './utils';
import HELPERS from './helpers';

const eventAttributeName = 'jtml-event';

export default class Render {
	constructor(func) {
		this.func = func;
		this.html = '';
	}

	render(data, events) {
		this.html = this.func(data, UTILS, HELPERS);
		this.fragment = UTILS.fragmentFromString(this.html);

		Array.from(this.fragment.querySelectorAll(`[${eventAttributeName}]`))
			.forEach(el => {

				if (events) {
					el.getAttribute('jtml-event').replace(/\[(.*?)]\((.*?)\)/g, (...args) => {
						let eventType = args[1];
						let handlers = args[2].trim().split(/\s+/);

						handlers.forEach(handlers => {
							el.addEventListener(eventType, events[handlers]);
						});
					});
				}

				el.removeAttribute(eventAttributeName);
			});

		return this;
	}

	appendTo(selectorOrNode) {
		if (UTILS.isDOM(selectorOrNode)) {
			selectorOrNode.appendChild(this.fragment);
		}
		else {
			let element = document.querySelector(selectorOrNode);
			if (element) {
				element.appendChild(this.fragment);
			}
		}

		return this;
	}
}

import UTILS from './utils';
import HELPERS from './helpers';

const eventAttributeName = 'jtml-event';

export default class Render {
	constructor(func) {
		this.func = func;
		this.html = '';
	}

	render(data, events) {
		this.html = this.func(data, UTILS, HELPERS);
		this.fragment = UTILS.fragmentFromString(this.html);

		Array.from(this.fragment.querySelectorAll(`[${eventAttributeName}]`))
			.forEach(el => {

				if (events) {
					el.getAttribute('jtml-event').replace(/@(.*?)\((.*?)\)/g, (...args) => {
						let eventType = args[1];
						let handlers = args[2].trim().split(/\s+/);

						handlers.forEach(handlers => {
							el.addEventListener(eventType, events[handlers]);
						});
					});
				}

				el.removeAttribute(eventAttributeName);
			});

		return this;
	}

	appendTo(selectorOrNode) {
		if (UTILS.isDOM(selectorOrNode)) {
			selectorOrNode.appendChild(this.fragment);
		}
		else {
			let element = document.querySelector(selectorOrNode);
			if (element) {
				element.appendChild(this.fragment);
			}
		}

		return this;
	}
}

Use a decorator style syntax in the event attribute


// fetch api
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
// https://blog.hospodarets.com/fetch_in_action

// async/await
// https://ponyfoo.com/articles/understanding-javascript-async-await

const venigi = (() => {
    let get = async function (source) {
        return await fetch(source)
            .then(response => response.text())
            .catch(err => console.error(err.message));
    }

    let getJson = async function (source) {
        return await fetch(source)
            .then(response => response.json())
            .catch(err => console.error(err.message));
    }

	return {
        get: get,
        getJson: getJson
  };
})();

// fetch api
// https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
// https://blog.hospodarets.com/fetch_in_action

// async/await
// https://ponyfoo.com/articles/understanding-javascript-async-await

// module pattern
// http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

const venigi = (() => {
    let get = async function (source) {
        return await fetch(source)
            .then(response => response.text())
            .catch(err => console.error(err.message));
    }

    let getJson = async function (source) {
        return await fetch(source)
            .then(response => response.json())
            .catch(err => console.error(err.message));
    }

	return {
        get: get,
        getJson: getJson
  };
})();

Add link to module pattern doc


'use strict';

/**
 * @ngdoc filter
 * @name dockstore.ui.filter:PreviewFilter
 * @function
 * @description
 * # PreviewFilter
 * Filter in the dockstore.ui.
 */
angular.module('dockstore.ui')
  .filter('PreviewFilter', [function () {
    return function (containers, contLimit) {
      if (!contLimit) return containers;
      var sortedByBuildTime = containers.sort(function(a, b) {
        return a.lastBuild - b.lastBuild;
      });
      return sortedByBuildTime.slice(0, contLimit - 1);
    };
  }]);

'use strict';

/**
 * @ngdoc filter
 * @name dockstore.ui.filter:PreviewFilter
 * @function
 * @description
 * # PreviewFilter
 * Filter in the dockstore.ui.
 */
angular.module('dockstore.ui')
  .filter('PreviewFilter', [function () {
    return function (containers, contLimit) {
      if (!contLimit) return containers;
      var sortedByBuildTime = containers.sort(function(a, b) {
      	if (!a) a = Number.MAX_VALUE;
      	if (!b) b = Number.MAX_VALUE;
        return a.lastBuild - b.lastBuild;
      });
      return sortedByBuildTime.slice(0, contLimit - 1);
    };
  }]);

Update PreviewFilter for invalid/non-returned timestamps.


/* global btoa: true */
/*!
 * Bootstrap Grunt task for generating raw-files.min.js for the Customizer
 * http://getbootstrap.com
 * Copyright 2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
'use strict';
var fs = require('fs');
var btoa = require('btoa');
var grunt = require('grunt');

function getFiles(type) {
  var files = {};
  fs.readdirSync(type)
    .filter(function (path) {
      return type === 'fonts' ? true : new RegExp('\\.' + type + '$').test(path);
    })
    .forEach(function (path) {
      var fullPath = type + '/' + path;
      files[path] = (type === 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8'));
    });
  return 'var __' + type + ' = ' + JSON.stringify(files) + '\n';
}

module.exports = function generateRawFilesJs(banner) {
  if (!banner) {
    banner = '';
  }
  var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts');
  var rawFilesJs = 'docs/assets/js/raw-files.min.js';
  try {
    fs.writeFileSync(rawFilesJs, files);
  }
  catch (err) {
    grunt.fail.warn(err);
  }
  grunt.log.writeln('File ' + rawFilesJs.cyan + ' created.');
};

/*!
 * Bootstrap Grunt task for generating raw-files.min.js for the Customizer
 * http://getbootstrap.com
 * Copyright 2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

/* global btoa: true */

'use strict';
var fs = require('fs');
var btoa = require('btoa');
var grunt = require('grunt');

function getFiles(type) {
  var files = {};
  fs.readdirSync(type)
    .filter(function (path) {
      return type === 'fonts' ? true : new RegExp('\\.' + type + '$').test(path);
    })
    .forEach(function (path) {
      var fullPath = type + '/' + path;
      files[path] = (type === 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8'));
    });
  return 'var __' + type + ' = ' + JSON.stringify(files) + '\n';
}

module.exports = function generateRawFilesJs(banner) {
  if (!banner) {
    banner = '';
  }
  var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts');
  var rawFilesJs = 'docs/assets/js/raw-files.min.js';
  try {
    fs.writeFileSync(rawFilesJs, files);
  }
  catch (err) {
    grunt.fail.warn(err);
  }
  grunt.log.writeln('File ' + rawFilesJs.cyan + ' created.');
};

Move license to the top of the file.


// LinkedIn:
$('title').remove();
$('#name-container').hide();
$('.profile-picture').hide();

// Logged out:
$('h1#name').hide();
$('.reg-upsell').hide();

// These should appear only if you're already connected, but just in case:
$('.endorse-v2').hide();
$('.write-endorsement').hide();

// LinkedIn:
$('title').remove();
$('#name-container').hide();
$('.profile-picture').hide();

// Logged out:
$('h1#name').hide();
$('.reg-upsell').hide();
$('.name-search').hide();

// These should appear only if you're already connected, but just in case:
$('.endorse-v2').hide();
$('.write-endorsement').hide();

Hide 'Find a different [NAME]'


export const OFFICIAL_SERVER_URL = 'https://music.bemuse.ninja/live'

export async function load(serverUrl, { fetch = global.fetch } = {}) {
  const indexUrl = getServerIndexFileUrl(serverUrl)
  const data = await fetch(indexUrl).then((response) => response.json())

  if (Array.isArray(data.songs)) {
    return data
  } else if (Array.isArray(data.charts)) {
    // Single-song server
    const dir = indexUrl.replace(/[^/]*$/, '')
    return { songs: [{ ...data, id: 'song', path: dir }] }
  } else {
    throw new Error(
      `Invalid server file at ${indexUrl}: Does not contain "songs" array.`
    )
  }
}

export function getServerIndexFileUrl(serverUrl) {
  if (serverUrl.endsWith('/bemuse-song.json')) {
    return serverUrl
  }
  return serverUrl.replace(/\/(?:index\.json)?$/, '') + '/index.json'
}

export const OFFICIAL_SERVER_URL = 'https://music4.bemuse.ninja/server'

export async function load(serverUrl, { fetch = global.fetch } = {}) {
  const indexUrl = getServerIndexFileUrl(serverUrl)
  const data = await fetch(indexUrl).then((response) => response.json())

  if (Array.isArray(data.songs)) {
    return data
  } else if (Array.isArray(data.charts)) {
    // Single-song server
    const dir = indexUrl.replace(/[^/]*$/, '')
    return { songs: [{ ...data, id: 'song', path: dir }] }
  } else {
    throw new Error(
      `Invalid server file at ${indexUrl}: Does not contain "songs" array.`
    )
  }
}

export function getServerIndexFileUrl(serverUrl) {
  if (serverUrl.endsWith('/bemuse-song.json')) {
    return serverUrl
  }
  return serverUrl.replace(/\/(?:index\.json)?$/, '') + '/index.json'
}

Switch to new music server


'use strict';

var h = require('virtual-hyperscript');
var VDOM = {
  diff: require('virtual-dom/diff'),
  patch: require('virtual-dom/patch')
};
var DOMDelegator = require('dom-delegator');

function renderEvery(vtree$, containerSelector) {
  // Find and prepare the container
  var container = document.querySelector(containerSelector);
  if (container === null) {
    throw new Error('Couldn\'t render into unknown \'' + containerSelector + '\'');
  }
  container.innerHTML = '';
  // Make the DOM node bound to the VDOM node
  var rootNode = document.createElement('div');
  container.appendChild(rootNode);
  return vtree$.startWith(h())
    .bufferWithCount(2, 1)
    .subscribe(function (buffer) {
      try {
        var oldVTree = buffer[0];
        var newVTree = buffer[1];
        rootNode = VDOM.patch(rootNode, VDOM.diff(oldVTree, newVTree));
      } catch (err) {
        console.error(err);
      }
    });
}

var delegator = new DOMDelegator();

module.exports = {
  renderEvery: renderEvery,
  delegator: delegator
};

'use strict';

var h = require('virtual-hyperscript');
var VDOM = {
  diff: require('virtual-dom/diff'),
  patch: require('virtual-dom/patch')
};
var DOMDelegator = require('dom-delegator');

function renderEvery(vtree$, container) {
  // Find and prepare the container
  var container = typeof container === 'string' ? document.querySelector(container) : container;
  if (container === null) {
    throw new Error('Couldn\'t render into unknown \'' + container + '\'');
  }
  container.innerHTML = '';
  // Make the DOM node bound to the VDOM node
  var rootNode = document.createElement('div');
  container.appendChild(rootNode);
  return vtree$.startWith(h())
    .bufferWithCount(2, 1)
    .subscribe(function (buffer) {
      try {
        var oldVTree = buffer[0];
        var newVTree = buffer[1];
        rootNode = VDOM.patch(rootNode, VDOM.diff(oldVTree, newVTree));
      } catch (err) {
        console.error(err);
      }
    });
}

var delegator = new DOMDelegator();

module.exports = {
  renderEvery: renderEvery,
  delegator: delegator
};

Allow renderEvery to be passed a DOM node


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

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

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

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

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

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

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

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

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

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

Fix the cleaning of the message once it is sent.


$(window).ready(function(){
	$("#config_button").unbind().click(function(){
		if($("#config_button").data('switch_flag')=='open') {
			$("#config_container").animate({height:"0px"},500);
			$("body").animate({height:"0px"},500);
			$("#config_button").data('switch_flag','close');
		}else{
			$("#config_container").animate({height:"100px"},500);
			$("#config_button").data('switch_flag','open');
		}
	});
	$("#config_decimal_places").change(function(){
		TMSGCCW.data("decimalPlaces", parseInt(config_decimal_places.value));TMSGCCW.saveSettings();TMSGCCW.startConvert();
	});
	$("#config_decimal_complemented_with_zero").change(function(){
		TMSGCCW.data("decimalComplementedWithZero", config_decimal_complemented_with_zero.checked);TMSGCCW.saveSettings();TMSGCCW.startConvert();
	});
	$("#config_font_family").change(function(){
		TMSGCCW.data("fontFamily", config_font_family.value);TMSGCCW.saveSettings();
		$("body").css("font-family",TMSGCCW.data("fontFamily"));
	});
});

$(window).ready(function(){
	$("#config_button").unbind().click(function(){
		if($("#config_button").data('switch_flag')=='open') {
			$("#config_container").animate({height:"0px"},500);
			$("body").animate({height:"134px"},500);
			$("#config_button").data('switch_flag','close');
		}else{
			$("#config_container").animate({height:"100px"},500);
			$("body").animate({height:"234px"},500);
			$("#config_button").data('switch_flag','open');
		}
	});
	$("#config_decimal_places").change(function(){
		TMSGCCW.data("decimalPlaces", parseInt(config_decimal_places.value));TMSGCCW.saveSettings();TMSGCCW.startConvert();
	});
	$("#config_decimal_complemented_with_zero").change(function(){
		TMSGCCW.data("decimalComplementedWithZero", config_decimal_complemented_with_zero.checked);TMSGCCW.saveSettings();TMSGCCW.startConvert();
	});
	$("#config_font_family").change(function(){
		TMSGCCW.data("fontFamily", config_font_family.value);TMSGCCW.saveSettings();
		$("body").css("font-family",TMSGCCW.data("fontFamily"));
	});
});

Fix bug when animate body get wrong height.


// Mailin List - Entry point

const Person = require('./person.js');
const Group = require('./group.js');
const MailList = require('./maillist.js');

function test01() {
  const g1 = new Group('list-developers');
  g1.add(new Person('Katzuro Akata', 'katzuro@stringcraft.org'));
  g1.add(new Person('Makimoro Tateke', 'maki.tate@pebblestone.net'));
  g1.add(new Person('Bessimo Taichi', 'bessimo@smallspace.com'));

  const sender = new Person('Agata Selfborn', 'agata@selfborn.net');

  const ml = new MailList();
  ml.send(sender, g1, 'Hello guys! This is a test message. Greets');
  ml.report();

  const ml2 = new MailList();
  ml2.send(sender, new Person('Katzuro Akata', 'katzuro@stringcraft.org'),
    'Hey Katzuro! How\'s it going? Cheeres!');
  ml2.report();

}

test01();

// eof

// Mailin List - Entry point

const Person = require('./person.js');
const Group = require('./group.js');
const MailList = require('./maillist.js');

const people = new Map();
people.set('akata', new Person('Katzuro Akata', 'katzuro@stringcraft.org'));
people.set('tateke', new Person('Makimoro Tateke', 'maki.tate@pebblestone.net'));
people.set('taichi', new Person('Bessimo Taichi', 'bessimo@smallspace.com'));
people.set('agata', new Person('Agata Selfborn', 'agata@selfborn.net'));

function test01() {
  const g1 = new Group('list-developers');
  g1.add(people.get('akata'));
  g1.add(people.get('tateke'));
  g1.add(people.get('taichi'));

  const sender = people.get('agata');

  const ml = new MailList();
  ml.send(sender, g1, 'Hello guys! This is a test message. Greets');
  ml.report();

  const ml2 = new MailList();
  ml2.send(sender, people.get('akata'), 'Hey Katzuro! How\'s it going? Cheeres!');
  ml2.report();
}

test01();

// eof

Use a map of persons instead of new ops every time


var Views = {};
Views.ListingView = Backbone.View.extend({
	initialise: function() {
		this.listenTo(this.collection, "add", this.render);
		this.listenTo(this.collection, "change", this.render);
		this.listenTo(this.collection, "remove", this.render);
		this.childViews = [];
	},

	render: function() {
		this.childViews = [];

		var fragment = document.createDocumentFragment();

		var currentChildView;
		var that = this;
		this.collection.each(function(currentModel) {
			currentChildView = new Views.ItemView({
				model: currentModel
			});
			that.childViews.push(currentChildView);
			fragment.appendChild(currentChildView.render().el);
		});

		this.$el.html(fragment);
		return this;
	}
});

Views.ItemView = Backbone.View.extend({
	template: Templates.ItemListingTemplate,
	initialise: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});

var Views = {};
Views.ListingView = Backbone.View.extend({
	initialise: function() {
		this.listenTo(this.collection, 'add', this.render);
		this.listenTo(this.collection, 'change', this.render);
		this.listenTo(this.collection, 'remove', this.render);
		this.childViews = [];
	},

	render: function() {
		this.childViews = [];

		var fragment = document.createDocumentFragment();

		var currentChildView;
		var that = this;
		this.collection.each(function(currentModel) {
			currentChildView = new Views.ItemView({
				model: currentModel
			});
			that.childViews.push(currentChildView);
			fragment.appendChild(currentChildView.render().el);
		});

		this.$el.html(fragment);
		return this;
	}
});

Views.ItemView = Backbone.View.extend({
	template: Templates.ItemListingTemplate,
	initialise: function() {
		this.listenTo(this.model, "change", this.render);
		this.id = "item-" + this.model.attributes.id;
	},

	render: function() {
		this.$el.html(this.template(this.model.attributes));
		return this;
	}
});

Use single-quotes for event handlers.


function(doc) {
    if (doc.type === "SonositeUpload") {
        emit([doc.domain, doc.case_id], doc._id);
    }
}

function(doc) {
    if (doc.type === "SonositeUpload" || doc.type === "VscanUpload") {
        emit([doc.domain, doc.type, doc.case_id], doc._id);
    }
}

Add vscan uploads to the couch view


/**
 * Created by MrIggyman1234 on 19/12/2016.
 */

$(document).ready(function(){
    var $nav = $("nav");
    var $body = $("body");
    $body.on("click", "#compare-link", function(e){
        e.preventDefault();
        $nav.fadeOut(200);
        $nav.html("Back" +
            "Bootstrap" +
            "Foundation");
        $nav.fadeIn(400);
    });

    $body.on("click", "#back-link", function(e){
        e.preventDefault();
        $nav.fadeOut(200);
        $nav.html('About' +
                              'Contribute' +
                              'How we compare with:' +
                              'Contact Us');
        $nav.fadeIn(400);
    });
});

/**
 * Created by MrIggyman1234 on 19/12/2016.
 */

$(document).ready(function(){
    var $nav = $("nav");
    var $body = $("body");
    $body.on("click", "#compare-link", function(e){
        e.preventDefault();
        $nav.html("Back" +
            "Bootstrap" +
            "Foundation");
    });

    $body.on("click", "#back-link", function(e){
        e.preventDefault();
        $nav.html('About' +
                              'Contribute' +
                              'How we compare with:' +
                              'Contact Us');
    });
});

Remove fade in and fade out


'use strict';

var webpack = require("webpack");
var config = require('./webpack.base.config.js');

if (process.env['NODE_ENV'] !== 'test') {
  config.entry = [
    'webpack-dev-server/client?http://localhost:3000',
    'webpack/hot/dev-server',
    config.entry
  ];
}

config.devtool = 'eval-source-map';

config.plugins = config.plugins.concat([
  new webpack.HotModuleReplacementPlugin()
]);

config.module.loaders = config.module.loaders.concat([
  {test: /\.jsx?$/, loaders: [ 'react-hot', 'babel'], exclude: /node_modules/}
]);

module.exports = config;

'use strict';

var webpack = require("webpack");
var config = require('./webpack.base.config.js');

if (process.env['NODE_ENV'] !== 'test') {
  config.entry = [
    'webpack-dev-server/client?http://localhost:3000',
    'webpack/hot/dev-server',
    config.entry
  ];
}

config.devtool = 'eval-source-map';

config.plugins = config.plugins.concat([
  new webpack.HotModuleReplacementPlugin()
]);

config.module.loaders = config.module.loaders.concat([
  {test: /\.jsx?$/, loaders: [ 'react-hot', 'babel?optional=runtime'], exclude: /node_modules/}
]);

module.exports = config;

Use `runtime` in babel to avoid duplication across the compiled output


/**
 * Various HTTP helper functions and defaults.
 */

'use strict';

/**
 * Module dependencies.
 */

var http = require('http');

/**
 * Default charset.
 */

var CHARSET = 'utf-8';

/**
 * Reply to options request
 */

function options(req, res, methods) {
  res.setHeader('Allow', methods.join(' '));
}

/**
 * Reply to request
 */

function reply(req, res) {
  return function(code, data) {
    if (data instanceof Error) {
      if (http.STATUS_CODES[data.code]) {
        code = data.code;
      }
      data = { message: data.message };
    }

    res.statusCode = code;

    if (!data && data !== null) {
      data = { message: http.STATUS_CODES[code] || 'unknown error' };
    }

    data = data ? JSON.stringify(data, null, 4) + '\n' : '';

    res.setHeader('Content-Length', Buffer.byteLength(data, CHARSET));

    if (data) {
      res.setHeader('Content-Type', 'application/json; charset=' + CHARSET);

      if (req.method !== 'HEAD') {
        return res.end(data);
      }
    }

    res.end();
  };
}

/**
 * Expose http
 */

exports.CHARSET = CHARSET;
exports.STATUS_CODES = http.STATUS_CODES;
exports.options = options;
exports.reply = reply;

/**
 * Various HTTP helper functions and defaults.
 */

'use strict';

/**
 * Module dependencies.
 */

var http = require('http');

/**
 * Default charset.
 */

var CHARSET = 'utf-8';

/**
 * Reply to options request
 */

function options(req, res, methods) {
  res.setHeader('Allow', methods.join(' '));
}

/**
 * Reply to request
 */

function reply(req, res) {
  return function(statusCode, data) {
    if (data instanceof Error) {
      if (http.STATUS_CODES[data.statusCode]) {
        statusCode = data.statusCode;
      }
      data = { message: data.message };
    }

    res.statusCode = statusCode;

    if (!data && data !== null) {
      data = { message: http.STATUS_CODES[statusCode] || 'unknown error' };
    }

    data = data ? JSON.stringify(data, null, 4) + '\n' : '';

    res.setHeader('Content-Length', Buffer.byteLength(data, CHARSET));

    if (data) {
      res.setHeader('Content-Type', 'application/json; charset=' + CHARSET);

      if (req.method !== 'HEAD') {
        return res.end(data);
      }
    }

    res.end();
  };
}

/**
 * Expose http
 */

exports.CHARSET = CHARSET;
exports.STATUS_CODES = http.STATUS_CODES;
exports.options = options;
exports.reply = reply;

Use statusCode instead of code


/* eslint-env mocha */
const FenwickTree = require('../../src').DataStructures.FenwickTree;
const assert = require('assert');

describe('Fenwick Tree', () => {
  it('should be empty when initialized', () => {
    const inst = new FenwickTree([]);
    assert(inst.isEmpty());
    assert.equal(inst.size, 0);
  });
});

/* eslint-env mocha */
const FenwickTree = require('../../src').DataStructures.FenwickTree;
const assert = require('assert');

describe('Fenwick Tree', () => {
  it('should be empty when initialized', () => {
    const inst = new FenwickTree([]);
    assert(inst.isEmpty());
    assert.equal(inst.size, 0);
  });

  it('should build tree with array', () => {
    const inst = new FenwickTree(4);

    inst.buildTree([1, 2, 3, 4]);
    assert(!inst.isEmpty());
    assert.equal(inst.size, 4);
  });

});

Test Fenwick Tree: Builds the tree


// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    "widgets/js/widget",
    "widgets/js/widget_int",
], function(widget, int_widgets){
    var IntSliderView = int_widgets.IntSliderView;
    var IntTextView = int_widgets.IntTextView;

    var FloatSliderView = IntSliderView.extend({
        _validate_slide_value: function(x) {
            // Validate the value of the slider before sending it to the back-end
            // and applying it to the other views on the page.
            return x;
        },
    });

    var FloatTextView = IntTextView.extend({
        _parse_value: function(value) {
            // Parse the value stored in a string.
            return  parseFloat(value);
        },
    });

    return {
        'FloatSliderView': FloatSliderView,
        'FloatTextView': FloatTextView,
    };
});

// Copyright (c) IPython Development Team.
// Distributed under the terms of the Modified BSD License.

define([
    "widgets/js/widget",
    "widgets/js/widget_int",
], function(widget, int_widgets){
    var IntSliderView = int_widgets.IntSliderView;
    var IntTextView = int_widgets.IntTextView;

    var FloatSliderView = IntSliderView.extend({
        _validate_text_input: function(x) {
            return parseFloat(x);
        },

        _validate_slide_value: function(x) {
            // Validate the value of the slider before sending it to the back-end
            // and applying it to the other views on the page.
            return x;
        },
    });

    var FloatTextView = IntTextView.extend({
        _parse_value: function(value) {
            // Parse the value stored in a string.
            return  parseFloat(value);
        },
    });

    return {
        'FloatSliderView': FloatSliderView,
        'FloatTextView': FloatTextView,
    };
});

Add support to the float slider


const Jasmine = require('jasmine');
const { jsdom } = require('jsdom');
const SpecReporter = require('jasmine-spec-reporter');

const jasmine = new Jasmine();

global.window = jsdom('<!doctype html>', {
    url: 'http://localhost'
}).defaultView;

jasmine.loadConfig({
    spec_dir: 'test/spec',
    spec_files: [
        '**/*_spec.js'
    ]
});

jasmine.addReporter(new SpecReporter());

jasmine.execute();

const Jasmine = require('jasmine');
const { jsdom } = require('jsdom');
const { SpecReporter } = require('jasmine-spec-reporter');

const jasmine = new Jasmine();

global.window = jsdom('<!doctype html>', {
    url: 'http://localhost'
}).defaultView;

jasmine.loadConfig({
    spec_dir: 'test/spec',
    spec_files: [
        '**/*_spec.js'
    ]
});

jasmine.addReporter(new SpecReporter());

jasmine.execute();

Update way how SpecReporter is imported


const { JSDOM } = require('jsdom');

const jsdom = new JSDOM('<!DOCTYPE html>');
const { window } = jsdom;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
        .filter(prop => typeof target[prop] === 'undefined')
        .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
global.navigator = {
    userAgent: 'node.js',
};
copyProps(window, global);

const { JSDOM } = require('jsdom');

const jsdom = new JSDOM('<!DOCTYPE html>');
const { window } = jsdom;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
        .filter(prop => typeof target[prop] === 'undefined')
        .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
global.HTMLElement = window.HTMLElement;
global.navigator = {
    userAgent: 'node.js',
};
copyProps(window, global);

Fix test errors caused by upgrade in Chai dependency


// Copyright 2014, Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var options = {
	"taskId": null,
	"type": null,
	"name": null,
	"title": null,

	"configuration": {},
	"decorators": [],

	"active": true,
	"suite": false,
	"debug": false,
	"verbose": false,
	"report": true,

	"failOnError": false,
	"echoStdOut": false,
	"echoStdErr": false
};

module.exports = options;

// Copyright 2014, Yahoo! Inc.
// Copyrights licensed under the Mit License. See the accompanying LICENSE file for terms.

var options = {
	"taskId": null,
	"type": null,
	"name": null,
	"title": null,

	"configuration": {},
	"decorators": [],

	"active": true,
	"suite": false,
	"debug": false,
	"verbose": false,
	"report": true,

	"failOnError": false,
	"echoStdOut": false,
	"echoStdErr": true
};

module.exports = options;

Change standard behavior for tasks, printing out all errors directly


var _ = require('lodash');
var dust = require('dustjs-linkedin');

module.exports = function(config) {
	return function(req, res, next) {
		if(req.params) {
			res.template = req.params[0];
		}
		next();
	};
};

var _ = require('lodash');
var dust = require('dustjs-linkedin');

module.exports = function(config) {
	return function(req, res, next) {
		if(req.params) {
			res.data.template = req.params[0];
		}
		next();
	};
};

Set res.locals.template instead of res.template.


'use strict';

describe('charm slider', function() {
  var container, Y;

  before(function(done) {
    Y = YUI(GlobalConfig).use(
        ['browser-charm-slider'], function(Y) {
          done();
        });
  });

  beforeEach(function() {
    container = Y.Node.create('

');
    Y.one(document.body).prepend(charm_container);
  });

  afterEach(function() {
    Y.one('#container').remove(true);
  });

  it('should initialize', function() {
    var slider = new Y.juju.widgets.browser.CharmSlider();
    assert.isObject(slider);
  });
});

'use strict';

describe('charm slider', function() {
  var container, Y;

  before(function(done) {
    Y = YUI(GlobalConfig).use(
        ['browser-charm-slider', 'node'], function(Y) {
          done();
        });
  });

  beforeEach(function() {
    container = Y.Node.create('

');
    Y.one(document.body).prepend(container);
  });

  afterEach(function() {
    Y.one('#container').remove(true);
  });

  it('should initialize', function() {
    var slider = new Y.juju.widgets.browser.CharmSlider();
    assert.isObject(slider);
  });
});

Test fails for the right reasons.


"use strict";

var limit = (process.argv.length == 3) ? parseInt(process.argv[2]) : 100;

for(var i = 1; i < limit; i++) {
 if (i % 3 == 0) {
    console.log ("Fizz");
  } else if (i % 5 == 0) {
    console.log ("Buzz");
  } else if (i % 3 == 0 && i % 5 == 0) {
    console.log ("FizzBuzz");
  } else {
    console.log (i);
  }
}

"use strict";

var limit = (process.argv.length == 3) ? parseInt(process.argv[2]) : 100;

for(var i = 1; i < limit; i++) {
  if (i % 3 == 0 && i % 5 == 0) {
    console.log ("FizzBuzz");
  } else if (i % 3 == 0) {
    console.log ("Fizz");
  } else if (i % 5 == 0) {
    console.log ("Buzz");
  } else {
    console.log (i);
  }
}

Test for divisibility of 3 and 5 first so that "FizzBuzz" is actually printed


const Signal = require('signals')

let MaterialID = 0

function Material (opts) {
  this.type = 'Material'
  this.id = 'Material_' + MaterialID++
  this.changed = new Signal()

  this._uniforms = {}

  const ctx = opts.ctx

  this.baseColor = [0.95, 0.95, 0.95, 1]
  this.emissiveColor = [0, 0, 0, 1]
  this.metallic = 0.01
  this.roughness = 0.5
  this.displacement = 0
  this.depthTest = true
  this.depthWrite = true
  this.depthFunc = opts.ctx.DepthFunc.LessEqual
  this.blendEnabled = false
  this.blendSrcRGBFactor = ctx.BlendFactor.ONE
  this.blendSrcAlphaFactor = ctx.BlendFactor.ONE
  this.blendDstRGBFactor = ctx.BlendFactor.ONE
  this.blendDstAlphaFactor = ctx.BlendFactor.ONE
  this.castShadows = false
  this.receiveShadows = false
  this.cullFaceEnabled = true

  this.set(opts)
}

Material.prototype.init = function (entity) {
  this.entity = entity
}

Material.prototype.set = function (opts) {
  Object.assign(this, opts)
  Object.keys(opts).forEach((prop) => this.changed.dispatch(prop))
}

module.exports = function (opts) {
  return new Material(opts)
}

const Signal = require('signals')

let MaterialID = 0

function Material (opts) {
  this.type = 'Material'
  this.id = 'Material_' + MaterialID++
  this.changed = new Signal()

  this._uniforms = {}

  const ctx = opts.ctx

  this.baseColor = [0.95, 0.95, 0.95, 1]
  this.baseColorMap = null
  this.emissiveColor = [0, 0, 0, 1]
  this.emissiveColorMap = null
  this.metallic = 0.01
  this.matallicMap = null
  this.roughness = 0.5
  this.roughnessMap = null
  this.displacement = 0
  this.depthTest = true
  this.depthWrite = true
  this.depthFunc = opts.ctx.DepthFunc.LessEqual
  this.blendEnabled = false
  this.blendSrcRGBFactor = ctx.BlendFactor.ONE
  this.blendSrcAlphaFactor = ctx.BlendFactor.ONE
  this.blendDstRGBFactor = ctx.BlendFactor.ONE
  this.blendDstAlphaFactor = ctx.BlendFactor.ONE
  this.castShadows = false
  this.receiveShadows = false
  this.cullFaceEnabled = true

  this.set(opts)
}

Material.prototype.init = function (entity) {
  this.entity = entity
}

Material.prototype.set = function (opts) {
  Object.assign(this, opts)
  Object.keys(opts).forEach((prop) => this.changed.dispatch(prop))
}

module.exports = function (opts) {
  return new Material(opts)
}

Initialize texture maps with null