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

module.exports = {
  name: 'ember-fullcalendar',

  included: function(app) {

    app.import(app.bowerDirectory + '/fullcalendar/dist/fullcalendar.js');
    app.import(app.bowerDirectory + '/fullcalendar/dist/fullcalendar.css');
    app.import(app.bowerDirectory + '/fullcalendar-scheduler/dist/scheduler.js');
    app.import(app.bowerDirectory + '/fullcalendar-scheduler/dist/scheduler.css');
  }
};

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

module.exports = {
  name: 'ember-fullcalendar',

  included: function(app) {

    app.import(app.bowerDirectory + '/fullcalendar/dist/fullcalendar.js');
    app.import(app.bowerDirectory + '/fullcalendar/dist/fullcalendar.css');

    // Add scheduler to executable unless configured not to.
    if (!app.options ||
        !app.options.emberFullCalendar ||
        app.options.emberFullCalendar.scheduler === undefined || app.options.emberFullCalendar.scheduler) {
      app.import(app.bowerDirectory + '/fullcalendar-scheduler/dist/scheduler.js');
      app.import(app.bowerDirectory + '/fullcalendar-scheduler/dist/scheduler.css');
    }
  }
};

Allow opting-out of FullCalendar Scheduler.


'use strict';

var cheerio = require('cheerio');
var got = require('got');

/**
 * w3counter API
 *
 * @param {String} type
 * @param {Function} cb
 * @api public
 */

module.exports = function (type, cb) {
    var types = {
        browser: 'Web Browsers',
        country: 'Countries',
        os: 'Operating Systems',
        res: 'Screen Resolutions'
    };
    var method = types[type];
    var ret = [];

    got('http://www.w3counter.com/globalstats.php', function (err, data) {
        if (err) {
            return cb(err);
        }

        var $ = cheerio.load(data);

        $('th').filter(function () {
            return this.text() === method;
        }).parent().nextAll('.item').each(function () {
            ret.push({ item: this.text(), percent: $(this).next('.pct').text() });
        });

        if (ret.length === 0) {
            return cb('Couldn\'t get any ' + method.toLowerCase());
        }

        cb(null, ret);
    });
};

'use strict';

var cheerio = require('cheerio');
var got = require('got');

/**
 * w3counter API
 *
 * @param {String} type
 * @param {Function} cb
 * @api public
 */

module.exports = function (type, cb) {
    var types = {
        browser: 'Web Browsers',
        country: 'Countries',
        os: 'Operating Systems',
        res: 'Screen Resolutions'
    };
    var method = types[type];
    var ret = [];

    got('http://www.w3counter.com/globalstats.php', function (err, data) {
        if (err) {
            return cb(err);
        }

        var $ = cheerio.load(data);

        $('th').filter(function () {
            return this.text() === method;
        }).parent().nextAll('.item').each(function () {
            ret.push({ item: this.text(), percent: $(this).next('.pct').text() });
        });

        if (ret.length === 0) {
            return cb(new Error('Couldn\'t get any ' + method.toLowerCase()));
        }

        cb(null, ret);
    });
};

Return error if no items could be fetched


'use strict';

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

if (!argv.hasOwnProperty('input')) {
    console.log('Usage: node index.js --input <path to line delimited GeoJSON FeatureCollections>');
} else {
    mergeStream(argv.input, argv.output);
}

function mergeStream(inputFile, outputFile) {
    if (!outputFile) {
        outputFile = argv.input.split('.')[0] + '-merged.json';
    }
    var inputStream = fs.createReadStream(inputFile, {encoding: 'utf8'}).pipe(split());

    var start = '{\'type\': \'FeatureCollection\', \'features\': [';

    fs.appendFileSync(outputFile, start, {encoding: 'utf8'});
    var comma = '';
    var line = 0;
    inputStream.on('data', function (chunk) {
        line = line + 1;
        process.stderr.cursorTo(0);
        process.stderr.write('Processing line: ' + String(line));
        if (chunk) {
            var features = JSON.parse(chunk).features;
            features.forEach(function (feature) {
                fs.appendFileSync(outputFile, comma + JSON.stringify(feature), {encoding: 'utf8'});
                if (!comma) {
                    comma = ',';
                }
            });
        }
    });

    inputStream.on('end', function () {
        var end = ']}';
        fs.appendFileSync(outputFile, end, {encoding: 'utf8'});
        console.log('\ndone');
    });
}

module.exports = {'mergeStream': mergeStream};

'use strict';

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

if (!argv.hasOwnProperty('input')) {
    console.log('Usage: node index.js --input <path to line delimited GeoJSON FeatureCollections>');
} else {
    mergeStream(argv.input, argv.output);
}

function mergeStream(inputFile, outputFile) {
    if (!outputFile) {
        outputFile = argv.input.split('.')[0] + '-merged.json';
    }
    var inputStream = fs.createReadStream(inputFile, {encoding: 'utf8'}).pipe(split());

    var start = '{\'type\': \'FeatureCollection\', \'features\': [';

    fs.appendFileSync(outputFile, start, {encoding: 'utf8'});
    var comma = '';
    var line = 0;
    inputStream.on('data', function (chunk) {
        line = line + 1;
        process.stderr.cursorTo(0);
        process.stderr.write('Processing line: ' + String(line));
        if (chunk) {
            var features = JSON.parse(chunk).features;
            features.forEach(function (feature) {
                fs.appendFileSync(outputFile, comma + JSON.stringify(feature), {encoding: 'utf8'});
                if (!comma) {
                    comma = ',';
                }
            });
        }
    });

    inputStream.on('end', function () {
        var end = ']}';
        fs.appendFileSync(outputFile, end, {encoding: 'utf8'});
        console.log('\nMerged features in %s', outputFile);
    });
}

module.exports = {'mergeStream': mergeStream};

Add output file path to final log


'use strict';

var swig = require('swig');

exports.name = 'swig';
exports.outputFormat = 'xml';
exports.render = function (str, options) {
  var template = swig.compile(str);
  return template(options);
};

'use strict';

var swig = require('swig');

exports.name = 'swig';
exports.outputFormat = 'html';
exports.render = function (str, options) {
  var template = swig.compile(str);
  return template(options);
};

Use `'html'` as output format


angular.module('codebrag.commits.comments')

    .directive('commentable', function($compile, events) {
        var template = $('#inlineCommentForm').html();
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                var alreadyOpened = false;
                var codeLine = $('a.comment', element);
                codeLine.bind('click', function() {
                    if(alreadyOpened) {
                        _locateCommentFormRow().show();
                        return;
                    }
                    element.append(template);
                    $compile($('tr.comment-form', element).contents())(scope);
                    alreadyOpened = true;
                    scope.$digest();
                });

                scope.$on(events.closeForm, function(event) {
                    event.stopPropagation();
                    _locateCommentFormRow().hide();
                });

                function _locateCommentFormRow() {
                    return element.find('tr.comment-form');
                }
            }
        }
    });

angular.module('codebrag.commits.comments')

    .directive('commentable', function($compile, events) {
        var template = $('#inlineCommentForm').html();
        return {
            restrict: 'A',
            link: function(scope, element) {
                var alreadyOpened = false;

                var onclick = function() {
                    if(alreadyOpened) {
                        _locateCommentFormRow().show();
                        return;
                    }
                    element.append(template);
                    $compile($('tr.comment-form', element).contents())(scope);
                    alreadyOpened = true;
                    scope.$digest();
                };

                var codeLine = $('td.diff-line-code', element);
                var commentBox = $('a.comment', element);
                codeLine.bind('click', onclick);
                commentBox.bind('click', onclick);

                scope.$on(events.closeForm, function(event) {
                    event.stopPropagation();
                    _locateCommentFormRow().hide();
                });

                function _locateCommentFormRow() {
                    return element.find('tr.comment-form');
                }
            }
        }
    });

Add possibility to open comment form by clicking anywhere in the diff line


'use strict()';

var config= {
    port: 3000
};

module.exports = function(grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    var options = {
        config: {
            src: './grunt/*.js'
        },
        pkg: grunt.file.readJSON('package.json')
    };

    var configs = require('load-grunt-configs')(grunt, options);

    // Project configuration.
    grunt.initConfig(configs);

    // load jshint
    grunt.registerTask('lint', [
        'jshint'
    ]);

    grunt.registerTask('dev', [
        'compass:dev',
        'postcss',
        'copy:modernizr',
        'copy:jqueryDev',
        'copy:revolutionSliderStyle',
        'copy:revolutionSliderAssets',
        'copy:allDev',
        'uglify:revolutionSlider'
    ]);

    grunt.registerTask('prod', [
        'compass:prod',
        'postcss',
        'copy:jqueryProd',
        'copy:revolutionSliderStyle',
        'copy:revolutionSliderAssets',
        'uglify:revolutionSlider',
        'uglify:prod'
    ]);

    // default option to connect server
    grunt.registerTask('serve', [
        'jshint',
        'concurrent:dev'
    ]);

    grunt.registerTask('server', function () {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve:' + target]);
    });
};

'use strict()';

var config= {
    port: 3000
};

module.exports = function(grunt) {

    // Load grunt tasks automatically
    require('load-grunt-tasks')(grunt);

    // Time how long tasks take. Can help when optimizing build times
    require('time-grunt')(grunt);

    var options = {
        config: {
            src: './grunt/*.js'
        },
        pkg: grunt.file.readJSON('package.json')
    };

    var configs = require('load-grunt-configs')(grunt, options);

    // Project configuration.
    grunt.initConfig(configs);

    // load jshint
    grunt.registerTask('lint', [
        'jshint'
    ]);

    grunt.registerTask('devcss', [
        'compass:dev',
        'postcss'
    ]);

    grunt.registerTask('devfull', [
        'compass:dev',
        'postcss',
        'copy:modernizr',
        'copy:jqueryDev',
        'copy:revolutionSliderStyle',
        'copy:revolutionSliderAssets',
        'copy:allDev',
        'uglify:revolutionSlider'
    ]);

    grunt.registerTask('prod', [
        'compass:prod',
        'postcss',
        'copy:jqueryProd',
        'copy:revolutionSliderStyle',
        'copy:revolutionSliderAssets',
        'uglify:revolutionSlider',
        'uglify:prod'
    ]);

    // default option to connect server
    grunt.registerTask('serve', [
        'jshint',
        'concurrent:dev'
    ]);

    grunt.registerTask('server', function () {
        grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
        grunt.task.run(['serve:' + target]);
    });
};

Add a grunt dev task for css only, without js


module.exports = function(grunt) {
  grunt.initConfig({
    less: {
      production: {
        options: {
          compress: true,
          yuicompress: true,
          cleancss: true,
          optimization: 2
        },
        files: {
          "saleor/static/css/style.css": "saleor/static/less/style.less"
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-less');

  grunt.registerTask('default', ['less']);
};

Add newline at the end of file


'use strict'

const paths = require('../../config/paths.json')

const gulp = require('gulp')
const runSequence = require('run-sequence')
const rename = require('gulp-rename')
const flatten = require('gulp-flatten')

const sass = require('gulp-sass')
const nano = require('gulp-cssnano')

// Compile Sass to CSS
gulp.task('build:styles', cb => {
  runSequence('lint:styles', 'build:styles:copy', 'build:styles:compile', cb)
})

gulp.task('build:styles:copy', cb => {
  gulp.src(paths.assetsScss + '**/*.scss').pipe(gulp.dest(paths.bundleScss))
  gulp.src(paths.srcComponents + '**/*.scss')
    .pipe(flatten())
    .pipe(gulp.dest(paths.bundleScss + 'components'))
  return cb()
})

gulp.task('build:styles:compile', () => {
  return gulp.src(paths.bundleScss + '**/*.scss')
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(gulp.dest(paths.bundleCss))
    .pipe(gulp.dest(paths.publicCss))
    .pipe(rename({ suffix: '.min' }))
    .pipe(nano())
    .pipe(gulp.dest(paths.bundleCss))
})

'use strict'

const paths = require('../../config/paths.json')

const gulp = require('gulp')
const runSequence = require('run-sequence')
const rename = require('gulp-rename')
const flatten = require('gulp-flatten')

const sass = require('gulp-sass')
const nano = require('gulp-cssnano')

// Compile Sass to CSS
gulp.task('build:styles', cb => {
  runSequence('lint:styles', 'build:styles:copy', 'build:styles:compile', cb)
})

gulp.task('build:styles:copy', cb => {
  runSequence('build:styles:copy:scss', 'build:styles:copy:components', cb)
})

gulp.task('build:styles:copy:scss', () => {
  return gulp.src(paths.assetsScss + '**/*.scss')
    .pipe(gulp.dest(paths.bundleScss))
})

gulp.task('build:styles:copy:components', () => {
  return gulp.src(paths.srcComponents + '**/*.scss')
    .pipe(flatten())
    .pipe(gulp.dest(paths.bundleScss + 'components'))
})

gulp.task('build:styles:compile', () => {
  return gulp.src(paths.bundleScss + '**/*.scss')
    .pipe(sass.sync().on('error', sass.logError))
    .pipe(gulp.dest(paths.bundleCss))
    .pipe(gulp.dest(paths.publicCss))
    .pipe(rename({ suffix: '.min' }))
    .pipe(nano())
    .pipe(gulp.dest(paths.bundleCss))
})

Split copy tasks to fix the failing test


// Hungarian

jQuery.extend( jQuery.fn.pickadate.defaults, {
    monthsFull: [ 'január', 'február', 'március', 'aprilis', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december' ],
    monthsShort: [ 'jan', 'febr', 'márc', 'apr', 'máj', 'jún', 'júl', 'aug', 'szept', 'okt', 'nov', 'dec' ],
    weekdaysFull: [ 'vasámap', 'hétfö', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat' ],
    weekdaysShort: [ 'V', 'H', 'K', 'SZ', 'CS', 'P', 'SZ' ],
    today: 'ma',
    clear: 'töröl',
    firstDay: 1,
    format: 'yyyy. mmmm dd.',
    formatSubmit: 'yyyy/mm/dd'
});

// Hungarian

jQuery.extend( jQuery.fn.pickadate.defaults, {
    monthsFull: [ 'január', 'február', 'március', 'április', 'május', 'június', 'július', 'augusztus', 'szeptember', 'október', 'november', 'december' ],
    monthsShort: [ 'jan', 'febr', 'márc', 'ápr', 'máj', 'jún', 'júl', 'aug', 'szept', 'okt', 'nov', 'dec' ],
    weekdaysFull: [ 'vasárnap', 'hétfő', 'kedd', 'szerda', 'csütörtök', 'péntek', 'szombat' ],
    weekdaysShort: [ 'V', 'H', 'K', 'SZe', 'CS', 'P', 'SZo' ],
    today: 'Ma',
    clear: 'Törlés',
    firstDay: 1,
    format: 'yyyy. mmmm dd.',
    formatSubmit: 'yyyy/mm/dd'
});

Fix typos in Hungarian translation


/*jshint strict:true, browser:true, jquery:true, devel:true, curly:true, eqeqeq:true, immed:true, latedef:true, plusplus:true, undef:true, unused:true, laxbreak:true, nonew:false */
/*global module */

module.exports = function(grunt) {
	"use strict";

	grunt.initConfig({
		compass: {
			dist: {
				options: {
					httpPath: '/',
					sassDir: 'scss',
					cssDir: 'public/css',
					sourcemap: true,
					watch: true
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-compass');

	grunt.registerTask("default", []);
};

/*jshint strict:true, browser:true, jquery:true, devel:true, curly:true, eqeqeq:true, immed:true, latedef:true, plusplus:true, undef:true, unused:true, laxbreak:true, nonew:false */
/*global module */

module.exports = function(grunt) {
	"use strict";

	grunt.initConfig({
		compass: {
			dist: {
				options: {
					httpPath: '/',
					sassDir: 'scss',
					cssDir: 'public/css',
					sourcemap: true,
					watch: true
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-compass');

	grunt.registerTask("default", ["compass"]);
};

Set grunt task "compass" as the default task


module.exports = function(grunt) {

  'use strict';

  var host = grunt.option('host') || 'localhost';

  grunt.loadNpmTasks('grunt-contrib');
  grunt.loadNpmTasks('grunt-karma');

  grunt.initConfig({
    concat: {
      all: {
        files: {
          'dist/skate.js': [
            'src/skate.js'
          ]
        }
      }
    },
    connect: {
      docs: {
        options: {
          keepalive: true,
          hostname: host,
          open: 'http://' + host + ':8000/docs'
        }
      }
    },
    karma: {
      all: {
        options: {
          browsers: ['PhantomJS'],
          files: [
            'dist/skate.js',
            'tests/skate.js'
          ],
          frameworks: ['mocha', 'sinon-chai'],
          singleRun: true
        }
      }
    },
    uglify: {
      all: {
        files: {
          'dist/skate.min.js': 'dist/skate.js'
        }
      }
    },
    watch: {
      test: {
        files: ['src/*.js'],
        tasks: ['dist']
      }
    }
  });

  grunt.registerTask('build', 'Runs the tests and builds the dist.', ['test']);
  grunt.registerTask('dist', 'Builds the dist.', ['concat', 'uglify']);
  grunt.registerTask('docs', 'Runs the docs server.', ['connect:docs'])
  grunt.registerTask('test', 'Runs the tests.', ['dist', 'karma']);

};

module.exports = function(grunt) {

  'use strict';

  var host = grunt.option('host') || 'localhost';

  grunt.loadNpmTasks('grunt-contrib');
  grunt.loadNpmTasks('grunt-karma');

  grunt.initConfig({
    concat: {
      all: {
        files: {
          'dist/skate.js': [
            'src/skate.js'
          ]
        }
      }
    },
    connect: {
      docs: {
        options: {
          keepalive: true,
          hostname: host,
          open: 'http://' + host + ':8000/docs'
        }
      }
    },
    karma: {
      all: {
        options: {
          browsers: ['PhantomJS'],
          files: [
            'src/skate.js',
            'tests/skate.js'
          ],
          frameworks: ['mocha', 'sinon-chai'],
          singleRun: true
        }
      }
    },
    uglify: {
      all: {
        files: {
          'dist/skate.min.js': 'dist/skate.js'
        }
      }
    },
    watch: {
      test: {
        files: ['src/*.js'],
        tasks: ['dist']
      }
    }
  });

  grunt.registerTask('build', 'Runs the tests and builds the dist.', ['test']);
  grunt.registerTask('dist', 'Builds the dist.', ['concat', 'uglify']);
  grunt.registerTask('docs', 'Runs the docs server.', ['connect:docs'])
  grunt.registerTask('test', 'Runs the tests.', ['dist', 'karma']);

};

Update gruntfile tasks for changes to source.


import Mixin from '@ember/object/mixin';
import { get, set, computed } from '@ember/object';

export default Mixin.create({

  // Inputs from component caller
  volume:      null,
  editing:     null,
  sourceStore: null, // set to clusterStore for cluster volumes

  // From the volume plugin
  field:       null, // the name of the field on the volume

  config: computed('field', function() {
    const volume = get(this, 'volume');
    const field = get(this, 'field');

    let config = get(volume, field);

    if ( !config ) {
      config = this.configForNew();
      set(volume, field, config);
    }

    return config;
  }),

  configForNew() {
    // Override to provide a custom empty config

    const store = get(this, 'sourceStore') || get(this, 'store');
    const index = get(this, 'volume.type').lastIndexOf('/') + 1
    const voluemType = get(this, 'volume.type').substr(index);
    const volumeSchema = store.getById('schema', voluemType);
    const type = get(volumeSchema, `resourceFields.${ get(this, 'field') }.type`);

    const config = store.createRecord({ type });

    const schema = store.getById('schema', type.toLowerCase());

    if ( schema && schema.typeifyFields ) {
      if ( (schema.typeifyFields || []).indexOf('secretRef') > -1 ) {
        get(config, 'secretRef') || set(config, 'secretRef', {});
      }
    }

    return config;
  },
});

import Mixin from '@ember/object/mixin';
import { get, set, computed } from '@ember/object';

export default Mixin.create({

  // Inputs from component caller
  volume:      null,
  editing:     null,
  sourceStore: null, // set to clusterStore for cluster volumes

  // From the volume plugin
  field:       null, // the name of the field on the volume

  config: computed('field', function() {
    const volume = get(this, 'volume');
    const field = get(this, 'field');

    let config = get(volume, field);

    if ( !config ) {
      config = this.configForNew();
      set(volume, field, config);
    }

    return config;
  }),

  configForNew() {
    // Override to provide a custom empty config

    const store = get(this, 'sourceStore') || get(this, 'store');
    const index = get(this, 'volume.type').lastIndexOf('/') + 1
    const voluemType = get(this, 'volume.type').substr(index).toLowerCase();
    const volumeSchema = store.getById('schema', voluemType);
    const type = get(volumeSchema, `resourceFields.${ get(this, 'field') }.type`).toLowerCase();

    const config = store.createRecord({ type });

    const schema = store.getById('schema', type);

    if ( schema && schema.typeifyFields ) {
      if ( (schema.typeifyFields || []).indexOf('secretRef') > -1 ) {
        get(config, 'secretRef') || set(config, 'secretRef', {});
      }
    }

    return config;
  },
});

Fix the issue that volume page breaks


Package.describe({
  name: 'kadira:react-layout',
  summary: 'Layout Manager for React with SSR Support',
  version: '1.1.0',
  git: 'https://github.com/kadirahq/meteor-react-layout.git'
});

Package.onUse(function(api) {
  configure(api);
  api.export('ReactLayout');
});

Package.onTest(function(api) {
  configure(api);
  api.use('react');
  api.use('tinytest');

  api.addFiles('test/client.jsx', 'client');
  api.addFiles('test/server.jsx', 'server');
});

function configure(api) {
  api.versionsFrom('1.0');

  api.use('meteorhacks:flow-router-ssr@2.0.1', ['client', 'server'], {weak: true});
  api.addFiles('lib/react_layout.js', ['client', 'server']);
}

Package.describe({
  name: 'kadira:react-layout',
  summary: 'Layout Manager for React with SSR Support',
  version: '1.2.0',
  git: 'https://github.com/kadirahq/meteor-react-layout.git'
});

Package.onUse(function(api) {
  configure(api);
  api.export('ReactLayout');
});

Package.onTest(function(api) {
  configure(api);
  api.use('react');
  api.use('tinytest');

  api.addFiles('test/client.jsx', 'client');
  api.addFiles('test/server.jsx', 'server');
});

function configure(api) {
  api.versionsFrom('1.0');

  api.use('kadira:flow-router-ssr@3.0.0', ['client', 'server'], {weak: true});
  api.addFiles('lib/react_layout.js', ['client', 'server']);
}

Update to depend on kadira:router-ssr


Package.describe({
  name: 'kadira:react-layout',
  summary: 'Layout Manager for React with SSR Support',
  version: '1.0.0',
  git: 'https://github.com/kadirahq/meteor-react-layout.git'
});

Package.onUse(function(api) {
  configure(api);
  api.export('FlowRouter');
});

Package.onTest(function(api) {
  configure(api);
  api.use('react');
  api.use('tinytest');

  api.addFiles('test/client.jsx', 'client');
  api.addFiles('test/server.jsx', 'server');
});

function configure(api) {
  api.versionsFrom('1.0');

  api.use('meteorhacks:flow-router-ssr@2.0.1', ['client', 'server'], {weak: true});
  api.addFiles('lib/react_layout.js', ['client', 'server']);
}

Package.describe({
  name: 'kadira:react-layout',
  summary: 'Layout Manager for React with SSR Support',
  version: '1.0.0',
  git: 'https://github.com/kadirahq/meteor-react-layout.git'
});

Package.onUse(function(api) {
  configure(api);
  api.export('ReactLayout');
});

Package.onTest(function(api) {
  configure(api);
  api.use('react');
  api.use('tinytest');

  api.addFiles('test/client.jsx', 'client');
  api.addFiles('test/server.jsx', 'server');
});

function configure(api) {
  api.versionsFrom('1.0');

  api.use('meteorhacks:flow-router-ssr@2.0.1', ['client', 'server'], {weak: true});
  api.addFiles('lib/react_layout.js', ['client', 'server']);
}

Fix lame mistake to export ReactLayout


Package.describe({
  summary: 'Meteor package to wrap TopoJSON: An extension to GeoJSON that encodes topology'
});

Package.on_use(function(api, where) {
  if (api.export) {
    api.export('topojson');
  }
  api.add_files('meteor-topojson.js', 'server');
  api.add_files('topojson.js', 'client');
});

Npm.depends({
  topojson: '1.4.6'
});

Package.describe({
  summary: 'Meteor package to wrap TopoJSON: An extension to GeoJSON that encodes topology'
});

Package.on_use(function(api) {
  api.export('topojson');
  api.add_files('meteor-topojson.js', 'server');
  api.add_files('topojson.js', 'client');
});

Npm.depends({
  topojson: '1.4.6'
});

Remove unneeded parm and test


const config = require('../config');
const db = require('../db');
const aql = require('arangojs').aql;

const collection = db.collection(config.get('arangodb:collections:putBodies:name'));

// Can give string of JSON rather than object
function savePutBody(body) {
  // the _id comes back in the response to save
  return collection.save(body);
}

function getPutBody(id) {
  return collection.document(id);
}

function removePutBody(id) {
  return collection.remove(id);
}

module.exports = {
  savePutBody,
  getPutBody,
  removePutBody,
};

const config = require('../config');
const db = require('../db');
const aql = require('arangojs').aql;

const collection = db.collection(config.get('arangodb:collections:putBodies:name'));

// Give string of JSON rather than object
function savePutBody(body) {
  // the _id comes back in the response to save
  return collection.save(`{"body":${body}}`);
}

function getPutBody(id) {
  return collection.document(id).get('body');
}

function removePutBody(id) {
  return collection.remove(id);
}

module.exports = {
  savePutBody,
  getPutBody,
  removePutBody,
};

Fix arango keys in PUT bodies


window.addEventListener('load', function() {
  document.querySelectorAll("link[rel=import][href$='.svg'").forEach(function(link) {
    link.addEventListener('load', function() {
      var url = new URL(link.href);
      var svg = link.import.querySelector('svg');
      document.querySelectorAll("img[src='" + url.pathname + "']").forEach(function(img) {
        img.replaceWith(svg);
      });
    });
  });
});

window.addEventListener('load', function() {
  document.querySelectorAll("link[rel=import][href$='.svg']").forEach(function(link) {
    link.addEventListener('load', function() {
      var url = new URL(link.href);
      var svg = link.import.querySelector('svg');
      document.querySelectorAll("img[src='" + url.pathname + "']").forEach(function(img) {
        img.replaceWith(svg);
      });
    });
  });
});

Fix syntax error in selector


import * as actions from '../actions';

const proto = (state = { descriptor: null, filename: null }, action) => {
  switch (action.type) {
    case actions.PROTO.LOAD:
      return Object.assign({}, state, {
        descriptor: window.grpc.load(action.filename),
        filename: action.filename,
      });
    default:
      return state;
  }
};

export default proto;

import { Descriptor } from '../lib/domain';
import * as actions from '../actions';

const proto = (state = { descriptor: null, filename: null }, action) => {
  switch (action.type) {
    case actions.PROTO.LOAD:
      const grpcDescriptor = window.grpc.load(action.filename);
      const descriptor = new Descriptor(grpcDescriptor);
      return Object.assign({}, state, {
        descriptor,
        filename: action.filename,
      });
    default:
      return state;
  }
};

export default proto;

Use a domain.Descriptor instead of one from grpclib


angular.module("hyperContentFor", [])
  .value("HYPER_CONTENT_FOR_IDS", { })

  .directive("hyperContent", function () {
    return {
      scope: { "for": "@" },

      restrict: "E",

      transclude: true,

      controller: function ($scope, $transclude, HYPER_CONTENT_FOR_IDS) {
        HYPER_CONTENT_FOR_IDS[$scope["for"]] = $transclude();
      }
    };
  })

  .directive("hyperYield", function ($interval, HYPER_CONTENT_FOR_IDS) {
    return {
      scope: { to: "@" },

      restrict: "E",

      link: function (scope, elem) {
        interval = null;

        watchFn = function () { return HYPER_CONTENT_FOR_IDS[scope.to]; };

        scope.$watch(watchFn, function (newValue) {
          elem.empty();
          elem.append(newValue);
        });
      }
    };
  });

angular.module("hyperContentFor", [])
  .value("HYPER_CONTENT_FOR_IDS", { })

  .directive("hyperContent", function () {
    return {
      scope: { "for": "@" },

      restrict: "E",

      transclude: true,

      controller: function ($scope, $transclude, HYPER_CONTENT_FOR_IDS) {
        HYPER_CONTENT_FOR_IDS[$scope["for"]] = $transclude();
      }
    };
  })

  .directive("hyperYield", function (HYPER_CONTENT_FOR_IDS) {
    return {
      scope: { to: "@" },

      restrict: "E",

      link: function (scope, elem) {
        interval = null;

        watchFn = function () { return HYPER_CONTENT_FOR_IDS[scope.to]; };

        scope.$watch(watchFn, function (newValue) {
          elem.empty();
          elem.append(newValue);
        });
      }
    };
  });

Remove unused injected $interval service


({
  init: function() {
    debugger;
    this.urlChanged();
  },

  feedUrl: "",

  urlChanged: function() {
    chrome.storage.onChanged.addListener(function(changes, namespace) {
      for (var key in changes) {
        if (key === "current_user_url") {
          alert("!!!");
          console.log(changes[key].newValue);
          this.feedUrl = chages[key].newValue;
        }
      }
    });
  },
}).init();

({
  init: function() {
    debugger;
    this.urlChanged();
  },

  feedUrl: "",

  urlChanged: function() {
    chrome.storage.onChanged.addListener(function(changes, namespace) {
      for (var key in changes) {
        if (key === "current_user_url") {
          alert("!!!");
          console.log(changes[key].newValue);
          this.feedUrl = chages[key].newValue;
        }
      }
    });
  },

  getUserFeed: function() {
    $.ajax({
      type: "GET",
      url: this.feedUrl,
      dataType: "application/atom+xml",
      success: function (data) {
      },
      error: function (xhr, status, data) {
      },
    });
  }
}).init();

Create function to get user feed


import Multipart from 'multi-part'

export default function toForm (fields, callback) {
  let called = false
  try {
    const form = new Multipart()
    for (const key of Object.keys(fields)) {
      let value = fields[key]
      if (value === undefined) continue
      if (
        !(value instanceof global.Buffer) &&
        (typeof value === 'object' || typeof value === 'function')
      ) {
        value = JSON.stringify(value)
      }
      form.append(key, value)
    }
    const stream = form.getStream()
    const bufs = []
    stream.on('data', (buf) => bufs.push(buf))
    stream.on('end', () => {
      if (called) return
      bufs.push(new Buffer('\r\n'))
      const body = Buffer.concat(bufs)
      const boundary = form.getBoundary()
      const headers = {
        'content-type': `multipart/form-data; boundary=${boundary}`,
        'content-length': String(body.length)
      }
      called = true
      callback(null, {body, headers})
    })
    stream.on('error', (e) => {
      if (called) return
      called = true
      callback(e)
    })
  } catch (e) {
    if (called) return
    called = true
    callback(e)
  }
}

import Multipart from 'multi-part'
import {Readable} from 'stream'

export default function toForm (fields, callback) {
  let called = false
  try {
    const form = new Multipart()
    for (const key of Object.keys(fields)) {
      let value = fields[key]
      if (value === undefined) continue
      if (
        !(value instanceof Readable) &&
        !(value instanceof global.Buffer) &&
        (typeof value === 'object' || typeof value === 'function')
      ) {
        value = JSON.stringify(value)
      }
      form.append(key, value)
    }
    const stream = form.getStream()
    const bufs = []
    stream.on('data', (buf) => bufs.push(buf))
    stream.on('end', () => {
      if (called) return
      bufs.push(new Buffer('\r\n'))
      const body = Buffer.concat(bufs)
      const boundary = form.getBoundary()
      const headers = {
        'content-type': `multipart/form-data; boundary=${boundary}`,
        'content-length': String(body.length)
      }
      called = true
      callback(null, {body, headers})
    })
    stream.on('error', (e) => {
      if (called) return
      called = true
      callback(e)
    })
  } catch (e) {
    if (called) return
    called = true
    callback(e)
  }
}

Support input streams for service uploads


(function( $ ) {

module( "progressbar: methods" );

test( "destroy", function() {
	expect( 1 );
	domEqual( "#progressbar", function() {
		$( "#progressbar" ).progressbar().progressbar( "destroy" );
	});
});

test( "disable", function() {
	expect( 3 );

	var element = $( "#progressbar" ).progressbar().progressbar( "disable" );

	ok( element.progressbar( "widget" ).hasClass( "ui-state-disabled" ), "element gets ui-state-disabled" );
	ok( element.progressbar( "widget" ).attr( "aria-disabled" ), "element gets aria-disabled" );
	ok( element.progressbar( "widget" ).hasClass( "ui-progressbar-disabled" ), "element gets ui-progressbar-disabled" );
});

test( "value", function() {
	expect( 3 );

	var element = $( "<div>" ).progressbar({ value: 20 });
	equal( element.progressbar( "value" ), 20, "correct value as getter" );
	strictEqual( element.progressbar( "value", 30 ), element, "chainable as setter" );
	equal( element.progressbar( "option", "value" ), 30, "correct value after setter" );
});

test( "widget", function() {
	expect( 2 );
	var element = $( "#progressbar" ).progressbar(),
		widgetElement = element.progressbar( "widget" );
	equal( widgetElement.length, 1, "one element" );
	strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
});

}( jQuery ) );

(function( $ ) {

module( "progressbar: methods" );

test( "destroy", function() {
	expect( 1 );
	domEqual( "#progressbar", function() {
		$( "#progressbar" ).progressbar().progressbar( "destroy" );
	});
});

test( "disable", function( assert ) {
	expect( 3 );

	var element = $( "#progressbar" ).progressbar().progressbar( "disable" );

	assert.hasClasses( element.progressbar( "widget" ), "ui-state-disabled" );
	ok( element.progressbar( "widget" ).attr( "aria-disabled" ), "element gets aria-disabled" );
	assert.hasClasses( element.progressbar( "widget" ), "ui-progressbar-disabled" );
});

test( "value", function() {
	expect( 3 );

	var element = $( "<div>" ).progressbar({ value: 20 });
	equal( element.progressbar( "value" ), 20, "correct value as getter" );
	strictEqual( element.progressbar( "value", 30 ), element, "chainable as setter" );
	equal( element.progressbar( "option", "value" ), 30, "correct value after setter" );
});

test( "widget", function() {
	expect( 2 );
	var element = $( "#progressbar" ).progressbar(),
		widgetElement = element.progressbar( "widget" );
	equal( widgetElement.length, 1, "one element" );
	strictEqual( widgetElement[ 0 ], element[ 0 ], "same element" );
});

}( jQuery ) );

Use new has/lacksClasses assertions for all class checks


export default class {
  constructor (controller, bot) {
    this.controller = controller
    this.bot = bot
  }

  conductUserSurvey = async (personEmail, survey, recordAnswer, recordCompletion) => {
    const roomForSurvey = await this.controller.api.rooms.create({
      title: survey.data.title
    })

    await this.controller.api.memberships.create({
      roomId: roomForSurvey.id,
      personEmail
    })

    this.controller.trigger('survey_started', [this.bot, {
      roomForSurvey,
      personEmail,
      survey,
      recordAnswer,
      recordCompletion,
    }])
  }
}

export default class {
  constructor (controller, bot) {
    this.controller = controller
    this.bot = bot
  }

  async conductUserSurvey (personEmail, survey, recordAnswer, recordCompletion) {
    const roomForSurvey = await this.controller.api.rooms.create({
      title: survey.data.title
    })

    await this.controller.api.memberships.create({
      roomId: roomForSurvey.id,
      personEmail
    })

    this.controller.trigger('survey_started', [this.bot, {
      roomForSurvey,
      personEmail,
      survey,
      recordAnswer,
      recordCompletion: () => {
        recordCompletion()
        setTimeout(() => this.controller.api.rooms.remove(roomForSurvey), 10000)
      },
    }])
  }
}

Remove survey room after finishing, but wait 10secs


var app = require('server'),
    fs = require('fs');

/**
 * Bootstrap the application - ensure that directories
 * exist, etc
 */
function bootstrap() {
    try {
        fs.statSync(app.set('settings')('mapfile_dir'));
    } catch (Exception) {
        console.log('Creating mapfile dir %s', app.set('settings')('mapfile_dir'));
        fs.mkdirSync(app.set('settings')('mapfile_dir'), 777);
    }

    try {
        fs.statSync(app.set('settings')('data_dir'));
    } catch (Exception) {
        console.log('Creating mapfile dir %s', app.set('settings')('data_dir'));
        fs.mkdirSync(app.set('settings')('data_dir'), 777);
    }
}

module.exports = bootstrap;

var app = require('server'),
    fs = require('fs');

/**
 * Bootstrap the application - ensure that directories
 * exist, etc
 */
function bootstrap() {
    try {
        fs.statSync(app.set('settings')('mapfile_dir'));
    } catch (Exception) {
        console.log('Creating mapfile dir %s', app.set('settings')('mapfile_dir'));
        fs.mkdirSync(app.set('settings')('mapfile_dir'), 0777);
    }

    try {
        fs.statSync(app.set('settings')('data_dir'));
    } catch (Exception) {
        console.log('Creating mapfile dir %s', app.set('settings')('data_dir'));
        fs.mkdirSync(app.set('settings')('data_dir'), 0777);
    }
}

module.exports = bootstrap;

Set proper file perms for newly created directories.


'use strict';

var dashboardApp = angular.module('dashboardApp', [
    'dashboardControllers'
  ]
);
/*
.config(['$routeProvider',
  function($routeProvider) {
      console.log("app config");
      $routeProvider.
          when('/statman', {
              controller: 'DashboardCtrl',
              template
          }).
          otherwise({
              redirectTo: '/statman'
          });
  }]
);
*/

Remove commented out code block


#!/usr/bin/env node
"use strict"
let FSWatcher = require('../lib/watcher')
let Minimist = require('minimist')
let Options = Minimist(process.argv.slice(2))
let FS = require('fs')
try {
  Options.Blacklist = String(Options.Blacklist || '').split(',').map(function(e) { return e.trim() }).filter(function(e) { return e && e !== 'true' })
  if(!Options['_'].length) throw new Error("Please specify a file/directory to watch")
  let Watcher = new FSWatcher(Options['_'][0], Options.Ignored)
  Watcher.on('error', Main.constructor.defaultError)
} catch(err){
  console.error(err)
}

#!/usr/bin/env node
"use strict"
const FSWatcher = require('../lib/watcher')
const Main = require('../lib/main')
const Minimist = require('minimist')
const Options = Minimist(process.argv.slice(2))
const FS = require('fs')

try {
  Options.Blacklist = String(Options.Blacklist || '').split(',').map(function(e) { return e.trim() }).filter(function(e) { return e && e !== 'true' })
  if(!Options['_'].length) throw new Error("Please specify a file/directory to watch")
  let Watcher = new FSWatcher(Options['_'][0], Options.Ignored)
  Watcher.on('error', Main.constructor.defaultError)
} catch(err){
  console.error(err)
}

Fix a reference in watch


//= require "./ChangeListener"
//= require "./Base"
//= require "./Instance"
//= require "./definitions"

//= require ./ChangeListener
//= require ./Base
//= require ./Router
//= require ./Instance
//= require ./definitions

Add router and remove quotes


import React from 'react';
// Components used
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import { NavLink } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';

// Wrapper for links on the navbar to make them work with react router
const NavItemLink = (props) => {
  return (
    <LinkContainer {...props}>
      <NavItem>{props.children}</NavItem>
    </LinkContainer>
  );
}

const DashNav = () => {
  return (
    <Navbar collapseOnSelect fixedTop>
      <Navbar.Header>
        <Navbar.Brand>
          <NavLink exact to="/dashboard">
            TruckTrack
          </NavLink>
        </Navbar.Brand>
        <Navbar.Toggle />
      </Navbar.Header>
      <Navbar.Collapse>

          <NavItemLink exact to="/">Track Package</NavItemLink>
          <NavItemLink to="/dashboard/routes">Routes</NavItemLink>
          <NavItemLink to="/dashboard/trucks">Trucks</NavItemLink>
          <NavItemLink to="/dashboard/drivers">Drivers</NavItemLink>

      </Navbar.Collapse>
    </Navbar>
  );
}

export default DashNav

import React from 'react';
import { connect } from 'react-redux';
// actions
import { logOut } from '../../actions/login';
// Components used
import { Navbar, Nav, NavItem } from 'react-bootstrap';
import { NavLink } from 'react-router-dom';
import { LinkContainer } from 'react-router-bootstrap';
import FontAwesome from 'react-fontawesome';

// Wrapper for links on the navbar to make them work with react router
const NavItemLink = (props) => {
  return (
    <LinkContainer {...props}>
      <NavItem>{props.children}</NavItem>
    </LinkContainer>
  );
}

const DashNav = ({logOut}) => {
  return (
    <Navbar collapseOnSelect fixedTop>
      <Navbar.Header>
        <Navbar.Brand>
          <NavLink exact to="/dashboard">
            <FontAwesome name="truck"/> TruckTrack
          </NavLink>
        </Navbar.Brand>
        <Navbar.Toggle />
      </Navbar.Header>
      <Navbar.Collapse>

          <NavItemLink exact to="/">
            Track Package <FontAwesome name="archive"/>
          </NavItemLink>
          <NavItemLink to="/dashboard/routes">
            Routes <FontAwesome name="map"/>
          </NavItemLink>
          <NavItemLink to="/dashboard/trucks">
            Trucks <FontAwesome name="truck"/>
          </NavItemLink>
          <NavItemLink to="/dashboard/drivers">
            Drivers <FontAwesome name="users"/>
          </NavItemLink>
          <NavItem onClick={logOut}>
            Log Out <FontAwesome name="sign-out"/>
          </NavItem>

      </Navbar.Collapse>
    </Navbar>
  );
}

export default connect(null, { logOut })(DashNav)

Isolate component and add logout functionaliry


require('dotenv').config();
const webpack = require('webpack');
// I don't really like doing it this way but it works for a limited number
// of configuration options.
const socketsEnabled = process.env.WEBSOCKETS_ENABLED &&
          process.env.WEBSOCKETS_ENABLED != ('false' || '0');

const appEntry = socketsEnabled ?
          './resources/app.js' :
          './resources/app_nosockets.js';

module.exports = {
    entry:
    {
        main: appEntry
    },
    output:
    {
        filename: './public/js/bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.s[ac]ss$/i,
                use: [
                  // Creates `style` nodes from JS strings
                  'style-loader',
                  // Translates CSS into CommonJS
                  'css-loader',
                  // Compiles Sass to CSS
                  'sass-loader',
                ],
            },
            {
                test: /\.html\.tpl$/,
                loader: 'ejs-loader',
                options: {
                    variable: 'data',
                }
            },
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['@babel/preset-env']
                  }
                }
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            _: 'lodash'
        })
    ]
};

require('dotenv').config();
const path = require('path');
const webpack = require('webpack');
// I don't really like doing it this way but it works for a limited number
// of configuration options.
const socketsEnabled = process.env.WEBSOCKETS_ENABLED &&
          process.env.WEBSOCKETS_ENABLED != ('false' || '0');

const appEntry = socketsEnabled ?
          './resources/app.js' :
          './resources/app_nosockets.js';

module.exports = {
    entry:
    {
        main: appEntry
    },
    output:
    {
	filename: "bundle.js",
    	path: path.resolve(__dirname, "./public/js/"),
    	publicPath: "/js/"
    },
    module: {
        rules: [
            {
                test: /\.s[ac]ss$/i,
                use: [
                  // Creates `style` nodes from JS strings
                  'style-loader',
                  // Translates CSS into CommonJS
                  'css-loader',
                  // Compiles Sass to CSS
                  'sass-loader',
                ],
            },
            {
                test: /\.html\.tpl$/,
                loader: 'ejs-loader',
                options: {
                    variable: 'data',
                }
            },
            {
                test: /\.js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                  loader: 'babel-loader',
                  options: {
                    presets: ['@babel/preset-env']
                  }
                }
            }
        ]
    },
    plugins: [
        new webpack.ProvidePlugin({
            _: 'lodash'
        })
    ]
};

Fix the webpack putting files into dist/ by mistake


(function(d){

    d([], function(){
        return {
            script: 'script.js',
            identity: function(x) { return x; }
        };
    });

})( define || function(){} );

(function(d){

    d([], function(){
        return {
            script: 'script.js',
            identity: function(x) { return {
                number: x,
                ctx: this
            }; }
        };
    });

})( define || function(){} );

Test script is now more testable


var request = require('supertest');
var should = require('should');
var Account = require('../app/data/AccountModel');
var appUnderTest = require('../server');

describe('Authentication', function(){
    it('should not allow unauthenticated users to withdraw funds', function(done){
        var postData = { "number": "434545", "amount": 300.00 };
        request(appUnderTest)
            .post('/banker/withdraw')
            .send(postData)
            .set('Accept', 'application/json')
            // no authentication complete, so request should fail
            .expect(401, done);
    });
});

var request = require('supertest');
var should = require('should');
var Account = require('../app/data/AccountModel');
var appUnderTest = require('../server');

describe('Authentication', function(){
    it('should not allow unauthenticated users to withdraw funds', function(done){
        var postData = { "number": "434545", "amount": 300.00 };
        request(appUnderTest)
            .post('/banker/withdraw')
            .send(postData)
            .set('Accept', 'application/json')
            // no authentication complete, so request should fail
            .expect(401, done);
    });

    it('should not allow unauthenticated users to deposit funds', function(done){
        var postData = { "number": "434545", "amount": 400.00 };
        request(appUnderTest)
            .post('/banker/deposit')
            .send(postData)
            .expect(401, done);
    });

    it('should not allow unauthenticated users to request a balance', function(done){
        request(appUnderTest)
            .get('/banker/account/123456')
            .expect(401, done);
    });

    it('should not allow unauthenticated users to transfer funds', function(done){
        var postData = { "fromNumber": "434545", "toNumber": "123456", "amount": 500 };
        request(appUnderTest)
            .post('/banker/transfer')
            .send(postData)
            .expect(401, done);
    });
});

Add authentication tests for all endpoints


'use strict';

import React from 'react/addons';

const ReactTransitionGroup = React.addons.TransitionGroup;

// CSS
require('../../styles/normalize.css');
require('../../styles/main.css');

const imageURL = require('../../images/yeoman.png');

const <%= scriptAppName %> = React.createClass({
  render: function() {
    return (

        <ReactTransitionGroup transitionName="fade">

        </ReactTransitionGroup>

    );
  }
});
<% if (!reactRouter) {
%>React.render(<<%= scriptAppName %> />, document.getElementById('content')); // jshint ignore:line
<% } %>
export default <%= scriptAppName %>;

'use strict';

import React from 'react/addons';

const ReactTransitionGroup = React.addons.TransitionGroup;

// CSS
require('styles/normalize.css');
require('styles/main.css');

const imageURL = require('../../images/yeoman.png');

const <%= scriptAppName %> = React.createClass({
  render: function() {
    return (

        <ReactTransitionGroup transitionName="fade">

        </ReactTransitionGroup>

    );
  }
});
<% if (!reactRouter) {
%>React.render(<<%= scriptAppName %> />, document.getElementById('content')); // jshint ignore:line
<% } %>
export default <%= scriptAppName %>;

Use the styles alias for CSS files


/* Admin */

var ADMIN_PANES           = {},
    ADMIN_FIELD_TIMEOUT   = null,
    ADMIN_REFRESH_TIMEOUT = null;

/* Admin */

var ADMIN_PANES         = {},
    ADMIN_FIELD_TIMEOUT = null;

Remove unused `ADMIN_REFRESH_TIMEOUT' JS variable


var wompt = require("./includes");

function MetaUser(doc){
	var me = this;
	this.clients = new wompt.ClientPool();
	this.doc = doc;
	this.visible = !!doc;
	this.readonly = !doc;
	this.touch();

	this.clients.on('added', function(client){
		me.clients.broadcast({
			action: 'new_client',
			channel: client.meta_data.channel.name
		},client);
	});
};

MetaUser.prototype.id = function(){
	return this.doc ? this.doc._id.toString() : null;
}

MetaUser.prototype.touch = function(){
	this.touched = new Date();
}

MetaUser.prototype.authenticated = function(){
	return !!this.doc;
}

MetaUser.prototype.new_session = function(session){
	this.clients.broadcast({
		action: 'new_session'
	});
}

MetaUser.prototype.end_session = function(session){
	this.clients.broadcast({
		action: 'end_session'
	});
	this.clients.each(function(client, index){
		if(client.meta_data && client.meta_data.token == session.token)
			client._onDisconnect();
	});
}

module.exports = MetaUser

var wompt = require("./includes");

function MetaUser(doc){
	var me = this;
	this.clients = new wompt.ClientPool();
	this.doc = doc;
	this.visible = !!doc;
	this.readonly = !doc;
	this.touch();

	this.clients.on('added', function(client){
		me.clients.broadcast({
			action: 'new_client',
			channel: client.meta_data.channel.name
		},client);
	});
};

MetaUser.prototype.id = function(){
	return this.doc ? this.doc._id.toJSON() : null;
}

MetaUser.prototype.touch = function(){
	this.touched = new Date();
}

MetaUser.prototype.authenticated = function(){
	return !!this.doc;
}

MetaUser.prototype.new_session = function(session){
	this.clients.broadcast({
		action: 'new_session'
	});
}

MetaUser.prototype.end_session = function(session){
	this.clients.broadcast({
		action: 'end_session'
	});
	this.clients.each(function(client, index){
		if(client.meta_data && client.meta_data.token == session.token)
			client._onDisconnect();
	});
}

module.exports = MetaUser

Change User ID to use the JSON (hex) representation throughout the site


var GremlinScript = require('../src/gremlinscript');

describe('GremlinScript', function() {
  it('should append script', function() {
    var gremlin = new GremlinScript();
    gremlin.append('foo');
    gremlin.script.should.equal('foo');

  });

  it('should append a new line', function() {
    var gremlin = new GremlinScript();
    gremlin.line('foo');
    gremlin.script.should.equal('\nfoo');
  });
});

var GremlinScript = require('../src/gremlinscript');

describe('GremlinScript', function() {
  describe('append()', function() {
    it('should append script', function() {
      var gremlin = new GremlinScript();
      gremlin.append('foo');
      gremlin.script.should.equal('foo');
    });
  });

  describe('line()', function() {
    it('should append a new line', function() {
      var gremlin = new GremlinScript();
      gremlin.line('foo');
      gremlin.script.should.equal('\nfoo');
    });
  });
});

Add descriptions to GremlinScript tests


#!/usr/bin/env node

var fs        = require('fs'),
    url       = require('url'),
    http      = require('http'),
    prompt    = require('prompt'),
    pecanApp  = require('commander'),
    pecanInfo = require('./package.json');

// Setup Project
pecanApp
  .version(pecanInfo.version)
  .command('init', 'Create new PyProcessing project');

// Run Project
pecanApp
  .command('run', 'Run Pyprocessing file');

pecanApp.parse(process.argv);

#!/usr/bin/env node

var fs        = require('fs'),
    prompt    = require('prompt'),
    pecanApp  = require('commander'),
    pecanInfo = require('./package.json');

// Setup Project
pecanApp
  .version(pecanInfo.version)
  .command('init', 'Create new PyProcessing project');

// Run Project
pecanApp
  .command('run', 'Run Pyprocessing file');

pecanApp.parse(process.argv);

Remove url & http modules


/* eslint-disable no-console */
// <nowiki>
(function() {

	var updateLinks = function() {
		$('a').each(function(i, e) {
			var shorthref = e.getAttribute('href') || '';
			if (shorthref.match(/^(|#)$/)) {
				return;
			}
			try {
				var url = new URL(e.href);
				if (url.host.match(/\.(wikipedia|wiktionary|wikiquote|wikisource|wikinews|wikivoyage|wikibooks|wikiversity|wikimedia|mediawiki|wikidata)\.org$/)) {
					url.searchParams.set('dtenable', '1');
					e.href = url.href;
				}
			} catch (err) {
				console.error(e, err);
			}
		});
	};

	setTimeout(updateLinks, 1000);

	var url = new URL(window.location.href);
	url.searchParams.set('dtenable', '1');
	mw.util.addPortletLink(
		'p-tb',
		url.href,
		'Enable DiscussionTools',
		't-dtenable'
	);

}
)();
// </nowiki>

/* eslint-disable no-console */
// <nowiki>
(function() {

	var updateLinks = function() {
		$('a').each(function(i, e) {
			var shorthref = e.getAttribute('href') || '';
			if (shorthref.match(/^(|#)$/)) {
				return;
			}
			try {
				var url = new URL(e.href);
				if (url.host.match(/\.(wikipedia|wiktionary|wikiquote|wikisource|wikinews|wikivoyage|wikibooks|wikiversity|wikimedia|mediawiki|wikidata)\.org$/)) {
					url.searchParams.set('dtenable', '1');
					e.href = url.href;
				}
			} catch (err) {
				console.error(e, err);
			}
		});
	};

	setTimeout(updateLinks, 1000);

	if (mw.util.getParamValue('dtenable') === null) {
		var url = new URL(window.location.href);
		url.searchParams.set('dtenable', '1');
		mw.util.addPortletLink(
			'p-tb',
			url.href,
			'Enable DiscussionTools',
			't-dtenable'
		);
	}

}
)();
// </nowiki>

Hide enable link when dtenable is set


module.exports = {
  rules: {
    'quote-props': [2, 'as-needed', {keywords: true}],
    'array-bracket-spacing': [2, 'never'],
    'vars-on-top': 0,
    'no-param-reassign': 0,
    'max-len': [
      1,
      110,
      2,
      {
        "ignoreComments": true,
        "ignoreUrls": true
      }
    ],
    'comma-dangle': [2, 'never'],
    'no-use-before-define': [2, 'nofunc'],
    'no-lonely-if': 2,
    'handle-callback-err': 2,
    'no-extra-parens': 2,
    'no-path-concat': 1,
    'func-style': [
      1,
      'declaration'
    ],
    'space-unary-ops': 2,
    'no-mixed-requires': [
      2,
      true
    ],
    'space-in-parens': [
      2,
      'never'
    ],
    'no-var': 0,
    'prefer-const': 0,
    strict: [2, 'global'],
    'object-curly-spacing': [2, 'never'],
    'computed-property-spacing': [2, 'never'],
    'func-names': 0,
    'valid-jsdoc': [2, {requireReturnDescription: false}],
    'id-length': 0
  }
};

module.exports = {
  rules: {
    'quote-props': [2, 'as-needed', {keywords: true}],
    'array-bracket-spacing': [2, 'never'],
    'vars-on-top': 0,
    'no-param-reassign': 0,
    'max-len': [
      1,
      110,
      2,
      {
        "ignoreComments": true,
        "ignoreUrls": true
      }
    ],
    'comma-dangle': [2, 'never'],
    'no-use-before-define': [2, 'nofunc'],
    'no-lonely-if': 2,
    'handle-callback-err': 2,
    'no-extra-parens': 2,
    'no-path-concat': 1,
    'func-style': [
      1,
      'declaration'
    ],
    'space-unary-ops': 2,
    'no-mixed-requires': [
      2,
      true
    ],
    'space-in-parens': [
      2,
      'never'
    ],
    'no-var': 0,
    'prefer-const': 0,
    strict: [2, 'global'],
    'object-curly-spacing': [2, 'never'],
    'computed-property-spacing': [2, 'never'],
    'func-names': 0,
    'valid-jsdoc': [2, {requireReturnDescription: false}],
    'id-length': 0,
    'no-unused-vars': [2, {args: 'after-used', argsIgnorePattern: '^_'}]
  }
};

Allow unused arguments prefixed with _


'use strict';

jest.autoMockOff();
jest.mock('jquery');

// Fixes https://github.com/facebook/jest/issues/78
jest.dontMock('react');
jest.dontMock('underscore');

describe("Server rendering", function () {
    var React;
    var App;
    var document;
    var home_url = "http://localhost/";
    var home = {
        "@id": "/",
        "@type": ["portal"],
        "portal_title": "ENCODE",
        "title": "Home"
    };

    beforeEach(function () {
        require('../../libs/react-patches');
        React = require('react');
        App = require('..');
        var server_app = <App context={home} href={home_url} />;
        var markup = '<!DOCTYPE html>\n' + React.renderToString(server_app);
        var parser = new DOMParser();
        document = parser.parseFromString(markup, 'text/html');
    });

    it("renders the application to html", function () {
        expect(document.title).toBe(home.portal_title);
    });

    it("react render http-equiv correctly", function () {
        var meta_http_equiv = document.querySelectorAll('meta[http-equiv]');
        expect(meta_http_equiv.length).not.toBe(0);
    });

    it("mounts the application over the rendered html", function () {
        var props = App.getRenderedProps(document);
        var app = React.render(<App {...props} />, document);
        expect(app.getDOMNode()).toBe(document.documentElement);
    });
});

'use strict';

jest.autoMockOff();
jest.mock('jquery');

// Fixes https://github.com/facebook/jest/issues/78
jest.dontMock('react');
jest.dontMock('underscore');

describe("Server rendering", function () {
    var React;
    var App;
    var document;
    var home_url = "http://localhost/";
    var home = {
        "@id": "/",
        "@type": ["portal"],
        "portal_title": "ENCODE",
        "title": "Home"
    };

    beforeEach(function () {
        require('../../libs/react-patches');
        React = require('react');
        App = require('..');
        var server_app = <App context={home} href={home_url} />;
        var markup = '<!DOCTYPE html>\n' + React.renderToString(server_app);
        var parser = new DOMParser();
        document = parser.parseFromString(markup, 'text/html');
        window.location.href = home_url;
    });

    it("renders the application to html", function () {
        expect(document.title).toBe(home.portal_title);
    });

    it("react render http-equiv correctly", function () {
        var meta_http_equiv = document.querySelectorAll('meta[http-equiv]');
        expect(meta_http_equiv.length).not.toBe(0);
    });

    it("mounts the application over the rendered html", function () {
        var props = App.getRenderedProps(document);
        var app = React.render(<App {...props} />, document);
        expect(app.getDOMNode()).toBe(document.documentElement);
    });
});

Set window.location.href so that it is picked up on componentDidMount.


/**
 *  @file routes.js
 */
const express = require('express'),
  storage = require('node-persist')

const categorize = require('./middlewares').categorize,
  validateGroup = require('./middlewares').validateGroup

let handlers = require('./middlewares').handlers

exports.init = (bot) => {
  storage.initSync()

  const router = express.Router()

  const url = '/bot/:id/:name'

  handlers = handlers.map(handle => handle(bot))

  // handle group messages
  router.post.apply(router, [url, categorize, validateGroup].concat(handlers))

  // handle user messages
  router.post.apply(router, [url].concat(handlers))

  return router
}

/**
 *  @file routes.js
 */
const express = require('express'),
  storage = require('node-persist')

const { validate, isGroup, hasMention, handlers } = require('./middlewares')

exports.init = (bot) => {
  storage.initSync()

  const uri = '/bot/:id/:name'

  const middlewares = handlers.map((init) => init(bot))

  const router = express.Router()

  router.post(uri, validate)

  // group message middlewares
  router.post(uri, isGroup, hasMention, middlewares)

  // private message middlewares
  router.post(uri, middlewares)

  return router
}

Add route and use new filter middlewares


(function(){
  generateHTML();

  $(document).ready(function(){
    $('a.node.expanded').each(expandListToggle);
    $('.my-name').fadeIn("slow");
    $('.headlogolinks a').hover(fadeInLink, fadeOutLink);
    $('.menu-button').on('click', showMainContent);
    $('a.node').on('click', expandListToggle);
    $('.about-me').on('click', toggleAboutMeContent);
  });

  function fadeInLink() {
    $(this).fadeTo("fast", 1.0);
  }

  function fadeOutLink() {
    $(this).fadeTo("fast", 0.6);
  }

  function showMainContent() {
    $(".main-content").fadeIn();
    $('.menu-button').hide();
    $('.logo').fadeIn();
  }

  function expandListToggle() {
    $(this).toggleClass("expanded");
    $(this).next('ul').toggle('fast');
  };

  function toggleAboutMeContent() {
    $('.about-me-content').slideToggle();
  }
})();

(function(){
  generateHTML();

  $(document).ready(function(){
    $('a.node.expanded').each(expandListToggle);
    $('.my-name').fadeIn("slow");
    $('.headlogolinks a').hover(fadeInLink, fadeOutLink);
    $('.menu-button').on('click', showMainContent);
    $('a.node').on('click', expandListToggle);
    $('.video-link').on('click', showLaunchVideo);
    $('.about-me').on('click', toggleAboutMeContent);
  });

  function fadeInLink() {
    $(this).fadeTo("fast", 1.0);
  }

  function fadeOutLink() {
    $(this).fadeTo("fast", 0.6);
  }

  function showLaunchVideo() {
    $('.video-block').slideToggle();
  }

  function showMainContent() {
    $(".main-content").fadeIn();
    $('.menu-button').hide();
    $('.logo').fadeIn();
  }

  function expandListToggle() {
    $(this).toggleClass("expanded");
    $(this).next('ul').toggle('fast');
  };

  function toggleAboutMeContent() {
    $('.about-me-content').slideToggle();
  }
})();

Add animation to toggle presentation video block


// @flow

import * as t from '@babel/types'

// Empty out bodies of falsy parts of if/else statements
// to avoid requiring modules that aren't needed aka
// if (process.env.NODE_ENV === 'production') module.exports = require('./prod-version') else module.exports = require('./dev-version')
// OR
// module.exports = process.env.NODE_ENV === 'production' ? require('./prod-version') : require('./dev-version')

function processBooleanConditional(path: $FlowFixMe) {
  const { node } = path

  if (!t.isBooleanLiteral(node.test)) return

  function visitIfNode(leafNode) {
    if (!t.isBooleanLiteral(leafNode.test)) return
    const { test, consequent, alternate } = node

    if (test.value) {
      path.replaceWithMultiple(consequent.body)
      return
    }
    node.consequent.body = []
    if (t.isIfStatement(alternate)) {
      visitIfNode(alternate)
    } else if (t.isBlockStatement(alternate)) {
      path.replaceWithMultiple(alternate.body)
    }
  }

  if (t.isIfStatement(node)) {
    visitIfNode(node)
  } else {
    path.replaceWith(node.test.value ? node.consequent : node.alternate)
  }
}

export default {
  visitor: {
    IfStatement: {
      exit: processBooleanConditional,
    },
    ConditionalExpression: {
      exit: processBooleanConditional,
    },
  },
}

// @flow

import * as t from '@babel/types'

// Empty out bodies of falsy parts of if/else statements
// to avoid requiring modules that aren't needed aka
// if (process.env.NODE_ENV === 'production') module.exports = require('./prod-version') else module.exports = require('./dev-version')
// OR
// module.exports = process.env.NODE_ENV === 'production' ? require('./prod-version') : require('./dev-version')

function processBooleanConditional(path: $FlowFixMe) {
  const { node } = path

  if (!t.isBooleanLiteral(node.test)) return

  function visitIfNode(leafNode) {
    if (!t.isBooleanLiteral(leafNode.test)) return
    const { test, consequent, alternate } = node

    if (test.value) {
      path.replaceWithMultiple(consequent.body)
      return
    }
    node.consequent.body = []
    if (t.isIfStatement(alternate)) {
      visitIfNode(alternate)
    } else if (t.isBlockStatement(alternate)) {
      path.replaceWithMultiple(alternate.body)
    }
  }

  if (t.isIfStatement(node)) {
    visitIfNode(node)
  } else {
    path.replaceWith(node.test.value ? node.consequent : node.alternate)
  }
}

export default {
  visitor: {
    IfStatement: processBooleanConditional,
    ConditionalExpression: processBooleanConditional,
  },
}

Remove dead nodes on enter not exit


/**
 * 403 Forbidden Network Error Interceptor
 *
 * This interceptor redirects to login page when
 * any 403 session expired error is returned in any of the
 * network requests
 */

var PASSWORD_CHANGE_ROUTE = '/password_change/';
var SESSION_EXPIRED = 'session_expired';

var subdomainMatch = /https?:\/\/([^.]+)/;

module.exports = function (xhr, textStatus, errorThrown) {
  if (xhr.status !== 403) return;

  var error = xhr.responseJSON && xhr.responseJSON.error;

  if (error === SESSION_EXPIRED) {
    window.location.href = getRedirectURL();
  }
};

function getRedirectURL () {
  // We cannot get accountHost and username from configModel
  // and userModel because of static pages. God save static pages.
  var username = getUsernameFromURL(location.href);

  if (!username) {
    return '';
  }

  var newURL = location.origin.replace(subdomainMatch, function () {
    return username;
  });

  return location.protocol + '//' + newURL + PASSWORD_CHANGE_ROUTE + username;
}

function getUsernameFromURL (url) {
  var usernameMatches = window.location.pathname.split('/');

  if (usernameMatches.length > 2) {
    return usernameMatches[2];
  }

  var subdomainMatches = url.match(subdomainMatch);

  if (subdomainMatches) {
    return subdomainMatches[1];
  }

  return '';
}

/**
 * 403 Forbidden Network Error Interceptor
 *
 * This interceptor redirects to login page when
 * any 403 session expired error is returned in any of the
 * network requests
 */

var LOGIN_ROUTE = '/login';
var SESSION_EXPIRED = 'session_expired';

var subdomainMatch = /https?:\/\/([^.]+)/;

module.exports = function (xhr, textStatus, errorThrown) {
  if (xhr.status !== 403) return;

  var error = xhr.responseJSON && xhr.responseJSON.error;

  if (error === SESSION_EXPIRED) {
    window.location.href = getRedirectURL();
  }
};

function getRedirectURL () {
  // We cannot get accountHost and username from configModel
  // and userModel because of static pages. God save static pages.
  var username = getUsernameFromURL(location.href);

  if (!username) {
    return '';
  }

  var newURL = location.origin.replace(subdomainMatch, function () {
    return username;
  });

  return location.protocol + '//' + newURL + LOGIN_ROUTE;
}

function getUsernameFromURL (url) {
  var usernameMatches = window.location.pathname.split('/');

  if (usernameMatches.length > 2) {
    return usernameMatches[2];
  }

  var subdomainMatches = url.match(subdomainMatch);

  if (subdomainMatches) {
    return subdomainMatches[1];
  }

  return '';
}

Change redirection from change password page to login


#!/usr/bin/env node
'use strict';

var sv2bts = require('./').sv2bts;
var bts2sv = require('./').bts2sv;
var n2sv = require('./').n2sv;
var sv2n = require('./').sv2n;
var bts2n = require('balanced-ternary').bts2n;
var n2bts = require('balanced-ternary').n2bts;

function maybe_sv(s) {
  return !!s.match(/^[A-Z]+$/);
}

function maybe_bts(s) {
  return !!s.match(/^[0i1]+$/);
}

function maybe_n(s) {
  return !!s.match(/^[-+]?[0-9]+$/);
}

process.argv.slice(2).forEach(function(arg) {

  // bts -> n -> sv

  if (maybe_sv(arg)) {
    console.log(sv2bts(arg)+' = '+n2sv(arg)+' = '+arg);
  }

  if (maybe_n(arg)) {
    console.log(n2bts(arg)+' = '+arg+' = '+n2sv(arg));
  }

  if (maybe_bts(arg)) {
    console.log(arg+' = '+bts2n(arg)+' = '+bts2sv(arg));
  }
});

#!/usr/bin/env node
'use strict';

var sv2bts = require('./').sv2bts;
var bts2sv = require('./').bts2sv;
var n2sv = require('./').n2sv;
var sv2n = require('./').sv2n;
var bts2n = require('balanced-ternary').bts2n;
var n2bts = require('balanced-ternary').n2bts;

function maybe_sv(s) {
  return !!s.match(/^[0A-Z]+$/);
}

function maybe_bts(s) {
  return !!s.match(/^[0i1]+$/);
}

function maybe_n(s) {
  return !!s.match(/^[-+]?[0-9]+$/);
}

process.argv.slice(2).forEach(function(arg) {

  // bts -> n -> sv

  if (maybe_sv(arg)) {
    console.log(sv2bts(arg)+' = '+n2sv(arg)+' = '+arg);
  }

  if (maybe_n(arg)) {
    console.log(n2bts(arg)+' = '+arg+' = '+n2sv(arg));
  }

  if (maybe_bts(arg)) {
    console.log(arg+' = '+bts2n(arg)+' = '+bts2sv(arg));
  }
});

Fix maybe_sv, 0 is a valid digit


exports.seed = function(knex, Promise) {
  // Deletes ALL existing entries
  return knex('taxonomy').del()
    .then(function () {
      // Inserts seed entries
      return knex('taxonomy').insert([
        {id: 1, title: 'Technical Blog', description: ''},
        {id: 2, title: 'Cultural Blog', description: ''}
      ]);
    });
};

exports.seed = function(knex, Promise) {
  // Deletes ALL existing entries
  return knex('taxonomy_vocabulary').del()
    .then(function () {
      // Inserts seed entries
      return knex('taxonomy_vocabulary').insert([
        {id: 1, title: 'Technical Blog', description: ''},
        {id: 2, title: 'Cultural Blog', description: ''}
      ]);
    });
};

Change taxonomy table to taxonomy_vocabulary


import Ember from 'ember';
import DS from 'ember-data';

const { String:EmberString, computed } = Ember;
const { Model, attr, belongsTo, hasMany } = DS;
const { htmlSafe } = EmberString;

export default Model.extend({
  title: attr('string'),
  calendarColor: attr('string'),
  active: attr('boolean'),
  assessment: attr('boolean'),
  assessmentOption: belongsTo('assessment-option', {async: true}),
  school: belongsTo('school', {async: true}),
  aamcMethods: hasMany('aamc-method', {async: true}),
  sessions: hasMany('session', {async: true}),
  safeCalendarColor: computed('calendarColor', function(){
    const calendarColor = this.get('calendarColor');
    const pattern = new RegExp("^#[a-fA-F0-9]{6}$");
    if (pattern.test(calendarColor)) {
      return htmlSafe(calendarColor);
    }

    return '';

  }),
  sessionCount: computed('sessions.[]', function(){
    const sessons = this.hasMany('sessions');

    return sessons.ids().length;
  })
});

import Ember from 'ember';
import DS from 'ember-data';

const { String:EmberString, computed } = Ember;
const { Model, attr, belongsTo, hasMany } = DS;
const { htmlSafe } = EmberString;

export default Model.extend({
  title: attr('string'),
  calendarColor: attr('string'),
  active: attr('boolean'),
  assessment: attr('boolean'),
  assessmentOption: belongsTo('assessment-option', {async: true}),
  school: belongsTo('school', {async: true}),
  aamcMethods: hasMany('aamc-method', {async: true}),
  sessions: hasMany('session', {async: true}),
  safeCalendarColor: computed('calendarColor', function(){
    const calendarColor = this.get('calendarColor');
    const pattern = new RegExp("^#[a-fA-F0-9]{6}$");
    if (pattern.test(calendarColor)) {
      return htmlSafe(calendarColor);
    }

    return '';

  }),
  sessionCount: computed('sessions.[]', function(){
    const sessons = this.hasMany('sessions');

    return sessons.ids().length;
  }),
  firstAamcMethod: computed('aamcMethods.[]', async function(){
    const aamcMethods = await this.get('aamcMethods');
    return aamcMethods.get('firstObject');
  }),
});

Add firstAamcMethod to sessionType model


#!/usr/bin/env node

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

var lib = require('@google/maps');
var args = process.argv.slice(3);
var apiCall = lib.createClient()[process.argv[2]];

apiCall(lib.cli.parseArgs(args), lib.cli.callback);

#!/usr/bin/env node

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

var lib = require('@google/maps');
var args = process.argv.slice(3);
var apiCall = lib.createClient()[process.argv[2]];

try {
    apiCall(lib.cli.parseArgs(args), lib.cli.callback);
} catch (error) {
    console.log("Error:", error.message);
}

Fix error handling in cli tool.


/**
 * Created by codaphillips on 4/18/15.
 */
(function() {
    angular.module('wikiMiner.services.query_api', ['ngResource'])
        .factory('query_api', ['$resource', function($resource){
            return $resource('http://104.236.226.8/w/api.php', {
                action:'query',
                prop:'revisions',
                format:'json',
                rvprop:'user|ids|comment',
                rvlimit:'100',
                titles:'@titles'
            },{
                get:{method:'GET'}
            });
        }]);
})();

/**
 * Created by codaphillips on 4/18/15.
 */
(function() {
    angular.module('wikiMiner.services.query_api', ['ngResource'])
        .factory('query_api', ['$resource', function($resource){
            return $resource('http://104.236.226.8/w/api.php', {
                action:'query',
                prop:'revisions',
                format:'json',
                rvprop:'user|ids|comment|timestamp',
                rvlimit:'100',
                titles:'@titles'
            },{
                get:{method:'GET'}
            });
        }]);
})();

Add timestamp to wikipedia queries


/**
 * The basic content data type.
 */

const lodash = require('lodash')

// Basic content data type.
const contentTemplate = {
  // If truthy there is an error.
  error: {
    // Errors are non-zero codes.
    code: 0,
    // Errors must produce a non-falsey message.
    message: ''
  },
  // Content either being retrieved or previously retrieved.
  content: {
    // name of transformer used to modify the content.
    transformer: '',
    // url content was retrieved from.
    url: '',
    // Type of the content: html, markdown, plain, etc.
    type: '',
    // the marked up text of the content.
    text: '',
  },
}

/**
 * Returns an instance of the contentTemplate.
 *
 * @param {object} overrides Overrides for content. Assumes correct format.
 * @return {object} Basic content object.
 */
const content = function (overrides) {
  return lodash.merge({}, contentTemplate, overrides || {})
}
module.exports.content = content

/**
 * The basic content data type.
 */

const _ = require('lodash')

// Basic content data type.
const contentTemplate = {
  // If truthy there is an error.
  error: {
    // Errors are non-zero codes.
    code: 0,
    // Errors must produce a non-falsey message.
    message: ''
  },
  // Content either being retrieved or previously retrieved.
  content: {
    // name of transformer used to modify the content.
    transformer: '',
    // url content was retrieved from.
    url: '',
    // Type of the content: html, markdown, plain, etc.
    type: '',
    // the marked up text of the content.
    text: '',
  },
}

/**
 * Returns an instance of the contentTemplate.
 *
 * @param {object} overrides Overrides for content. Assumes correct format.
 * @return {object} Basic content object.
 */
const create = function (overrides) {
  return _.merge({}, contentTemplate, overrides || {})
}

module.exports = {
  create,
}

Refactor to make more wrapper based.


var es = require('event-stream');
var stylus = require('stylus');
var gutil = require('gulp-util');
var path = require('path');

module.exports = function (options) {
  var opts = options ? options : {};
  var paths = opts.paths || [];

  function stylusstream (file, cb) {
    // file is on object passed in by gulp
    // TODO: support streaming files

    var s = stylus(file.contents.toString('utf8'));
    s.set('filename', file.path);
    s.set('paths', paths.concat([path.dirname(file.path)]));

    //trying to load extensions from array passed by user
    if (options && options.use && options.use.length > 0){
      s.use(function(stylus){
        try{
          options.use.forEach(function(args){
            stylus.use(require(args)());
          });
        }
        catch(e){}
      });
    }

    s.render(function(err, css){
      if (err) return cb(err);

      file.path = gutil.replaceExtension(file.path, '.css');
      file.contents = new Buffer(css);

      cb(null, file);
    });
  }

  return es.map(stylusstream);
};

var es = require('event-stream');
var stylus = require('stylus');
var gutil = require('gulp-util');
var path = require('path');

module.exports = function (options) {
  var opts = options ? options : {};
  var paths = opts.paths || [];

  function stylusstream (file, cb) {
    // file is on object passed in by gulp
    // TODO: support streaming files
    if (file.isNull()) return cb(null, file); // pass along
    if (file.isStream()) return cb(new Error("gulp-stylus: Streaming not supported"));

    var s = stylus(file.contents.toString('utf8'));
    s.set('filename', file.path);
    s.set('paths', paths.concat([path.dirname(file.path)]));

    //trying to load extensions from array passed by user
    if (options && options.use && options.use.length > 0){
      s.use(function(stylus){
        try{
          options.use.forEach(function(args){
            stylus.use(require(args)());
          });
        }
        catch(e){}
      });
    }

    s.render(function(err, css){
      if (err) return cb(err);

      file.path = gutil.replaceExtension(file.path, '.css');
      file.contents = new Buffer(css);

      cb(null, file);
    });
  }

  return es.map(stylusstream);
};

Add checks for null and streaming files


import pegjs from 'pegjs';
import loaderUtils from 'loader-utils';

export default function loader(source) {
  if (this.cacheable) {
    this.cacheable();
  }

  const query = loaderUtils.parseQuery(this.query);
  const cacheParserResults = !!query.cache;
  const optimizeParser = query.optimize || 'speed';

  // Description of PEG.js options: https://github.com/pegjs/pegjs#javascript-api
  const pegOptions = {
    output: 'source',
    cache: cacheParserResults,
    optimize: optimizeParser
  };

  return `module.exports = ${pegjs.buildParser(source, pegOptions)};`;
}

import pegjs from 'pegjs';
import loaderUtils from 'loader-utils';

export default function loader(source) {
  if (this.cacheable) {
    this.cacheable();
  }

  const query = loaderUtils.parseQuery(this.query);
  const cacheParserResults = !!query.cache;
  const optimizeParser = query.optimize || 'speed';

  // Description of PEG.js options: https://github.com/pegjs/pegjs#javascript-api
  const pegOptions = {
    output: 'source',
    cache: cacheParserResults,
    optimize: optimizeParser,
  };

  return `module.exports = ${pegjs.buildParser(source, pegOptions)};`;
}

Fix an eslint warning about a missing trailing comma


'use strict';
var http = require("http");
var port = '8089';

module.exports = {
  start: function(bundles){
    http.createServer(function(request, response) {
      response.writeHead(200, {'Content-Type': 'application/javascript'});
      response.end(bundles[request.url]);

    }).listen(parseInt(port, 10));

  }
};

'use strict';
var http = require("http");
var port = '8089';
var findPackageJson = require('./findPackageJson');
var pack = findPackageJson();

module.exports = {
  start: function(bundles){
    pack.then(function(data){
      var port = data.pack.promethify.port;
      http.createServer(function(request, response) {
        response.writeHead(200, {'Content-Type': 'application/javascript'});
        response.end(bundles[request.url]);

      }).listen(parseInt(port, 10));

    });

  }
};

Fix problem with port number


'use strict';

const glob = require('glob-all');
const fs = require('fs');
const mime = require('mime-types');

const globOpts = {
  nodir: true
};

class Assets {
  constructor (serverless, options) {
    this.serverless = serverless;
    this.options = options;
    this.provider = this.serverless.getProvider('aws');

    Object.assign(this, validate)

    this.commands = {
      s3deploy: {
        lifecycleEvents: [
          'deploy'
        ]
      }
    };

    this.hooks = {
      's3deploy:deploy': () => new Promise.resolve()
        .then(this.deployS3.bind(this))
    };
  }

  deployS3() {
    const service = this.serverless.service;
    const config = service.custom.assets;

    // glob
    config.files.forEach((opt) => {
      let cfg = Object.assign({}, globOpts, {cwd: opt.source});
      glob.sync(opt.globs, cfg).forEach((fn) => {

        const body = fs.readFileSync(opt.source + fn)
        const type = mime.lookup(fn);

        console.log("File: ", fn, type)

        this.provider.request('S3', 'putObject', {
          ACL: config.acl || 'public-read',
          Body: body,
          Bucket: config.bucket,
          Key: fn,
          ContentType: type
        }, this.options.stage, this.options.region);

      });
    });

  }
}

module.exports = Assets;

'use strict';

const glob = require('glob-all');
const fs = require('fs');
const mime = require('mime-types');

const globOpts = {
  nodir: true
};

class Assets {
  constructor (serverless, options) {
    this.serverless = serverless;
    this.options = options;
    this.provider = this.serverless.getProvider('aws');

    this.commands = {
      s3deploy: {
        lifecycleEvents: [
          'deploy'
        ],
        options: {
            verbose: {
                usage: "Increase verbosity",
                shortcut: 'v'
            }
        }
      }
    };

    this.hooks = {
      's3deploy:deploy': () => new Promise.resolve().then(this.deployS3.bind(this))
    };
  }

  deployS3() {
    const service = this.serverless.service;
    const config = service.custom.assets;

    // glob
    config.files.forEach((opt) => {
      let cfg = Object.assign({}, globOpts, {cwd: opt.source});
      glob.sync(opt.globs, cfg).forEach((fn) => {

        const body = fs.readFileSync(opt.source + fn)
        const type = mime.lookup(fn);

        (!!this.options.verbose) && this.serverless.cli.log("File: ", fn, type)

        this.provider.request('S3', 'putObject', {
          ACL: config.acl || 'public-read',
          Body: body,
          Bucket: config.bucket,
          Key: fn,
          ContentType: type
        }, this.options.stage, this.options.region);

      });
    });

  }
}

module.exports = Assets;

Remove reference to validate. Added verbose flag


// Return Promise
const imageMerge = (sources = []) => new Promise(resolve => {
	// Load sources
	const images = sources.map(source => new Promise(resolve => {
		// Convert strings to objects
		if (typeof source === 'string') {
			source = {src: source};
		}

		// Resolve source and img when loaded
		const img = new Image();
		img.onload = () => resolve(Object.assign({}, source, {img}));
		img.src = source.src;
	}));

	// Create canvas
	const canvas = document.createElement('canvas');
	const ctx = canvas.getContext('2d');

	// When sources have loaded
	Promise.all(images)
		.then(images => {
			// Set canvas dimensions
			canvas.width = Math.max(...images.map(image => image.img.width));
			canvas.height = Math.max(...images.map(image => image.img.height));

			// Draw images to canvas
			images.forEach(image => ctx.drawImage(image.img, image.x || 0, image.y || 0));

			// Resolve data uri
			resolve(canvas.toDataURL());
		});
});

module.exports = imageMerge;

// Return Promise
const imageMerge = (sources = [], options = {}) => new Promise(resolve => {
	// Load sources
	const images = sources.map(source => new Promise(resolve => {
		// Convert strings to objects
		if (typeof source === 'string') {
			source = {src: source};
		}

		// Resolve source and img when loaded
		const img = new Image();
		img.onload = () => resolve(Object.assign({}, source, {img}));
		img.src = source.src;
	}));

	// Create canvas
	const canvas = document.createElement('canvas');
	const ctx = canvas.getContext('2d');

	// When sources have loaded
	Promise.all(images)
		.then(images => {
			// Set canvas dimensions
			canvas.width = options.width || Math.max(...images.map(image => image.img.width));
			canvas.height = options.height || Math.max(...images.map(image => image.img.height));

			// Draw images to canvas
			images.forEach(image => ctx.drawImage(image.img, image.x || 0, image.y || 0));

			// Resolve data uri
			resolve(canvas.toDataURL());
		});
});

module.exports = imageMerge;

Add option object with width/height options


'use strict';

const path   = require('path');
const config = require('./config');
const Koa    = require('koa');
const Router = require('koa-router');
const serve  = require('koa-static');

const koa = new Koa();
const app = new Router();

koa.use(serve(path.join(__dirname, 'public')))

app.get('/push', async (ctx) => {
  const secs = ctx.query.sleep || 0;
  ctx.body = `push ${secs}`;
});

koa.use(app.routes());

console.log(`Starting server on port ${config.port}...`);
koa.listen(config.port);

'use strict';

const path      = require('path');
const { sleep } = require('sleep');

const config = require('./config');
const Koa    = require('koa');
const Router = require('koa-router');
const serve  = require('koa-static');

const koa = new Koa();
const app = new Router();

koa.use(serve(path.join(__dirname, 'public')))

app.get('/push', async (ctx) => {
  const secs = +ctx.query.sleep || 0;
  sleep(secs);
  ctx.status = 200;
});

koa.use(app.routes());

console.log(`Starting server on port ${config.port}...`);
koa.listen(config.port);

Implement sleep for push endpoint


const express = require('express');
const shows = require('./routes/shows');

const app = express();

app.get('/shows', shows.findAll);
app.get('/shows/:channelId', shows.findByChannel);

app.listen(4000);
console.log('Listening on port 3000...');

const express = require('express');
const shows = require('./routes/shows');

const app = express();

app.get('/v1/shows', shows.findAll);
app.get('/v1/shows/:channelId', shows.findByChannel);

app.listen(4000);
console.log('Listening on port 3000...');

Add version to api url


/**
 *  @file routes.js
 *  @author vitor cortez
 */

var express = require('express'),
	storage = require('node-persist');

var categorize = require('./middlewares').categorize,
	validateGroup = require('./middlewares').validateGroup,
	handlers = require('./middlewares').handlers;

exports.init = bot => {
	storage.initSync();

	var router = express.Router();

	var url = '/bot/:id/:name';

	handlers = handlers.map(handler => handler(bot));

	// handle group messages
	router.post.apply(null, [url, categorize, validateGroup].concat(handlers));

	// handle user messages
	router.post.apply(null, [url].concat(handlers));

	return router;
};

/**
 *  @file routes.js
 *  @author vitor cortez
 */

var express = require('express'),
	storage = require('node-persist');

var categorize = require('./middlewares').categorize,
	validateGroup = require('./middlewares').validateGroup,
	handlers = require('./middlewares').handlers;

exports.init = bot => {
	storage.initSync();

	var router = express.Router();

	var url = '/bot/:id/:name';

	handlers = handlers.map(handler => handler(bot));

	// handle group messages
	router.post.apply(router, [url, categorize, validateGroup].concat(handlers));

	// handle user messages
	router.post.apply(router, [url].concat(handlers));

	return router;
};

Fix error when applying `post` with null receiver


'use strict'

const Store = require('orbit-db-store')
const CounterIndex = require('./CounterIndex')

class CounterStore extends Store {
  constructor(ipfs, id, dbname, options = {}) {
    if(!options.Index) Object.assign(options, { Index: CounterIndex })
    super(ipfs, id, dbname, options)
    this._type = 'counter'
  }

  get value() {
    return this._index.get().value
  }

  inc(amount) {
    const counter = this._index.get()
    if(counter) {
      counter.increment(amount)
      return this._addOperation({
        op: 'COUNTER',
        key: null,
        value: counter.payload,
        meta: {
          ts: new Date().getTime()
        }
      })
    }
  }
}

module.exports = CounterStore

'use strict'

const Store = require('orbit-db-store')
const CounterIndex = require('./CounterIndex')

class CounterStore extends Store {
  constructor(ipfs, id, dbname, options = {}) {
    if(!options.Index) Object.assign(options, { Index: CounterIndex })
    super(ipfs, id, dbname, options)
    this._type = 'counter'
  }

  get value() {
    return this._index.get().value
  }

  inc(amount) {
    const counter = this._index.get()
    if(counter) {
      counter.increment(amount)
      return this._addOperation({
        op: 'COUNTER',
        key: null,
        value: counter.payload,
      })
    }
  }
}

module.exports = CounterStore

Remove obsolete meta and timestamp field


'use strict';

var peg = require('pegjs');

class PegJsPlugin {

  constructor(config) {
    this.config = config.plugins.pegjs;
    // The output of the below peg.generate() function must be a string, not an
    // object
    this.config.output = 'source';
  }

  compile(file) {
    var parser;
    try {
      parser = peg.generate(file.data, this.config);
    } catch(error) {
      if (error instanceof peg.parser.SyntaxError) {
        error.message = `${error.message} at ${error.location.start.line}:${error.location.start.column}`;
      }
      return Promise.reject(error);
    }
    return Promise.resolve({data: parser});
  }

}

// brunchPlugin must be set to true for all Brunch plugins
PegJsPlugin.prototype.brunchPlugin = true;
// The type of file to generate
PegJsPlugin.prototype.type = 'javascript';
// The extension for files to process
PegJsPlugin.prototype.extension = 'pegjs';
// The extension for processed files (this allows for compiler chaining)
PegJsPlugin.prototype.targetExtension = 'js';

module.exports = PegJsPlugin;

'use strict';

const peg = require('pegjs');

class PegJsPlugin {

  constructor(config) {
    this.config = config.plugins.pegjs;
    // The output of the below peg.generate() function must be a string, not an
    // object
    this.config.output = 'source';
  }

  compile(file) {
    let parser;
    try {
      parser = peg.generate(file.data, this.config);
    } catch(error) {
      if (error instanceof peg.parser.SyntaxError) {
        error.message = `${error.message} at ${error.location.start.line}:${error.location.start.column}`;
      }
      return Promise.reject(error);
    }
    return Promise.resolve({data: parser});
  }

}

// brunchPlugin must be set to true for all Brunch plugins
PegJsPlugin.prototype.brunchPlugin = true;
// The type of file to generate
PegJsPlugin.prototype.type = 'javascript';
// The extension for files to process
PegJsPlugin.prototype.extension = 'pegjs';
// The extension for processed files (this allows for compiler chaining)
PegJsPlugin.prototype.targetExtension = 'js';

module.exports = PegJsPlugin;

Use const/let instead of var


var jsdom = require("jsdom");

function assign (destination, source) {
  for (var key in source) {
    if (source.hasOwnProperty(key)) {
      destination[key] = source[key];
    }
  }

  return destination;
}

var jsdomBrowser = function (baseBrowserDecorator, config) {
  baseBrowserDecorator(this);

  this.name = "jsdom";

  this._start = function (url) {
    if (jsdom.JSDOM) { // Indicate jsdom >= 10.0.0 and a new API
      var jsdomOptions = {
        resources: "usable",
        runScripts: "dangerously",
        virtualConsole: virtualConsole
      };

      if (config.jsdom) {
        jsdomOptions = assign(jsdomOptions, config.jsdom);
      }

      jsdom.JSDOM.fromURL(url, jsdomOptions);
    } else {
      var jsdomOptions = {
        url: url,
        features : {
          FetchExternalResources: ["script", "iframe"],
          ProcessExternalResources: ["script"]
        },
        created: function (error, window) {
          // Do nothing.
        }
      }

      if (config.jsdom) {
        jsdomOptions = assign(jsdomOptions, config.jsdom);
      }

      jsdom.env(jsdomOptions);
    }
  };
};

jsdomBrowser.$inject = ["baseBrowserDecorator", "config.jsdomLauncher"];

module.exports = {
  "launcher:jsdom": ["type", jsdomBrowser]
};

var jsdom = require("jsdom");

function assign (destination, source) {
  for (var key in source) {
    if (source.hasOwnProperty(key)) {
      destination[key] = source[key];
    }
  }

  return destination;
}

var jsdomBrowser = function (baseBrowserDecorator, config) {
  baseBrowserDecorator(this);

  this.name = "jsdom";

  this._start = function (url) {
    if (jsdom.JSDOM) { // Indicate jsdom >= 10.0.0 and a new API
      var jsdomOptions = {
        resources: "usable",
        runScripts: "dangerously"
      };

      if (config.jsdom) {
        jsdomOptions = assign(jsdomOptions, config.jsdom);
      }

      jsdom.JSDOM.fromURL(url, jsdomOptions);
    } else {
      var jsdomOptions = {
        url: url,
        features : {
          FetchExternalResources: ["script", "iframe"],
          ProcessExternalResources: ["script"]
        },
        created: function (error, window) {
          // Do nothing.
        }
      }

      if (config.jsdom) {
        jsdomOptions = assign(jsdomOptions, config.jsdom);
      }

      jsdom.env(jsdomOptions);
    }
  };
};

jsdomBrowser.$inject = ["baseBrowserDecorator", "config.jsdomLauncher"];

module.exports = {
  "launcher:jsdom": ["type", jsdomBrowser]
};

Correct a mistake from 1ae32f5


var StorageFactory = require('./lib/StorageFactory');

module.exports = new StorageFactory();
module.exports.Factory = new StorageFactory();

var StorageFactory = require('./lib/StorageFactory');

module.exports = new StorageFactory();
module.exports.Factory = StorageFactory;

Fix returning pointer to factory class


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

module.exports = {
  name: 'ember-cli-respond',
  contentFor: function(type, config) {
    if (type === 'head-footer') {
        var output = '<script src="/ember-cli-respond/respond.min.js"></script>';
        if (typeof config.respond !== 'undefined' && config.respond.proxy === true) {
            output += '<link href="' + config.respond.externalUrl + 'respond-proxy.html" id="respond-proxy" rel="respond-proxy" />' +
            '<link href="/ember-cli-respond/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />' +
            '<script src="/ember-cli-respond/respond.proxy.js"></script>';
        }
        return output;
    }
  }
};

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

module.exports = {
  name: 'ember-cli-respond',
  contentFor: function(type, config) {
    if (type === 'head-footer') {
        var output = '<script src="' + config.respond.externalUrl + 'ember-cli-respond/respond.min.js"></script>';
        if (typeof config.respond !== 'undefined' && config.respond.proxy === true) {
            output += '<link href="' + config.respond.externalUrl + 'respond-proxy.html" id="respond-proxy" rel="respond-proxy" />' +
            '<link href="' + config.respond.externalUrl + '"ember-cli-respond/respond.proxy.gif" id="respond-redirect" rel="respond-redirect" />' +
            '<script src="' + config.respond.externalUrl + '"ember-cli-respond/respond.proxy.js"></script>';
        }
        return output;
    }
  }
};

Add externalUrl to all resources