/*global describe, beforeEach, it*/
'use strict';

var path    = require('path');
var helpers = require('yeoman-generator').test;

describe('bespoke generator', function () {
  beforeEach(function (done) {
    helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
      if (err) {
        return done(err);
      }

      this.app = helpers.createGenerator('bespoke:app', [
        '../../app'
      ]);
      done();
    }.bind(this));
  });

  it('creates expected files', function (done) {
    var expected = [
      // add files you expect to exist here.
      'package.json',
      'bower.json',
      'Gruntfile.js',
      '.gitignore',
      '.jshintrc',
      '.bowerrc',
      'src/index.jade',
      'src/js/js.js',
      'src/css/css.styl'
    ];

    helpers.mockPrompt(this.app, {
      'title': 'Foo Bar',
      'bullets': 'Y',
      'hash': 'Y'
    });

    this.app.run({}, function () {
      helpers.assertFiles(expected);
      done();
    });
  });
});

/*global describe, beforeEach, it*/
'use strict';

var path    = require('path');
var helpers = require('yeoman-generator').test;

describe('bespoke generator', function () {
  beforeEach(function (done) {
    helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
      if (err) {
        return done(err);
      }

      this.app = helpers.createGenerator('bespoke:app', [
        '../../app'
      ]);
      done();
    }.bind(this));
  });

  it('creates expected files', function (done) {
    var expected = [
      // add files you expect to exist here.
      'package.json',
      'bower.json',
      'Gruntfile.js',
      '.gitignore',
      '.jshintrc',
      '.bowerrc',
      'src/index.jade',
      'src/scripts/main.js',
      'src/styles/main.styl'
    ];

    helpers.mockPrompt(this.app, {
      'title': 'Foo Bar',
      'bullets': 'Y',
      'hash': 'Y'
    });

    this.app.run({}, function () {
      helpers.assertFiles(expected);
      done();
    });
  });
});

Update test to reflect renamed 'js' and 'css' dirs


(function($){
    var location = 'resources/snippets/';
    console.log("loading snippets");
    $(".clojure").each(function(index, element){
        var url = location + $(element).data("snippet");
        $.ajax(url).done(function(data){
            $(element).html(data);
        });
    });
})(jQuery);

(function($){
    $.fn.load_snippets = function(options){
        console.log("loading snippets");
        var settings = $.extend({
            location: 'resources/snippets/',
            data: 'snippet'
        }, options);
        this.each(function(index, element){
            var url = settings.location + $(element).data(settings.data);
            $.ajax(url).done(function(data){
                $(element).html(data);
            });
        });

        return this;
    };
    $(".clojure").load_snippets();
})(jQuery);

Create and use a jQuery plugin loading snippets


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

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

module.exports = {
  validateFields: function(next) {
    if (!this.title) {
      return next(new Error('Trip is missing a title'));
    }

    if (!Array.isArray(this.ideas)) {
      return next(new Error('Trip ideas have invalid format'));
    }

    if (!Array.isArray(this.plan)) {
      return next(new Error('Trip plan has invalid format'));
    }

    if (this.endDate && this.startDate) {
      if (this.endDate < this.startDate) {
        return next(new Error('Trip end date is before start date'));
      }
    }

    next();
  },

  // Create a trip day by default for each new trip
  createDefaultTripDay: function(next) {
    if (!this.isNew) {
      return next();
    }

    var params = {
      entries: [],
      lodging: {}
    };

    this.plan.push(params);
    next();
  },

  findTrips: function(params, page) {
    var count = config.database.DEFAULT_TRIP_COUNT;

    if (!params || !page) {
      return Promise.reject(new Error('Invalid arguments'));
    }

    return this
      .find(params)
      .sort({ date: -1 })
      .skip(count * (page-1))
      .limit(count)
      .exec();
  }
};

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

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

module.exports = {
  validateFields: function(next) {
    if (!this.title) {
      return next(new Error('Trip is missing a title'));
    }

    if (!Array.isArray(this.ideas)) {
      return next(new Error('Trip ideas have invalid format'));
    }

    if (!Array.isArray(this.plan)) {
      return next(new Error('Trip plan has invalid format'));
    }

    if (this.endDate && this.startDate) {
      if (this.endDate < this.startDate) {
        return next(new Error('Trip end date is before start date'));
      }
    }

    var vis = this.visibility;
    if (vis && vis !== 'public' && vis !== 'private') {
      return next(new Error('Trip has invalid visibility set'));
    }

    next();
  },

  // Create a trip day by default for each new trip
  createDefaultTripDay: function(next) {
    if (!this.isNew) {
      return next();
    }

    var params = {
      entries: [],
      lodging: {}
    };

    this.plan.push(params);
    next();
  },

  findTrips: function(params, page) {
    var count = config.database.DEFAULT_TRIP_COUNT;

    if (!params || !page) {
      return Promise.reject(new Error('Invalid arguments'));
    }

    return this
      .find(params)
      .sort({ date: -1 })
      .skip(count * (page-1))
      .limit(count)
      .exec();
  }
};

Add validation for trip visibility field


// DOM Ready
$(function() {

	// www.conditionizr.com
	// Legacy content and retina scripts and styles
	$('head').conditionizr({
		ieLessThan : {
			active: true,
			version: '9',
			scripts: false,
			styles: false,
			classes: true,
			customScript: 'WORDPRESS_THEME_DIRECTORY_HERE/js/mediaqueries.min.js'
		}
	});

	// SVG custom feature detection and svg to png fallback
	// toddmotto.com/mastering-svg-use-for-a-retina-web-fallbacks-with-png-script#update
	function supportsSVG() {
		return !! document.createElementNS && !! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect;
	}
	if (supportsSVG()) {
		document.documentElement.className += ' svg';
	} else {
		document.documentElement.className += ' no-svg';
		var imgs = document.getElementsByTagName('img'),
			dotSVG = /.*\.svg$/;
		for (var i = 0; i != imgs.length; ++i) {
			if(imgs[i].src.match(dotSVG)) {
				imgs[i].src = imgs[i].src.slice(0, -3) + "png";
			}
		}
	}

	// iPhone Safari URL bar hides itself on pageload
	if (navigator.userAgent.indexOf('iPhone') != -1) {
	    addEventListener("load", function () {
	        setTimeout(hideURLbar, 0);
	    }, false);
	}

	function hideURLbar() {
	    window.scrollTo(0, 0);
	}

});

// DOM Ready
$(function() {

	// www.conditionizr.com
	// Legacy content and retina scripts and styles
	$('head').conditionizr({
		ieLessThan : {
			active: true,
			version: '9',
			scripts: false,
			styles: false,
			classes: true,
			customScript: 'WORDPRESS_THEME_DIRECTORY_HERE/js/mediaqueries.min.js'
		}
	});

	// SVG custom feature detection and svg to png fallback
	// toddmotto.com/mastering-svg-use-for-a-retina-web-fallbacks-with-png-script#update
	function supportsSVG() {
		return !! document.createElementNS && !! document.createElementNS('http://www.w3.org/2000/svg','svg').createSVGRect;
	}
	if (supportsSVG()) {
		document.documentElement.className += ' svg';
	} else {
		document.documentElement.className += ' no-svg';
		var imgs = document.getElementsByTagName('img'),
			dotSVG = /.*\.svg$/;
		for (var i = 0; i != imgs.length; ++i) {
			if(imgs[i].src.match(dotSVG)) {
				imgs[i].src = imgs[i].src.slice(0, -3) + "png";
			}
		}
	}

});

Remove iPhone scrollbar onload script


angular.module('paperworkNotes')
  .directive('pwDatepickerRefresh', function() {
    var noop = function() {};
    var refresh = function(dpCtrl) {
      return function() {
        dpCtrl.refreshView();
      };
    };

    return {
      require: 'datepicker',
      link:    function(scope, elem, attrs, dpCtrl) {
        var refreshPromise = scope[attrs.datepickerRefresh];
        refreshPromise.then(noop, noop, refresh(dpCtrl));
      }
    };
  });

angular.module('paperworkNotes')
  .directive('pwDatepickerRefresh', function() {
    var noop = function() {};
    var refresh = function(dpCtrl) {
      return function() {
        dpCtrl.refreshView();
      };
    };

    return {
      require: 'datepicker',
      link:    function(scope, elem, attrs, dpCtrl) {
        var refreshPromise = scope[attrs.pwDatepickerRefresh];
        refreshPromise.then(noop, noop, refresh(dpCtrl));
      }
    };
  });

Fix naming bug introduced by refactoring


var command = (process.platform === 'win32') ? 'casperjs.cmd' : 'casperjs';

exports.find = function(args, successFind) {
	var spawn = require('child_process').spawn(command, args);
	var info = new Object();

	spawn.stdout.on('data', function(data) {
		info = JSON.parse(data);
	});

	spawn.stderr.on('data', function(data) {
		console.log(JSON.stringify(data));
	});

	spawn.on('exit', function(code) {
		successFind(info);
	});
}

exports.download = function(args, successDownload) {
	var spawn = require('child_process').spawn(command, args);
	var info = new Object();

	spawn.stdout.on('data', function(data) {
		info = JSON.parse(data);
	});

	spawn.stderr.on('data', function(data) {
		console.log(JSON.stringify(data));
	});

	spawn.on('exit', function(code) {
		successDownload(info);
	});
}

Add a function to download the source solved by Casper.


'use-strict';

const path = require('path');
const postcss = require('postcss');
const cssImport = require('postcss-import');
const atRulesVars = require('postcss-at-rules-variables');
const each = require('postcss-each');
const mixins = require('postcss-mixins');
const nested = require('postcss-nested');
const customProperties = require('postcss-custom-properties');
const conditionals = require('postcss-conditionals');
const customMedia = require('postcss-custom-media');
const calc = require('postcss-calc');
const colorFunction = require('postcss-color-function');
const mediaQueryPacker = require('css-mqpacker');
const autoprefixer = require('autoprefixer');

const mixinsPath = path.join(
  path.dirname(require.resolve('@wearegenki/css')),
  'src/mixins',
);

module.exports = postcss.plugin('ui-postcss', (opts = {}) => {
  const mixinsDir = [opts.mixinsDir] || [];
  mixinsDir.push(mixinsPath);

  return postcss()
    .use(cssImport({ path: opts.importPath || ['src'] }))
    .use(atRulesVars)
    .use(each)
    .use(mixins({ mixinsDir }))
    .use(nested)
    .use(customProperties)
    .use(conditionals)
    .use(customMedia)
    .use(calc({ warnWhenCannotResolve: opts.verbose }))
    .use(colorFunction)
    .use(mediaQueryPacker)
    .use(autoprefixer({ cascade: false, remove: false, grid: true }));
});

'use-strict';

const path = require('path');
const postcss = require('postcss');
const cssImport = require('postcss-import');
const atRulesVars = require('postcss-at-rules-variables');
const each = require('postcss-each');
const mixins = require('postcss-mixins');
const nested = require('postcss-nested');
const customProperties = require('postcss-custom-properties');
const conditionals = require('postcss-conditionals');
const customMedia = require('postcss-custom-media');
const calc = require('postcss-calc');
const colorFunction = require('postcss-color-function');
const mediaQueryPacker = require('css-mqpacker');
const autoprefixer = require('autoprefixer');

const mixinsPath = path.join(
  path.dirname(require.resolve('@wearegenki/css')),
  'src/mixins',
);

module.exports = postcss.plugin('ui-postcss', (opts = {}) => {
  const mixinsDir = opts.mixinsDir ? [opts.mixinsDir] : [];
  mixinsDir.push(mixinsPath);

  return postcss()
    .use(cssImport({ path: opts.importPath || ['src'] }))
    .use(atRulesVars)
    .use(each)
    .use(mixins({ mixinsDir }))
    .use(nested)
    .use(customProperties)
    .use(conditionals)
    .use(customMedia)
    .use(calc({ warnWhenCannotResolve: opts.verbose }))
    .use(colorFunction)
    .use(mediaQueryPacker)
    .use(autoprefixer({ cascade: false, remove: false, grid: true }));
});

Fix error when mixinsDir option is not defined in psotcss preset


module.exports = {
  contacts         :  '2.0/contacts/',
  favorites        :  '2.0/favorites/',
  folders          :  '2.0/folders/',
  groups           :  '2.0/groups/',
  home             :  '2.0/home/',
  imageUrls        :  '2.0/imageurls',
  reports          :  '2.0/reports/',
  search           :  '2.0/search/',
  server           :  '2.0/serverinfo/',
  sheets           :  '2.0/sheets/',
  sights           :  '2.0/sights/',
  templates        :  '2.0/templates/',
  templatesPublic  :  '2.0/templates/public',
  users            :  '2.0/users/',
  webhooks         :  '2.0/webhooks/',
  workspaces       :  '2.0/workspaces/'
};

module.exports = {
  contacts         :  '2.0/contacts/',
  favorites        :  '2.0/favorites/',
  folders          :  '2.0/folders/',
  groups           :  '2.0/groups/',
  home             :  '2.0/home/',
  imageUrls        :  '2.0/imageurls/',
  reports          :  '2.0/reports/',
  search           :  '2.0/search/',
  server           :  '2.0/serverinfo/',
  sheets           :  '2.0/sheets/',
  sights           :  '2.0/sights/',
  templates        :  '2.0/templates/',
  templatesPublic  :  '2.0/templates/public',
  users            :  '2.0/users/',
  webhooks         :  '2.0/webhooks/',
  workspaces       :  '2.0/workspaces/'
};

Add trailing slash on API URIs for consistency.


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

  var getThemeConfig = require('../lib/get-theme-config')
    , happyplan = grunt.config.get('happyplan')
    , glyphicons = []

  getThemeConfig(grunt, ['path', 'assets', 'glyphicons'], { merge: true } ).forEach(function(src) {
    glyphicons.push(src + '/**/*.svg')
  });

  return {
    glyphicons: {
      src: glyphicons,
      dest: '<%= happyplan.path.build.assets.fonts %>',
      destCss: '<%= happyplan.path.build.assets.styles %>',
      options: {
          relativeFontPath: require('path').relative(
            happyplan.cwd + '/' + grunt.config.get(['happyplan', 'path', 'dist', 'assets', 'styles']),
            happyplan.cwd + '/' + grunt.config.get(['happyplan', 'path', 'dist', 'assets', 'fonts'])
          ),
          stylesheet: 'scss',
          hashes: false,
          htmlDemo: false,
          engine: '<%= happyplan.glyphicons.engine %>'
      }
    }
  }
}

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

  var getThemeConfig = require('../lib/get-theme-config')
    , happyplan = grunt.config.get('happyplan')
    , glyphicons = []

  getThemeConfig(grunt, ['path', 'assets', 'glyphicons'], { merge: true } ).forEach(function(src) {
    glyphicons.push(src + '/**/*.svg')
  });

  return {
    glyphicons: {
      src: glyphicons,
      dest: '<%= happyplan.path.dist.assets.fonts %>',
      destCss: '<%= happyplan.path.build.assets.styles %>',
      options: {
          relativeFontPath: require('path').relative(
            happyplan.cwd + '/' + grunt.config.get(['happyplan', 'path', 'dist', 'assets', 'styles']),
            happyplan.cwd + '/' + grunt.config.get(['happyplan', 'path', 'dist', 'assets', 'fonts'])
          ),
          stylesheet: 'scss',
          hashes: false,
          htmlDemo: false,
          engine: '<%= happyplan.glyphicons.engine %>'
      }
    }
  }
}

Fix glyphicons font path for dist


module.exports = function(config) {

  var SRC = [
    'dist/autocompleteList.js',
    'src/**/*.spec.js'
  ];

  var DEPENDENCIES = [
    'node_modules/angular/angular.js',
    'node_modules/angular-animate/angular-animate.js',
    'node_modules/angular-aria/angular-aria.js',
    'node_modules/angular-mocks/angular-mocks.js',
    'node_modules/angular-material/angular-material.js',
  ];

  config.set({
    basePath: './',
    frameworks: ['jasmine'],
    files: DEPENDENCIES.concat(SRC),

    reporters: ['progress'],
    browsers: ['Chrome'],
    singleRun: true,

    client: {
      clearContext: false
    }
  });
}

module.exports = function(config) {

  var SRC = [
    'dist/autocompleteList.js',
    'src/**/*.spec.js'
  ];

  var DEPENDENCIES = [
    'node_modules/angular/angular.js',
    'node_modules/angular-animate/angular-animate.js',
    'node_modules/angular-aria/angular-aria.js',
    'node_modules/angular-mocks/angular-mocks.js',
    'node_modules/angular-material/angular-material.js',
  ];

  config.set({
    basePath: './',
    frameworks: ['jasmine'],
    files: DEPENDENCIES.concat(SRC),

    reporters: ['progress'],
    browsers: ['Chrome', 'Firefox'],
    singleRun: true,

    client: {
      clearContext: false
    }
  });
}

Add Firefox to test browser list


var Event = require('../models/Event.js');
var Venue = require('../models/Venue.js');

exports.sync = function(events) {
    events.map(function(evt) {
        var eventquery = {
            'title': evt.title,
            'startAt': evt.startAt
        };
        Event.findOne(
            eventquery,
            function(err, doc) {
                if(!doc){
                    Event.create(evt , function(err, doc){
                        if(err){
                            console.log("Something went wrong in creating new event");
                        }
                    }
                );}

            }
        );
        var venuequery = {
            'name': evt.venue.name
        };
        Venue.findOne(
            venuequery,
            function(err, doc) {
                if(!doc){
                    var venue = new Venue();
                    venue.name = evt.venue.name;
                    venue.address = evt.venue.address;
                    venue.latitude = evt.venue.latitude;
                    venue.longitude = evt.venue.longitude;
                    venue.save(function(err, doc){
                            if(err){
                                console.log("Something went wrong in creating new event");
                            }
                        }
                    );}
            }
        );
    });
};

var Event = require('../models/Event.js');
var Venue = require('../models/Venue.js');

exports.sync = function(events) {
    events.map(function(evt) {
        var eventquery = {
            'title': evt.title,
            'startAt': evt.startAt
        };
        Event.findOne(
            eventquery,
            function (err, doc) {
                if (!doc) {
                    Event.create(evt, function (err, doc) {
                            if (err) {
                                console.log("Something went wrong in creating new event");
                            }
                        }
                    );
                }

            }
        );
        var venuequery = {
            'name': evt.venue.name
        };
        var venue = {};
        venue.name = evt.venue.name;
        venue.address = evt.venue.address;
        venue.latitude = evt.venue.latitude;
        venue.longitude = evt.venue.longitude;
        Venue.findOneAndUpdate(
            venuequery,
            venue,
            {'upsert': true},
            function(err, doc) {
                if (err) {
                    console.log("Something went wrong in creating new event");
                }
            }
        );
    });
};

Fix duplicates in imported venues


// error message handler
const handleError = (err, res) => {
  switch (err.code) {
    case 401:
      return res.status(401).json(err.message);
    case 404:
      return res.status(404).json(err.message);
    default:
      return res.status(400).json(err);
  }
};
// success message handler
const handleSuccess = (code, body, res) => {
  switch (code) {
    case 201:
      return res.status(201).json(body);
    default:
      return res.status(200).json(body);
  }
};
module.exports = { handleError, handleSuccess };

// error message handler
const handleError = (err, res) => {
  switch (err.code) {
    case 401:
      return res.status(401).json({ status: 401, message: err.message });
    case 404:
      return res.status(404).json({ status: 404, message: err.message });
    default:
      return res.status(400).json({ status: 400, message: err.message });
  }
};
// success message handler
const handleSuccess = (code, body, res) => {
  switch (code) {
    case 201:
      return res.status(201).json({ status: 201, data: body });
    default:
      return res.status(200).json({ status: 200, data: body });
  }
};
module.exports = { handleError, handleSuccess };

Change error handlers to objects


function showAjaxIndicator() {
	$('#${componentId}').show();
}

function hideAjaxIndicator() {
	$('#${componentId}').hide();
}
Wicket.Event.subscribe('/ajax/call/beforeSend',
	function( attributes, jqXHR, settings ) {
		showAjaxIndicator()
    });
Wicket.Event.subscribe('/ajax/call/complete',
	function( attributes, jqXHR, textStatus) {
		hideAjaxIndicator()
    });

'use strict';

var timeoutID;
var needShow = false;

function showAjaxIndicator() {
	needShow = true;
    timeoutID = window.setTimeout(function () {
        if (needShow) $('#${componentId}').show();
    }, 100);
}

function hideAjaxIndicator() {
	needShow = false;
    window.clearTimeout(timeoutID);
    $('#${componentId}').hide();
}

Wicket.Event.subscribe('/ajax/call/beforeSend',
	function( attributes, jqXHR, settings ) {
		showAjaxIndicator();
    });

Wicket.Event.subscribe('/ajax/call/complete',
	function( attributes, jqXHR, textStatus) {
		hideAjaxIndicator();
    });

Create delay before show AjaxIndicator


'use strict';

// Dependencies
const cssnext = require('cssnext')
const path = require('path')

// Aliases
var basedir = __dirname

module.exports = {
  paths: {
    destination: path.join(basedir, 'dist'),
    source: path.join(basedir, 'src'),
    templates: path.join(basedir, 'templates')
  },

  processors: {
    defaults: {
      '*.md': {
        kind: 'page',
        template: 'page'
      },
      'posts/**/*.md': {
        kind: 'post',
        permalink: false,
        template: 'post'
      }
    },
    extractPathData: {
      'posts/**/*.md': 'posts/{category}/{date}--{slug}.md'
    },
    postcss: [
      cssnext()
    ]
  },

  globals: {
    site: {
      title: 'Steffen Bruchmann’s Website'
    }
  }
}

'use strict';

// Dependencies
const cssnext = require('cssnext')
const path = require('path')

// Aliases
let basedir = __dirname

module.exports = {
  paths: {
    destination: path.join(basedir, 'dist'),
    source: path.join(basedir, 'src'),
    templates: path.join(basedir, 'templates')
  },

  processors: {
    defaults: {
      '*.md': {
        kind: 'page',
        template: 'page'
      },
      'posts/**/*.md': {
        kind: 'post',
        permalink: false,
        template: 'post'
      }
    },
    extractPathData: {
      'posts/**/*.md': 'posts/{category}/{date}--{slug}.md'
    },
    postcss: [
      cssnext()
    ]
  },

  globals: {
    site: {
      title: 'Steffen Bruchmann’s Website'
    }
  }
}

Use `let` instead of `var` for aliases


var Application = require('application');

module.exports = (function() {

    function prepareDOM() {
        document.body.appendChild(document.createElement('gelato-application'));
        document.body.appendChild(document.createElement('gelato-dialogs'));
        document.body.appendChild(document.createElement('gelato-navbars'));
        document.body.appendChild(document.createElement('gelato-sidebars'));
    }

    function start() {
        prepareDOM();
        window.app = new Application();
        window.app.start();
    }

    if (location.protocol === 'file:') {
        $.ajax({
            url: 'cordova.js',
            dataType: 'script'
        }).done(function() {
            document.addEventListener('deviceready', start, false);
        }).fail(function() {
            console.error(new Error('Unable to load cordova.js file.'));
        });
    } else {
        $(document).ready(start);
    }

})();

var Application = require('application');

module.exports = (function() {

    function start() {
        document.body.appendChild(document.createElement('gelato-application'));
        new Application().start();
    }

    if (location.protocol === 'file:') {
        $.ajax({
            url: 'cordova.js',
            dataType: 'script'
        }).done(function() {
            document.addEventListener('deviceready', start, false);
        }).fail(function() {
            console.error(new Error('Unable to load cordova.js file.'));
        });
    } else {
        $(document).ready(start);
    }

})();

Remove adding of app to the window on initialization.


module.exports = {
  API_URL: process.env.USE_LOCAL ? 'http://localhost:5000' : 'https://cofacts-api.hacktabl.org',

  // If is dev but connet to production api, don't use appId = RUMORS_SITE.
  // Use RUMORS_SITE only on production, or when connecting to local dev server
  //
  APP_ID: process.env.USE_LOCAL || process.env.NODE_ENV === 'production' ? 'RUMORS_SITE' : 'DEV',
};

module.exports = {
  API_URL: process.env.USE_LOCAL ? 'http://localhost:5000' : 'https://cofacts-api.g0v.tw',

  // If is dev but connet to production api, don't use appId = RUMORS_SITE.
  // Use RUMORS_SITE only on production, or when connecting to local dev server
  //
  APP_ID: process.env.USE_LOCAL || process.env.NODE_ENV === 'production' ? 'RUMORS_SITE' : 'DEV',
};

Use cofacts-api.g0v.tw as API endpoint


import { expect, getRenderedComponent } from '../../spec_helper'
import { default as subject } from '../../../src/components/views/PostDetailView'

describe('PostDetailView', () => {
  it('#render', () => {
    const comp = getRenderedComponent(subject, { params: { token: 'yay' } })
    expect(comp.props.className).to.equal('PostDetail Panel')
    expect(comp.type).to.equal('section')
    const streamComp = comp.props.children
    expect(streamComp.ref).to.equal('streamComponent')
  })
})

import { expect, getRenderedComponent } from '../../spec_helper'
import { default as subject } from '../../../src/components/views/PostDetailView'

describe('PostDetailView', () => {
  it('#render', () => {
    const comp = getRenderedComponent(subject, { params: { token: 'yay' } })
    expect(comp.props.className).to.equal('PostDetailView Panel')
    expect(comp.type).to.equal('section')
    const streamComp = comp.props.children
    expect(streamComp.ref).to.equal('streamComponent')
  })
})

Fix a broken test from a rename.


Meteor.publish("misureBySito", function (sitoId) {
    check(sitoId, String);
    var sito = Siti.findOne({_id: new Mongo.ObjectID(sitoId)});
    return sito && Misure.find({pod: sito.pod});
});

Meteor.publish("misureBySito", function (sitoId) {
    check(sitoId, String);
    var sito = Siti.findOne({$or: [
        {_id: new Mongo.ObjectID(sitoId)},
        {_id: sitoId}
    ]});
    return sito && Misure.find({pod: sito.pod});
});

Select siti using either a string or an ObjectId as _id


define(['jquery', 'underscore', 'backbone', 'model_search_item'], function($, _, Backbone, Models) {
	Models.SearchResults = Backbone.Collection.extend({
		model: Models.SearchItem,
		initialize: function() {
			this.fetch();
		},
		parse: function(response, options) {
			return response.result.results;
		}
	});
	return Models;
});

define(['jquery', 'underscore', 'backbone', 'model_search_item'], function($, _, Backbone, Models) {
	Models.SearchResults = Backbone.Collection.extend({
		model: Models.SearchItem,
		url: '/service/products/search/',
		initialize: function() {
			this.fetch();
		},
		parse: function(response, options) {
			return response.result.results;
		}
	});
	return Models;
});

Add URL back to Models.SearchResults.


'use strict';
/* jshint node:true */
/* global module, process, console, require */

var osenv = require('osenv'),
    Configstore = require('configstore');

var conf = new Configstore(process.env.SSH_TTY || osenv.user());

module.exports = {

  // TODO IMPORTANT: still missing timestamp check

  /**
   * Gets configuration parameter synchronously
   * @param {String} key
   * @public
   */
  getSync: function _getSync(key) {
    return conf.get(key);
  },

  /**
   * Sets the configuration parameter
   * If {{override}} is {{false}} it doesn' change
   * the existing param (default is {{true}})
   * @param {String} key
   * @param {String} value
   * @public
   */
  setSync: function _setSync(key, value) {
    conf.set(key, value);
  },

  /**
   * Gets all configuration parameters
   * for the current user
   * @returns {*|{get, set}}
   * @public
   */
  getAllSync: function _getAllSync() {
    return conf.all;
  }

};

'use strict';
/* jshint node:true */
/* global module, process, console, require */

var osenv = require('osenv'),
    Configstore = require('configstore');

var conf = new Configstore(process.env.SSH_TTY || osenv.user());

module.exports = {

  // TODO IMPORTANT: still missing timestamp check

  /**
   * Defaults:
   * Duration of user's CLI session (m)
   * Max number of hits to return
   */
  logseneEsHost: 'logsene-receiver.sematext.com',
  logseneUri: 'https://apps.sematext.com/users-web/api/v2',
  sessionDuration: 30,
  maxHits: 200,

  /**
   * Used to tidy up set and get commands a bit
   * @returns {string[]} all params
   * @public
   */
  getAvailableParams: function _getAvailableParams() {
    return['api-key', 'app-key', 'app-name', 'trace'];
  },

  /**
   * Gets configuration parameter synchronously
   * @param {String} key
   * @public
   */
  getSync: function _getSync(key) {
    return conf.get(key);
  },

  /**
   * Sets the configuration parameter
   * @param {String} key
   * @param {String} value
   * @public
   */
  setSync: function _setSync(key, value) {
    conf.set(key, value);
  },

  /**
   * Deletes the configuration parameter from the store
   * @param {String} key
   * @public
   */
  deleteSync: function _deleteSync(key) {
    conf.del(key);
  },

  /**
   * Gets all configuration parameters
   * for the current user
   * @returns {*|{get, set}}
   * @public
   */
  getAllSync: function _getAllSync() {
    return conf.all;
  }

};

Add additional global params; Add getAvailableParams method


// Copyright (c) Martin Costello, 2016. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

const puppeteer = require("puppeteer");
process.env.CHROME_BIN = puppeteer.executablePath();

module.exports = function (config) {
    config.set({

        autoWatch: false,
        concurrency: Infinity,

        browsers: ["ChromeHeadless"],
        frameworks: ["jasmine", "karma-typescript"],

        files: [
            "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js",
            "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.1/clipboard.min.js",
            "assets/scripts/**/*.ts"
        ],

        preprocessors: {
            "**/*.ts": ["karma-typescript"]
        },

        karmaTypescriptConfig: {
            tsconfig: "tsconfig.json"
        },

        htmlDetailed: {
            splitResults: false
        },

        plugins: [
            "karma-appveyor-reporter",
            "karma-chrome-launcher",
            "karma-html-detailed-reporter",
            "karma-jasmine",
            "karma-typescript"
        ],

        reporters: [
            "progress",
            "appveyor",
            "karma-typescript"
        ]
    });
};

// Copyright (c) Martin Costello, 2016. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

const puppeteer = require("puppeteer");
process.env.CHROME_BIN = puppeteer.executablePath();

module.exports = function (config) {
    config.set({

        autoWatch: false,
        concurrency: Infinity,

        browsers: ["ChromeHeadlessNoSandbox"],

        customLaunchers: {
            ChromeHeadlessNoSandbox: {
                base: "ChromeHeadless",
                flags: ["--no-sandbox"]
            }
        },

        frameworks: ["jasmine", "karma-typescript"],

        files: [
            "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js",
            "https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.1/clipboard.min.js",
            "assets/scripts/**/*.ts"
        ],

        preprocessors: {
            "**/*.ts": ["karma-typescript"]
        },

        karmaTypescriptConfig: {
            tsconfig: "tsconfig.json"
        },

        htmlDetailed: {
            splitResults: false
        },

        plugins: [
            "karma-appveyor-reporter",
            "karma-chrome-launcher",
            "karma-html-detailed-reporter",
            "karma-jasmine",
            "karma-typescript"
        ],

        reporters: [
            "progress",
            "appveyor",
            "karma-typescript"
        ]
    });
};

Fix Chrome headless when root on Linux


'use strict';

function DigitCanvas(element, width, height) {
    this.canvas = document.getElementById(element);
    this.canvas.width = width;
    this.canvas.height = height;
    this.context = this.canvas.getContext('2d');

    this.gridWidth = this.canvas.width/28;
    this.gridHeight = this.canvas.height/28;

    this.draw(testArray);
}

DigitCanvas.prototype.draw = function(valueArray) {
    for(var i = 0; i < valueArray.length; i++) {
        var cellX = i % 28;
        var cellY = Math.floor(i / 28);
        this.drawCell(valueArray[i], cellX, cellY);
    }
};

DigitCanvas.prototype.drawCell = function(value, cellX, cellY) {
    this.context.fillStyle = rgbToHex(255 - value, 255 - value, 255 - value);
    this.context.fillRect(this.gridWidth * cellX, this.gridHeight * cellY,
        this.gridWidth, this.gridHeight);
};

function componentToHex(c) {
    var hex = c.toString(16);
    return hex.length === 1 ? "0" + hex : hex;
}

function rgbToHex(r, g, b) {
    return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}

module.exports = DigitCanvas;

'use strict';

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

function DigitCanvas(element, width, height) {
    this.canvas = document.getElementById(element);
    this.canvas.width = width;
    this.canvas.height = height;
    this.context = this.canvas.getContext('2d');

    this.gridWidth = this.canvas.width/28;
    this.gridHeight = this.canvas.height/28;
}

DigitCanvas.prototype.draw = function(valueArray) {
    for(var i = 0; i < valueArray.length; i++) {
        var cellX = i % 28;
        var cellY = Math.floor(i / 28);
        this.drawCell(valueArray[i], cellX, cellY);
    }
};

DigitCanvas.prototype.drawCell = function(value, cellX, cellY) {
    this.context.fillStyle = Utils.rgbToHex(255 - value, 255 - value, 255 - value);
    this.context.fillRect(this.gridWidth * cellX, this.gridHeight * cellY,
        this.gridWidth, this.gridHeight);
};

module.exports = DigitCanvas;

Add object for drawing digits with canvas


window.deprecationWorkflow = window.deprecationWorkflow || {};
window.deprecationWorkflow.config = {
  workflow: [
    { handler: "silence", matchId: "ember-application.app-instance-container"},
    { handler: "silence", matchId: "ember-htmlbars.ember-handlebars-safestring"},
    { handler: "silence", matchId: "ember-getowner-polyfill.import"},
    { handler: "silence", matchId: "ember-metal.ember-k"},
  ]
};

window.deprecationWorkflow = window.deprecationWorkflow || {};
window.deprecationWorkflow.config = {
  workflow: [
  ]
};

Remove deprecations that have been resolved


var Class = require('../../utils/Class');
var WebAudioSound = require('./WebAudioSound');
var WebAudioSpriteSound = new Class({
    Extends: WebAudioSound,
    initialize: function WebAudioSpriteSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        WebAudioSound.call(this, manager, key, config);
        /**
         * Local reference to 'spritemap' object form json file generated by audiosprite tool.
         *
         * @property {object} spritemap
         */
        this.spritemap = manager.game.cache.json.get(key).spritemap;
        for (var markerName in this.spritemap) {
            this.addMarker({
                name: markerName,
                start: this.spritemap[markerName].start,
                duration: this.spritemap[markerName].end - this.spritemap[markerName].start,
                config: config
            });
        }
    }
});
module.exports = WebAudioSpriteSound;

var Class = require('../../utils/Class');
var WebAudioSound = require('./WebAudioSound');
var WebAudioSpriteSound = new Class({
    Extends: WebAudioSound,
    initialize: function WebAudioSpriteSound(manager, key, config) {
        if (config === void 0) { config = {}; }
        WebAudioSound.call(this, manager, key, config);
        /**
         * Local reference to 'spritemap' object form json file generated by audiosprite tool.
         *
         * @property {object} spritemap
         */
        this.spritemap = manager.game.cache.json.get(key).spritemap;
        for (var markerName in this.spritemap) {
            var marker = this.spritemap[markerName];
            this.addMarker({
                name: markerName,
                start: marker.start,
                duration: marker.end - marker.start,
                config: config
            });
        }
    }
});
module.exports = WebAudioSpriteSound;

Improve readability with local variable


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

Select.prototype._select = function(option, index) {
  this.model.set('value', option[this.key]);
  this.model.set('selected', option);
  this.model.set('selectedIndex', index);
  this._closeOptions();
};

Select.prototype._willSelect = function() {
  this.model.set('selectOptionsVisible', true);
};

Select.prototype._adjustDropdown = function() {
  var index = this.model.get('selectedIndex');
  var ul = this.optionListDropdown;

  if (index > 2) {
    index = index - 2;
    ul.scrollTop = (index * 40);
  } else {
    ul.scrollTop = 0;
  }
};

Select.prototype._addCloseListener = function () {
  var self = this;

  this.listener = function (e) {
    if (!self.optionListDropdown.contains(e.target)) self._closeOptions();
  }

  document.body.addEventListener('mouseup', this.listener);
};

Select.prototype._removeCloseListener = function() {
  document.body.removeEventListener('mouseup', this.listener);
};

Select.prototype._validate = function () {
  if(this.validator && typeof this.validator[this.fieldName].validate === 'function') {
    this.validator[this.fieldName].validate();
  }
};

Select.prototype._closeOptions = function () {
  this.model.set('selectOptionsVisible', false);
};

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

Select.prototype._select = function(option, index) {
  this.model.set('value', option[this.key]);
  this.model.set('selected', option);
  this.model.set('selectedIndex', index);
  this._closeOptions();
};

Select.prototype._willSelect = function() {
  this.model.set('selectOptionsVisible', true);
};

Select.prototype._adjustDropdown = function() {
  var index = this.model.get('selectedIndex');
  var ul = this.optionListDropdown;

  if (index > 2) {
    index = index - 2;
    ul.scrollTop = (index * 40);
  } else {
    ul.scrollTop = 0;
  }
};

Select.prototype._addCloseListener = function () {
  var self = this;

  this.listener = function (e) {
    if (!self.optionListDropdown.contains(e.target)) self._closeOptions();
  }

  document.body.addEventListener('mouseup', this.listener);
};

Select.prototype._removeCloseListener = function() {
  document.body.removeEventListener('mouseup', this.listener);
};

Select.prototype._validate = function () {
  if(this.validator) {
    var field = this.model.get('validator.' + this.fieldName);
    if (typeof field.validate === 'function') field.validate();
  }
};

Select.prototype._closeOptions = function () {
  this.model.set('selectOptionsVisible', false);
};

Fix fieldname could be path so validation not working


$(function() {
	// Calculate top of sidebar container in relation to window
	var stickyTop = $('.sidebar-container').offset().top;

	// Calculate the current position of window top (will change as user scrolls)
	$(window).scroll(function(){
		var windowTop = $(window).scrollTop();

		if (stickyTop < windowTop) {
			$('.sticky').css({ position: 'fixed', top: 0 });
		}
		else {
			$('.sticky').css('position', 'static');
		}
	});
});

$(document).ready(function(){

	$('#postcontent li').each(function(){
		$(this).after('<hr/>');
	});

	$('#postcontent li').each(function(){
		$(this).addClass('row');
	});

	$('#postcontent li p').each(function(){
		$(this).addClass('col-xs-12 col-md-6');
	});

});

Add grid class responsiveness to paragraphs.


Router.configure({
  layoutTemplate: 'layout',
  loadingTemplate: 'loading',
  notFoundTemplate: 'notFound',

  waitOn: function() {
    return Meteor.userId() ?
      Meteor.subscribe('Notifications', Meteor.userId()) :
      null
  }
});

Router.route('/', {
  name: 'projectsList',
  waitOn: function() {
    return Meteor.subscribe('Projects');
  }
});

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

Router.route('projects/:_id', {
  name: 'projectPage',
  data: function() {
    return Projects.findOne(this.params._id);
  }
});

Router.route('user/:userId', {
  name: 'userProfile',
  data: function() {
    return Meteor.users.findOne({_id: this.params.userId});
  }
});

Router.configure({
  layoutTemplate: 'layout',
  loadingTemplate: 'loading',
  notFoundTemplate: 'notFound',

  waitOn: function() {
    return Meteor.userId() ?
      Meteor.subscribe('Notifications', Meteor.userId()) :
      null
  }
});

Router.route('/', {
  name: 'projectsList',
  waitOn: function() {
    return [Meteor.subscribe('Projects'),
            Meteor.subscribe('Requests')];
  }
});

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

Router.route('projects/:_id', {
  name: 'projectPage',
  data: function() {
    return Projects.findOne(this.params._id);
  }
});

Router.route('user/:userId', {
  name: 'userProfile',
  data: function() {
    return Meteor.users.findOne({_id: this.params.userId});
  }
});

Add waitOn to subscription of requests


// @flow
/**
 * Переводит номер страницы с человеческого на программистский
 * @param {number} page человеческий номер
 * @returns {number} программистский номер
 */
function transformPageFromHumanToProgrammer(page: number): number {
    return page - 1;
}

export { transformPageFromHumanToProgrammer as default };

// @flow
/**
 * Переводит номер страницы с человеческого на программистский
 * @param {number} page человеческий номер
 * @returns {number} программистский номер
 */
function transformPageFromHumanToProgrammer(page: number): number {
    return page <= 0 ? 0 : page - 1;
}

export { transformPageFromHumanToProgrammer as default };

Fix bottom border for page


var fs = require('fs');

exports.name = 'logger';

exports.attach = function (options) {
  options = options || {};
  var monitor = this;

  if (options.outFile) {
    monitor.stdout = options.stdout || fs.createWriteStream(options.outFile, {
      flags: monitor.append ? 'a+' : 'w+',
      encoding: 'utf8',
      mode: 0644
    });
  }

  if (options.errFile) {
    monitor.stderr = options.stderr || fs.createWriteStream(options.errFile, {
      flags: monitor.append ? 'a+' : 'w+',
      encoding: 'utf8',
      mode: 0644
    });
  }

  monitor.on('start', startLogs);

  monitor.on('restart', startLogs);

  monitor.on('exit', function () {
    monitor.stdout.end();
    monitor.stderr.end();
  });

  function startLogs(child, childData) {
    if (monitor.child && !monitor.silent) {
      monitor.child.stdout.pipe(process.stdout, { end: false });
      monitor.child.stderr.pipe(process.stderr, { end: false });
      if (monitor.stdout) {
        monitor.child.stdout.pipe(monitor.stdout, { end: false });
      }
      if (monitor.stderr) {
        monitor.child.stderr.pipe(monitor.stderr, { end: false });
      }
    }
  }
};

var fs = require('fs');

exports.name = 'logger';

exports.attach = function (options) {
  options = options || {};
  var monitor = this;

  if (options.outFile) {
    monitor.stdout = options.stdout || fs.createWriteStream(options.outFile, {
      flags: monitor.append ? 'a+' : 'w+',
      encoding: 'utf8',
      mode: 0644
    });
  }

  if (options.errFile) {
    monitor.stderr = options.stderr || fs.createWriteStream(options.errFile, {
      flags: monitor.append ? 'a+' : 'w+',
      encoding: 'utf8',
      mode: 0644
    });
  }

  monitor.on('start', startLogs);

  monitor.on('restart', startLogs);

  monitor.on('exit', function () {
    if (monitor.stdout) {
      monitor.stdout.destroySoon();
    }
    if (monitor.stderr) {
      monitor.stderr.destroySoon();
    }
  });

  function startLogs(child, childData) {
    if (monitor.child && !monitor.silent) {
      monitor.child.stdout.pipe(process.stdout, { end: false });
      monitor.child.stderr.pipe(process.stderr, { end: false });
      if (monitor.stdout) {
        monitor.child.stdout.pipe(monitor.stdout, { end: false });
      }
      if (monitor.stderr) {
        monitor.child.stderr.pipe(monitor.stderr, { end: false });
      }
    }
  }
};

Destroy log file streams in a more intelligent way.


import Ember from 'ember';

export default Ember.Controller.extend({
  queryParams: ['environmentId','containerId'],
  environmentId: null,
  containerId: null,
  editing: false,

  actions: {
    done() {
      this.send('goToPrevious');
    },

    cancel() {
      this.send('goToPrevious');
    },
  }
});

import Ember from 'ember';

export default Ember.Controller.extend({
  queryParams: ['environmentId','containerId','hostId'],
  hostId: null,
  environmentId: null,
  containerId: null,
  editing: false,

  actions: {
    done() {
      this.send('goToPrevious');
    },

    cancel() {
      this.send('goToPrevious');
    },
  }
});

Fix add container to specific host


/**
 * @description
 * var app = angular.module('App', ['flow.provider'], function(flowFactoryProvider){
 *    flowFactoryProvider.defaults = {target: '/'};
 * });
 * @name flowFactoryProvider
 */
angular.module('flow.provider', [])
.provider('flowFactory', function() {
  'use strict';
  /**
   * Define the default properties for flow.js
   * @name flowFactoryProvider.defaults
   * @type {Object}
   */
  this.defaults = {};

  /**
   * Flow, MaybeFlow or NotFlow
   * @name flowFactoryProvider.factory
   * @type {function}
   * @return {Flow}
   */
  this.factory = function (options) {
    return new Flow(options);
  };

  /**
   * Define the default events
   * @name flowFactoryProvider.events
   * @type {Array}
   * @private
   */
  this.events = [];

  /**
   * Add default events
   * @name flowFactoryProvider.on
   * @function
   * @param {string} event
   * @param {Function} callback
   */
  this.on = function (event, callback) {
    this.events.push([event, callback]);
  };

  this.$get = function() {
    var fn = this.factory;
    var defaults = this.defaults;
    var events = this.events;
    return {
      'create': function(opts) {
        // combine default options with global options and options
        var flow = fn(angular.extend({}, defaults, opts));
        angular.forEach(events, function (event) {
          flow.on(event[0], event[1]);
        });
        return flow;
      }
    };
  };
});

/**
 * @description
 * var app = angular.module('App', ['flow.provider'], function(flowFactoryProvider){
 *    flowFactoryProvider.defaults = {target: '/'};
 * });
 * @name flowFactoryProvider
 */
angular.module('flow.provider', [])
.provider('flowFactory', function() {
  'use strict';
  /**
   * Define the default properties for flow.js
   * @name flowFactoryProvider.defaults
   * @type {Object}
   */
  this.defaults = {};

  /**
   * Flow, MaybeFlow or NotFlow
   * @name flowFactoryProvider.factory
   * @type {function}
   * @return {!Flow}
   */
  this.factory = function (options) {
    return new Flow(options);
  };

  /**
   * Define the default events
   * @name flowFactoryProvider.events
   * @type {Array}
   * @private
   */
  this.events = [];

  /**
   * Add default events
   * @name flowFactoryProvider.on
   * @function
   * @param {string} event
   * @param {Function} callback
   */
  this.on = function (event, callback) {
    this.events.push([event, callback]);
  };

  this.$get = function() {
    var fn = this.factory;
    var defaults = this.defaults;
    var events = this.events;
    return {
      'create': function(opts) {
        // combine default options with global options and options
        var flow = fn(angular.extend({}, defaults, opts));
        angular.forEach(events, function (event) {
          flow.on(event[0], event[1]);
        });
        return flow;
      }
    };
  };
});

Add non-nullable modifier to return type of functions never returning null


// Convert params from url into JSON object
export default function getParamsFromUrl(url) {
  const params = {};
  const { searchParams } = new URL(url);
  for (const [key, value] of searchParams.entries()) {
    params[key] = value;
  }
  return params;
}

// Convert params from url into JSON object
export default function getParamsFromUrl(url) {
  const params = {};
  const urlObj = new URL(url);
  const { searchParams, hostname } = urlObj;
  if (hostname === 'youtu.be') {
    const { pathname, search } = urlObj;
    const videoId = pathname.substring(1);
    const videoStartTime = search.substring(3);
    params['v'] = videoId;
    if (!isNaN(videoStartTime)) {
      params['t'] = videoStartTime;
    }
  } else {
    for (const [key, value] of searchParams.entries()) {
      params[key] = value;
    }
  }
  return params;
}

Fix edge case where video id is given in different format


import React from 'react'
import {withRouter} from 'react-router-dom'
import '../styles/App.css'

const BackButton = ({history}) => (

 history.goBack()}> < < Back

)

export default withRouter(BackButton)

import React from 'react'
import {withRouter} from 'react-router-dom'
import '../styles/App.css'

const BackButton = ({history}) => (

     history.goBack()}> < < Back  |
     history.push('/newsfeed')}> Home

)

export default withRouter(BackButton)

Move Home navigation to Back button


"use strict";

$("[data-react-class]").each(function() {
  var componentName = this.getAttribute("data-react-class"),
      constructor = window[componentName],
      propsJson = this.getAttribute("data-react-props"),
      props = propsJson && JSON.parse(propsJson);

  ReactDOM.render(
    React.createElement(
      constructor,
      props
    ),
    this
  );
});

var currentAjaxRequest = null;

function search(text) {

  if(null !== currentAjaxRequest) {
    currentAjaxRequest.abort();
  }

  currentAjaxRequest = $.get('/practices', {search: text});
  return currentAjaxRequest;
}

"use strict";

function attachReactComponents() {
  var nodes = document.querySelectorAll("[data-react-class]"),
      index;

  for (index = 0; index < nodes.length; ++index) {
    var node = nodes[index],
        componentName = node.getAttribute("data-react-class"),
        constructor = window[componentName],
        propsJson = node.getAttribute("data-react-props"),
        props = propsJson && JSON.parse(propsJson);

    ReactDOM.render(
      React.createElement(
        constructor,
        props
      ),
      node
    );
  }
}

attachReactComponents();

var currentAjaxRequest = null;

function search(text) {

  if(null !== currentAjaxRequest) {
    currentAjaxRequest.abort();
  }

  currentAjaxRequest = $.get('/practices', {search: text});
  return currentAjaxRequest;
}

Stop using jQuery to attach React components


/// <binding BeforeBuild='bower, concat' ProjectOpened='bower:install' />
/*
This file in the main entry point for defining grunt tasks and using grunt plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409
*/
module.exports = function (grunt) {
    grunt.initConfig({
        bower: {
            install: {
                options: {
                    targetDir: "wwwroot/lib",
                    layout: "byComponent",
                    cleanTargetDir: true
                }
            }
        },

        concat: {
            js: {
                src: "Assets/js/*.js",
                dest: "wwwroot/js/site.js"
            },

            css: {
                src: "Assets/css/*.css",
                dest: "wwwroot/css/site.css"
            }
        },
    });

    grunt.registerTask("default", ["bower:install"]);

    grunt.loadNpmTasks("grunt-bower-task");
    grunt.loadNpmTasks("grunt-contrib-concat");
};

/// <binding BeforeBuild='bower, concat' ProjectOpened='bower:install' />
/*
This file in the main entry point for defining grunt tasks and using grunt plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkID=513275&clcid=0x409
*/
module.exports = function (grunt) {
    grunt.initConfig({
        bower: {
            install: {
                options: {
                    targetDir: "wwwroot/lib",
                    layout: "byComponent",
                    cleanTargetDir: true
                }
            }
        },

        concat: {
            js: {
                src: "Assets/js/*.js",
                dest: "wwwroot/js/site.js"
            },

            css: {
                src: "Assets/css/*.css",
                dest: "wwwroot/css/site.css"
            }
        },
    });

    grunt.registerTask("default", ["bower:install", "concat"]);

    grunt.loadNpmTasks("grunt-bower-task");
    grunt.loadNpmTasks("grunt-contrib-concat");
};

Add concat step to default grunt task


window.onload = function() {
  var path = require('path');
  var ipc = require('ipc');
  try {
    // Skip "?loadSettings=".
    var loadSettings = JSON.parse(decodeURIComponent(location.search.substr(14)));

    // Start the crash reporter before anything else.
    if (process.platform != 'win32')
      require('crash-reporter').start({
        productName: 'Atom',
        companyName: 'GitHub',
        // By explicitly passing the app version here, we could save the call
        // of "require('remote').require('app').getVersion()".
        extra: {_version: loadSettings.appVersion}
      });

    require('vm-compatibility-layer');
    require('coffee-script').register();
    require(path.resolve(__dirname, '..', 'src', 'coffee-cache')).register();
    require(loadSettings.bootstrapScript);
    ipc.sendChannel('window-command', 'window:loaded')
  }
  catch (error) {
    var currentWindow = require('remote').getCurrentWindow();
    currentWindow.setSize(800, 600);
    currentWindow.center();
    currentWindow.show();
    currentWindow.openDevTools();
    console.error(error.stack || error);
  }
}

window.onload = function() {
  var path = require('path');
  var ipc = require('ipc');
  try {
    // Skip "?loadSettings=".
    var loadSettings = JSON.parse(decodeURIComponent(location.search.substr(14)));

    // Start the crash reporter before anything else.
    require('crash-reporter').start({
      productName: 'Atom',
      companyName: 'GitHub',
      // By explicitly passing the app version here, we could save the call
      // of "require('remote').require('app').getVersion()".
      extra: {_version: loadSettings.appVersion}
    });

    require('vm-compatibility-layer');
    require('coffee-script').register();
    require(path.resolve(__dirname, '..', 'src', 'coffee-cache')).register();
    require(loadSettings.bootstrapScript);
    ipc.sendChannel('window-command', 'window:loaded')
  }
  catch (error) {
    var currentWindow = require('remote').getCurrentWindow();
    currentWindow.setSize(800, 600);
    currentWindow.center();
    currentWindow.show();
    currentWindow.openDevTools();
    console.error(error.stack || error);
  }
}

Revert "Don't start crash reporter on Windows."


/*

MessageRepeat plugin - Desigened to forward incomming messages to another server

*/
var request = require('request')
var logger = require('../log')

function run (trigger, scope, data, config, callback) {
  if (config.repeatURI) {
    var uri = config.repeatURI
    var apikey = config.repeatAPIKEY
    var messageData = {
      address: data.capcode,
      message: data.message,
      source: data.source
    }
    request.post({
      url: uri,
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        "content-type": "application/json",
        'User-Agent': 'PagerMon Plugin - Message Repeat',
        apikey: apikey,
        json: true
      },
      form: messageData
    }, function (error, response, body) {
      //if (!error && response.statusCode === 200) {
        //logger.main.info('MessageRepeat: Message Sent')
      //} else {
      //  logger.main.error('MessageRepeat: ' + error + response.statusCode + response.statusText)
      //}
      console.log('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
    })
    callback()
  } else {
    callback()
  }
}

module.exports = {
  run: run
}

/*

MessageRepeat plugin - Desigened to forward incomming messages to another server

*/
var request = require('request')
var logger = require('../log')

function run (trigger, scope, data, config, callback) {
  if (config.repeatURI) {
    var uri = config.repeatURI
    var apikey = config.repeatAPIKEY
    var messageData = {
      address: data.capcode,
      message: data.message,
      source: data.source
    }
    request.post({
      url: uri,
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        "content-type": 'application/json',
        'User-Agent': 'PagerMon Plugin - Message Repeat',
        apikey: apikey,
        json: true
      },
      form: messageData
    }, function (error, response, body) {
      if (!error && response.statusCode === 200) {
        logger.main.info('MessageRepeat: Message Sent')
      } else {
        logger.main.error('MessageRepeat: ' + error + response.statusCode + response.statusText)
      }
    })
    callback()
  } else {
    callback()
  }
}

module.exports = {
  run: run
}

Format everything nicely + cleanup


/*
** Last Revision: 1/8/16
**
*/

Router.route('/', function(){
  this.layout('main');
  this.render('page');
});

Router.route('/create', function() {
  this.layout('main');
  this.render('create_listing');
});

Router.route('/view', function() {
  this.layout('main');
  this.render('view_listing');
});

/*
** Last Revision: 1/8/16
**
*/

Router.route('/', function(){
  this.layout('main');
  this.render('page');
});

Router.route('/create', function() {
  this.layout('main');
  this.render('create_listing');
});

Router.route('/view/:id', function() {
  this.layout('main');
  this.render('view_listing');
});

Add id to view URL


var express = require('express');
var bodyParser = require('body-parser');
var middleware = reuqire('./middleware');
var verifyToken = middleware.verifyToken;
var ignoreBot = middleware.ignoreBot;

var Bot = require('./irc');

var app = module.exports = express();
var bot = new Bot();

app.set('port', process.env.PORT || 3000);
app.use(bodyParser.urlencoded({
  extended: true
}));

app.post('/send', verifyPost, ignoreBot, function(req, res) {
  var channel = req.body.channel_name;
  var author = req.body.user_name;
  var message = req.body.text;

  bot.sendMessage(author, channel, message);
  res.status(202).send();
});

var express = require('express');
var bodyParser = require('body-parser');
var middleware = require('./middleware');
var verifyToken = middleware.verifyToken;
var ignoreBot = middleware.ignoreBot;

var Bot = require('./irc');

var app = module.exports = express();
var bot = new Bot();

app.set('port', process.env.PORT || 3000);
app.use(bodyParser.urlencoded({
  extended: true
}));

app.post('/send', verifyToken, ignoreBot, function(req, res) {
  var channel = req.body.channel_name;
  var author = req.body.user_name;
  var message = req.body.text;

  bot.sendMessage(author, channel, message);
  res.status(202).send();
});

Include middleware's in post route


var http = require('http');

var courseraHttpHandler = function(url, processor, callback) {
    http.get(url, function(response) {
        var str = '';
        response.on('data', function (chunk) {
            str += chunk;
        });
        response.on('end', function () {
            var processedStr = str.trim().split('\r\n').map( processor );
            callback( processedStr );
        });
    });
}

var strToInt = function (str) {
    return parseInt(str);
}
/*
 * Convert from coursera sample format to javascript array.
 * e.g :
 *
 * a.txt :
 *
 * 111
 * 222
 * 333
 * 444
 *
 * converts to
 *
 * [111,222,333,444]
 * */

exports.getNumberArray = function (url, callback) {
    courseraHttpHandler(url, strToInt, callback);

};

exports.getAdjacencylist = function (url, callback) {
    courseraHttpHandler(url, function (str) {
        return str.trim().split('\t').map( strToInt );
    }, callback);
}

var http = require('http');

var courseraHttpHandler = function(url, lineProcessor, callback) {
    http.get(url, function(response) {
        var str = '';
        response.on('data', function (chunk) {
            str += chunk;
        });
        response.on('end', function () {
            var processedStr = str.trim().split('\r\n').map( lineProcessor );
            callback( processedStr );
        });
    });
}

var strToInt = function (str) {
    return parseInt(str);
}
/*
 * Convert from coursera sample format to javascript array.
 * e.g :
 *
 * a.txt :
 *
 * 111
 * 222
 * 333
 * 444
 *
 * converts to
 *
 * [111,222,333,444]
 * */

exports.getNumberArray = function (url, callback) {
    courseraHttpHandler(url, strToInt, callback);

};

exports.getAdjacencylist = function (url, callback) {
    courseraHttpHandler(url, function (str) {
        return str.trim().split(/\s+/).map( strToInt );
    }, callback);
}

Refactor variable name, use regex instead of string for split parameter.


var Reporter = require('../reporter');

/**
 * NullReporter outputs nothing
 * @class  NullReporter
 * @param {Object} options hash of options interpreted by reporter
 */
module.exports = Reporter.extend({
  report: function(/* coverageData */) {
  }
});

var Reporter = require('../reporter');

/**
 * NullReporter outputs nothing
 * @class  NullReporter
 * @param {Object} options hash of options interpreted by reporter
 */
module.exports = Reporter.extend({
  report: function(/* coverageData */) {
  },
  processOptions: function(/* options */) {
  }
});

Fix so null reporter builds again.


const webpack = require("webpack");

module.exports = {
  target: "node",
  externals: ["jquery", "moment"],
  resolve: {
    extensions: [".ts", ".js"]
  },
  devtool: "#inline-cheap-module-source-map",
  module: {
    loaders: [
      { test: /\.ts$/, loader: "ts-loader" },
      { test: /\.scss$/, loaders: ['css-loader/locals?modules', 'sass-loader'] }
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
        $: "jQuery",
        jQuery: "jQuery"
    })
  ]
}

const webpack = require("webpack");

module.exports = {
  target: "node",
  externals: ["jquery", "moment"],
  resolve: {
    extensions: [".ts", ".js"]
  },
  devtool: "#inline-cheap-module-source-map",
  module: {
    loaders: [
      { test: /\.ts$/, loader: "ts-loader" },
      { test: /\.scss$/, loaders: ['css-loader/locals?modules', 'sass-loader'] }
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
        $: "jQuery"
    })
  ]
}

Update Test Confiig Plugins to Maybe Fix JQuery Module


'use strict';

var Promise = require('bluebird')

module.exports = new Promise(function(resolve) {
	if (document.readyState === 'complete') {
		resolve()
	} else {
		function onReady() {
			resolve()
			document.removeEventListener('DOMContentLoaded', onReady, true)
			window.removeEventListener('load', onReady, true)
		}
		document.addEventListener('DOMContentLoaded', onReady, true)
		window.addEventListener('load', onReady, true)
	}
})

'use strict';

var Promise = require('bluebird')

module.exports = new Promise(function(resolve) {
	function onReady() {
		resolve()
		document.removeEventListener('DOMContentLoaded', onReady, true)
		window.removeEventListener('load', onReady, true)
	}

	if (document.readyState === 'complete') {
		resolve()
	} else {
		document.addEventListener('DOMContentLoaded', onReady, true)
		window.addEventListener('load', onReady, true)
	}
})

Move where onReady is declared to shut up JSHint


/** @jsx React.DOM */

define(
  [
    'react',
    'backbone'
  ],
  function (React, Backbone) {

    return React.createClass({

      propTypes: {
        volume: React.PropTypes.instanceOf(Backbone.Model).isRequired,
        instances: React.PropTypes.instanceOf(Backbone.Collection).isRequired
      },

      render: function () {
        var status = this.props.volume.get('status'),
            placeholderMessage = status;

        if(status === "available"){
          placeholderMessage = "Unattached";
        }else if(status === "in-use"){
          var attachData = this.props.volume.get('attach_data');
          var instance = this.props.instances.get(attachData.instance_id);
          placeholderMessage = "Attached to " + instance.get('name') + " as device " + attachData.device;
        }

        return (
          <span>
            {placeholderMessage}
          </span>
        );
      }

    });

  });

/** @jsx React.DOM */

define(
  [
    'react',
    'backbone'
  ],
  function (React, Backbone) {

    return React.createClass({

      propTypes: {
        volume: React.PropTypes.instanceOf(Backbone.Model).isRequired,
        instances: React.PropTypes.instanceOf(Backbone.Collection).isRequired
      },

      render: function () {
        var status = this.props.volume.get('status'),
            placeholderMessage = status;

        if(status === "available"){
          placeholderMessage = "Unattached";
        }else if(status === "in-use"){
          var attachData = this.props.volume.get('attach_data');
          var instance = this.props.instances.get(attachData.instance_id);
          if(instance) {
            placeholderMessage = "Attached to " + instance.get('name') + " as device " + attachData.device;
          }else{
            placeholderMessage = "Attached to instance outside project (" + attachData.instance_id + ")";
          }
        }

        return (
          <span>
            {placeholderMessage}
          </span>
        );
      }

    });

  });

Add message when volume attached to instance outside project


import settings from './settings';
import { SCALE_MODES } from './const';
import { is_webgl_supported } from './utils/index';
import { loader_use_procs } from 'engine/registry';
import WebGLRenderer from './renderers/WebGLRenderer';
import texture_parser from 'engine/textures/texture_parser';

// Texture parser is mandatory
loader_use_procs.push(texture_parser);

export default class VisualServer {
    constructor() {
        this.is_initialized = false;

        this.renderer = null;
    }

    init(config) {
        if (this.is_initialized) {
            return;
        }
        this.is_initialized = true;

        if (config.scale_mode === 'linear') {
            settings.SCALE_MODE = SCALE_MODES.LINEAR;
        } else {
            settings.SCALE_MODE = SCALE_MODES.NEAREST;
        }

        if (!is_webgl_supported()) {
            throw 'Voltar only support WebGL rendering!';
        } else {
            this.renderer = new WebGLRenderer(config);
        }
    }
    render(viewport) {
        this.renderer.render(viewport, undefined, true, undefined, true);
    }
}

import settings from './settings';
import { SCALE_MODES } from './const';
import { is_webgl_supported } from './utils/index';
import { loader_use_procs } from 'engine/registry';
import WebGLRenderer from './renderers/WebGLRenderer';
import texture_parser from 'engine/textures/texture_parser';
import spritesheet_parser from 'engine/textures/spritesheet_parser';

// Texture and spritesheet parsers are mandatory
loader_use_procs.push(texture_parser);
loader_use_procs.push(spritesheet_parser);

export default class VisualServer {
    constructor() {
        this.is_initialized = false;

        this.renderer = null;
    }

    init(config) {
        if (this.is_initialized) {
            return;
        }
        this.is_initialized = true;

        if (config.scale_mode === 'linear') {
            settings.SCALE_MODE = SCALE_MODES.LINEAR;
        } else {
            settings.SCALE_MODE = SCALE_MODES.NEAREST;
        }

        if (!is_webgl_supported()) {
            throw 'Voltar only support WebGL rendering!';
        } else {
            this.renderer = new WebGLRenderer(config);
        }
    }
    render(viewport) {
        this.renderer.render(viewport, undefined, true, undefined, true);
    }
}

Load spritesheet middleware for atlas support


import angular from 'angular';
import uiRouter from 'angular-ui-router';
import Common from './common/common';
import Components from './components/components';
import AppComponent from './app.component';
import 'normalize.css';
import SmartOnFhir from './components/smartOnFhir/smartOnFhir';
import LabResultsService from './services/labResults/labResults';

angular.module('app', [
        uiRouter,
        Common.name,
        Components.name
    ])
    .config(($locationProvider) => {
        "ngInject";
        // @see: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions
        // #how-to-configure-your-server-to-work-with-html5mode
        $locationProvider.html5Mode(true).hashPrefix('!');
    })
    .run(() => {
        // Authenticate (if necessary)
        SmartOnFhir.instance().run();
    })
    .service('LabResultsService', LabResultsService)

    .component('app', AppComponent);

import angular from 'angular';
import uiRouter from 'angular-ui-router';
import Common from './common/common';
import Components from './components/components';
import AppComponent from './app.component';
import 'normalize.css';
import SmartOnFhir from './components/smartOnFhir/smartOnFhir';
import LabResultsService from './services/labResults/labResults';

angular.module('app', [
        uiRouter,
        Common.name,
        Components.name
    ])
    .config(($locationProvider) => {
        "ngInject";
        // @see: https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions
        // #how-to-configure-your-server-to-work-with-html5mode
        $locationProvider.html5Mode(true).hashPrefix('!');
    })
    .run(() => {
        // Authenticate (if necessary)
        //SmartOnFhir.instance().run();
    })
    .service('LabResultsService', LabResultsService)

    .component('app', AppComponent);

Disable smart on fhir (auth)


/*
 * @module Entity
 */
'use strict';

var Node = require('./node')

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

/**
 * @class Entity
 * @extends Node
 * @see [Node](./node.md)
 * @see [Constructor Conventions](../conventions-constructor.md)
 * @param {Object} opts Relevant opts: _none_. Rest passed to `Node`.
 */
class Entity extends Node {
  constructor() {
    super()

    /**
     * @property {Date} created Date corresponding to creation time of the Entity.
     */
    this.created = new Date()

  }

}

module.exports = Entity

/*
 * @module Entity
 */
'use strict';

var Node = require('./node')

var util = require('./util')

/**
 * @class Entity
 * @extends Node
 * @see [Node](./node.md)
 * @see [Constructor Conventions](../conventions-constructor.md)
 */
class Entity extends Node {
  constructor() {

    var defaults =
      {
      }

    var [ opts, rest ] = util.parseOpts(arguments[0], defaults)

    super(rest)

    /**
     * @property {Date} created Date corresponding to creation time of the Entity.
     */
    this.created = new Date()

  }

}

module.exports = Entity

Clean up and prepare Entity class


import React, { Component } from 'react'

export default (props) => {
  let {
    selectedOption,
    selectedLabel,
    placeholder,
    disabled,
    onClick,
    handleOnChange,
    handleKeyDown,
    handleOnFocus,
  } = props

  let value = props.searchTerm
  if (value === null) {
    value = selectedOption ? (selectedOption[selectedLabel] || '') : ''
  }

  return (
    <div
      className='powerselect__trigger'
      onClick={onClick}
    >
      <input
        className='powerselect__trigger-input'
        autoComplete='off'
        spellCheck='false'
        placeholder={props.placeholder}
        value={value}
        disabled={disabled}
        onChange={handleOnChange}
        onKeyDown={handleKeyDown}
        onFocus={handleOnFocus}
      />
      <span
        className='powerselect__trigger-status'
      ></span>
    </div>
  )
}

import React, { Component } from 'react'

export default (props) => {
  let {
    selectedOption,
    selectedLabel,
    placeholder,
    disabled,
    onClick,
    handleOnChange,
    handleKeyDown,
    handleOnFocus,
  } = props

  let value = props.searchTerm

  if (value === null) {
    value = ''
    if (selectedOption) {
      if (typeof selectedLabel === 'function') {
        value = selectedLabel(selectedOption)
      } else {
        value = selectedOption[selectedLabel]
      }
    }
  }

  return (
    <div
      className='powerselect__trigger'
      onClick={onClick}
    >
      <input
        className='powerselect__trigger-input'
        autoComplete='off'
        spellCheck='false'
        placeholder={props.placeholder}
        value={value}
        disabled={disabled}
        onChange={handleOnChange}
        onKeyDown={handleKeyDown}
        onFocus={handleOnFocus}
      />
      <span
        className='powerselect__trigger-status'
      ></span>
    </div>
  )
}

Allow selectedLabel to be func


import React, { Component } from 'react'

//class-based component (ES6)
class SearchBar extends Component {
  constructor(props) {
    super(props);

    this.state = { searchInput: '' } //This is the only time we set state like this. We usually use setState
  }

  render() { //method definition in ES6
    return (
      <div>
      <input onChange={event => this.setState({ searchInput: event.target.value })} />
      </div>
    )
  }

}

export default SearchBar;

import React, { Component } from 'react'

//class-based component (ES6)
class SearchBar extends Component {
  constructor(props) {
    super(props);

    this.state = { searchInput: 'Starting value' } //This is the only time we set state like this. We usually use setState
  }

  render() { //method definition in ES6
    //Add 'value' to make it a controlled component: controlled by the state -- more declarative syntax
    return (
      <div>
      <input
        value={this.state.searchInput}
        onChange={event => this.setState({ searchInput: event.target.value })} />
      </div>
    )
  }

}

export default SearchBar;

Make it a controlled component


function commentsMap(comment, parent, op, score=4, nthSibling=0, nthNest=0, siblingHidden=false) {
  var i = 0;
  var length;

  if (comment == undefined) {
    return;
  }

  // Start degrading
  score--;

  // Show longer threads involving op
  if (comment.author == op || comment.gilded) {
    score++;
  // Show longer threads if a parent has a higher score
  } else if (parent && comment.score > (parent.score * (nthSibling + nthNest + 1))) {
    score++;
  }

  if (nthSibling > score || nthSibling > 5 || nthNest > 5) {
    comment.hidden = true;
  }

  // If score is low, or if it is a long sibling chain, hide
  if (score < 0 || (parent && parent.hidden) || siblingHidden) {
    comment.hidden = true;
  }

  if (comment.hidden && parent && !parent.hidden && !siblingHidden) {
    comment.firstHidden = true;
  }

  comment.hideScore = score;

  if (!comment.replies) {
    return comment;
  }

  length = comment.replies.length;
  i = 0;

  // Increment the nesting level before we recurse through children
  nthNest++;

  comment.replies = comment.replies.map(function(c, i) {
    var sh = siblingHidden;

    if (i > 0) {
      sh = comment.replies[i-1].hidden;
    }

    return commentsMap(c, comment, op, score, i, nthNest, sh);
  });

  return comment;
}

export default commentsMap;

function commentsMap(comment, parent, op, score=4, nthSibling=0, nthNest=0, siblingHidden=false) {
  var i = 0;
  var length;

  if (comment == undefined) {
    return;
  }

  // Start degrading
  score--;

  // Show longer threads involving op
  if (comment.author == op || comment.gilded) {
    score++;
  // Show longer threads if a parent has a higher score
  } else if (parent && comment.score > (parent.score * (nthSibling + nthNest + 1))) {
    score++;
  }

  if (nthSibling > score || nthSibling > 5 || nthNest > 5) {
    comment.hidden = true;
  }

  // If score is low, or if it is a long sibling chain, hide
  if (score < 0 || (parent && parent.hidden) || siblingHidden) {
    comment.hidden = true;
  }

  if (comment.hidden && parent && !parent.hidden && !siblingHidden) {
    comment.firstHidden = true;
  }

  comment.hideScore = score;

  if (!comment.replies) {
    return comment;
  }

  length = comment.replies.length;
  i = 0;

  // Increment the nesting level before we recurse through children
  nthNest++;

  comment.replies = comment.replies.map(function(c, i) {
    var sh = siblingHidden;

    if (i > 0 && comment.replies[i-1]) {
      sh = comment.replies[i-1].hidden;
    }

    return commentsMap(c, comment, op, score, i, nthNest, sh);
  });

  return comment;
}

export default commentsMap;

Fix break in commentmap where first sibling is null


const { join } = require('path')
const { cache_path: cachePath } = require('../config')
const { nodeEnv } = require('../env')

// Compile standard ES features for JS in node_modules with Babel.
module.exports = {
  test: /\.(js|mjs)$/,
  exclude: /@babel(?:\/|\\{1,2})runtime/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        babelrc: false,
        presets: [['@babel/preset-env', { modules: false }]],
        cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
        cacheCompression: nodeEnv === 'production',
        compact: false,
        sourceMaps: false
      }
    }
  ]
}

const { join } = require('path')
const { cache_path: cachePath } = require('../config')
const { nodeEnv } = require('../env')

// Compile standard ES features for JS in node_modules with Babel.
module.exports = {
  test: /\.(js|mjs)$/,
  include: /node_modules/,
  exclude: /@babel(?:\/|\\{1,2})runtime/,
  use: [
    {
      loader: 'babel-loader',
      options: {
        babelrc: false,
        presets: [['@babel/preset-env', { modules: false }]],
        cacheDirectory: join(cachePath, 'babel-loader-node-modules'),
        cacheCompression: nodeEnv === 'production',
        compact: false,
        sourceMaps: false
      }
    }
  ]
}

Configure the nodeModules loader to do what its name suggests


import React, {Component} from 'react';
import {connect} from 'react-redux';
import './list.css';

export class List extends Component {
    render() {
        return (

                {this.props.countries.map(country => {
                    return (

{country.name}

                    )
                })}

        );
    }
}

const mapStateToProps = (state) => {
    const countries = state.countries;
    return {
        countries
    };
};

export default connect(mapStateToProps)(List)

Add alt tag to image


jQuery(document).ready(function($){
  $('notices_primary').infinitescroll({
    debug: true,
    infiniteScroll  : false,
    nextSelector    : 'body#public li.nav_next a,'+
                      'body#all li.nav_next a,'+
                      'body#showstream li.nav_next a,'+
                      'body#replies li.nav_next a,'+
                      'body#showfavorites li.nav_next a,'+
                      'body#showgroup li.nav_next a,'+
                      'body#favorited li.nav_next a',
    loadingImg      : $('address .url')[0].href+'plugins/InfiniteScroll/ajax-loader.gif',
    text            : "Loading the next set of posts...",
    donetext        : "Congratulations, you\'ve reached the end of the Internet.",
    navSelector     : ".pagination",
    contentSelector : "#notices_primary ol.notices",
    itemSelector    : "#notices_primary ol.notices li"
    },function(){
        NoticeAttachments();
        NoticeReply();
        NoticeFavors();
    });
});

jQuery(document).ready(function($){
  $('notices_primary').infinitescroll({
    debug: true,
    infiniteScroll  : false,
    nextSelector    : 'body#public li.nav_next a,'+
                      'body#all li.nav_next a,'+
                      'body#showstream li.nav_next a,'+
                      'body#replies li.nav_next a,'+
                      'body#showfavorites li.nav_next a,'+
                      'body#showgroup li.nav_next a,'+
                      'body#favorited li.nav_next a',
    loadingImg      : $('address .url')[0].href+'plugins/InfiniteScroll/ajax-loader.gif',
    text            : "Loading the next set of posts...",
    donetext        : "Congratulations, you\'ve reached the end of the Internet.",
    navSelector     : ".pagination",
    contentSelector : "#notices_primary ol.notices",
    itemSelector    : "#notices_primary ol.notices li"
    },function(){
        SN.Init.Notices();
    });
});

Fix to work with csarven's changes to util.js


'use strict';

function Specs() {
    //console.log('After:', this.World);

    this.Given(/^I am a thingamabob client on port (\d*)$/, function(port, callback) {
        this.createClient(port, callback);
    });

    this.Given(/^a thingamabob server on port (\d*)$/, function(port, callback) {
        this.createServer(port, callback);
    });

    this.When(/^I send a CONNECT message$/, function(callback) {
        console.log('client:', this.Client);
        console.log('server:', this.Server);
        this.Client.connect(this.Server.host, this.Server.port, callback);
    });

    this.Then(/^I receive a CONACK reply$/, function(callback) {
        this.Client.messages.should.have.lengthOf(1);
        this.Client.messages[0].msgType.should.eql('CONACK');
        callback.pending();
    });
}

module.exports = Specs;

'use strict';

function Specs() {
    //console.log('After:', this.World);

    this.Given(/^I am a thingamabob client on port (\d*)$/, function(port, callback) {
        this.createClient(port, callback);
    });

    this.Given(/^a thingamabob server on port (\d*)$/, function(port, callback) {
        this.createServer(port, callback);
    });

    this.When(/^I send a CONNECT message$/, function(callback) {
        console.log('client:', this.Client);
        console.log('server:', this.Server);
        this.Client.connect(this.Server.host, this.Server.port, callback);
    });

    this.Then(/^I receive a CONACK reply$/, function(callback) {
        var client = this.Client;
        setTimeout(function() {
            client.messages.should.have.lengthOf(1);
            client.messages[0].msgType.should.eql('CONACK');
            callback();
        }, 100);
    });
}

module.exports = Specs;

Add setTimeout to the Then step to ensure processing before assert.


'use strict';

var express = require('express');
var controller = require('./user.controller');
var config = require('../../config/environment');
var auth = require('../../auth/auth.service');

var router = express.Router();

router.get('/', auth.hasRole('admin'), controller.index);
router.delete('/:id', auth.hasRole('admin'), controller.destroy);
router.get('/me', auth.isAuthenticated(), controller.me);
router.put('/:id/password', auth.isAuthenticated(), controller.changePassword);
router.get('/:id', auth.isAuthenticated(), controller.show);
router.post('/', controller.create);

module.exports = router;

'use strict';

var express = require('express');
var controller = require('./user.controller');
var config = require('../../config/environment');
var auth = require('../../auth/auth.service');

var router = express.Router();

router.get('/', auth.isAuthenticated(), controller.index);
router.delete('/:id', auth.hasRole('admin'), controller.destroy);
router.get('/me', auth.isAuthenticated(), controller.me);
router.put('/:id/password', auth.isAuthenticated(), controller.changePassword);
router.get('/:id', auth.isAuthenticated(), controller.show);
router.post('/', controller.create);

module.exports = router;

Change users API auth rules


module.exports = function(config) {
  config.set({
    frameworks: ['mocha', 'chai', 'karma-typescript', 'sinon'],
    browsers: ['ChromeHeadless', 'FirefoxHeadless'],
    files: [
      './node_modules/@webcomponents/webcomponentsjs/bundles/webcomponents-sd-ce.js',
      { pattern: 'src/*.ts' },
      { pattern: 'test/*.ts' },
    ],
    reporters: ['progress', 'karma-typescript'],
    singleRun: true,
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    concurrency: Infinity,
    preprocessors: {
      '**/*.ts': ['karma-typescript'],
    },
    karmaTypescriptConfig: {
      compilerOptions: {
        target: 'esnext',
        lib: ['esnext', 'dom'],
      },
      bundlerOptions: {
        transforms: [require('karma-typescript-es6-transform')({ presets: 'env' })],
      },
    },
  });
}

module.exports = function(config) {
  config.set({
    frameworks: ['mocha', 'chai', 'karma-typescript', 'sinon'],
    browsers: ['ChromeHeadless', 'FirefoxHeadless'],
    files: [
      './node_modules/@webcomponents/webcomponentsjs/bundles/webcomponents-sd-ce.js',
      { pattern: 'src/*.ts' },
      { pattern: 'test/*.ts' },
    ],
    reporters: ['progress', 'karma-typescript'],
    singleRun: true,
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    concurrency: Infinity,
    preprocessors: {
      '**/*.ts': ['karma-typescript'],
    },
    karmaTypescriptConfig: {
      compilerOptions: {
        target: 'esnext',
        lib: ['esnext', 'dom'],
      },
      bundlerOptions: {
        transforms: [require('karma-typescript-es6-transform')({ presets: ['@babel/preset-env'] })],
      },
    },
  });
}

Update karma typescript es6 transform presets


define([
  'http',
  'url'
],
function (http, url) {
  var renderPng = function (req, res) {
    var options = url.parse(renderPng.getScreenshotPath(req.url));
    http.get(options, function (screenshot) {
      res.status(screenshot.statusCode);
      for (var i in screenshot.headers) {
        res.setHeader(i, screenshot.headers[i]);
      }
      screenshot.on("data", function(chunk) {
        res.write(chunk);
      });
      screenshot.on("end", function () {
        res.end();
      });
    }).on('error', function (e) {
      res.status(500);
      res.send("Got error: " + e.message);
    });
  };

  if (global.config) {
    renderPng.screenshotServiceUrl = config.screenshotServiceUrl;
    renderPng.screenshotTargetUrl = config.screenshotTargetUrl;
  }

  renderPng.getScreenshotPath = function (url) {
    return [
      renderPng.screenshotServiceUrl,
      '?readyExpression=$("body").hasClass("ready")',
      '&forwardCacheHeaders=true',
      '&clipSelector=.visualisation',
      '&url=',
      renderPng.screenshotTargetUrl,
      url.replace(/.png|\?raw/g, "?raw")
    ].join('');
  };

  return renderPng;
});

define([
  'http',
  'url'
],
function (http, url) {
  var renderPng = function (req, res) {
    var options = url.parse(renderPng.getScreenshotPath(req.url));
    http.get(options, function (screenshot) {
      res.status(screenshot.statusCode);
      for (var i in screenshot.headers) {
        res.setHeader(i, screenshot.headers[i]);
      }
      screenshot.on("data", function(chunk) {
        res.write(chunk);
      });
      screenshot.on("end", function () {
        res.end();
      });
    }).on('error', function (e) {
      res.status(500);
      res.send("Got error: " + e.message);
    });
  };

  if (global.config) {
    renderPng.screenshotServiceUrl = config.screenshotServiceUrl;
    renderPng.screenshotTargetUrl = config.screenshotTargetUrl;
  }

  renderPng.getScreenshotPath = function (url) {
    return [
      renderPng.screenshotServiceUrl,
      '?readyExpression=!!document.querySelector(".ready")',
      '&forwardCacheHeaders=true',
      '&clipSelector=.visualisation',
      '&url=',
      renderPng.screenshotTargetUrl,
      url.replace(/.png|\?raw/g, "?raw")
    ].join('');
  };

  return renderPng;
});

Use native DOM commands for screenshot ready expression


let AnnotationApi = require('./annotation');
let ScssCommentParser = require('scss-comment-parser');

export default class Parser {
  constructor (config) {
    this.annotations = new AnnotationApi();
    this.scssParser = new ScssCommentParser(this.annotations.list, config);

    this.scssParser.commentParser.on('warning', (warning) => {
      config.logger.warn(warning);
    });
  }

  parse(...args) {
    return this.scssParser.parse(args);
  }

  /**
   * Invoke the `resolve` function of an annotation if present.
   * Called with all found annotations except with type "unkown".
   */
  postProcess(data) {
    Object.keys(this.annotations.list).forEach(key => {
      let annotation = this.annotations.list[key];
      if (annotation.resolve) {
        annotation.resolve(data);
      }
    });

    return data;
  }
}

import AnnotationApi from './annotation';
let ScssCommentParser = require('scss-comment-parser');

export default class Parser {
  constructor (config) {
    this.annotations = new AnnotationApi();
    this.scssParser = new ScssCommentParser(this.annotations.list, config);

    this.scssParser.commentParser.on('warning', (warning) => {
      config.logger.warn(warning);
    });
  }

  parse(...args) {
    return this.scssParser.parse(args);
  }

  /**
   * Invoke the `resolve` function of an annotation if present.
   * Called with all found annotations except with type "unkown".
   */
  postProcess(data) {
    Object.keys(this.annotations.list).forEach(key => {
      let annotation = this.annotations.list[key];
      if (annotation.resolve) {
        annotation.resolve(data);
      }
    });

    return data;
  }
}

Use `import` for ES6 modules


// We won't show Taiwan and Western Sahara as an independent country
export const IGNORED_COUNTRIES_ISOS = ['TWN', 'ESH'];

// We won't show Taiwan and Western Sahara as an independent country
export const IGNORED_COUNTRIES_ISOS = ['TWN', 'ESH', 'GRL'];

Add Greenland to non hoverable countries


const randomSubs = ['random', 'randnsfw', 'myrandom'];
const fakeSubs = ['all', 'mod', 'friends'].concat(randomSubs);

export { fakeSubs, randomSubs };

export default function isFakeSubreddit(subredditName) {
  return !!subredditName && (subredditName.indexOf('+') > -1 || fakeSubs.includes(subredditName));
}

const randomSubs = ['random', 'randnsfw', 'myrandom'];
const fakeSubs = ['all', 'mod', 'friends'].concat(randomSubs);

export { fakeSubs, randomSubs };

export default function isFakeSubreddit(subredditName) {
  return !!subredditName && (
    subredditName.indexOf('+') > -1 ||
    subredditName.indexOf('-') > -1 ||
    fakeSubs.includes(subredditName)
  );
}

Revert "Revert "Count filtered r/all as a fake subreddit""


;(function (name, definition) {
    var theModule = definition(),
    hasDefine = typeof define === 'function' && define.amd,
    hasExports = typeof module !== 'undefined' && module.exports;

    if(hasDefine) // AMD Module
        define(theModule);
    else if(hasExports) // Node.js Module
        module.exports = theModule;
    else
        this[name] = theModule;
})('SerialQueue', function() {

    'use strict';

    var Q = function(worker)
    {
        this._running = false;
        this._worker  = worker;
        this._q = [];
    };

    Q.prototype = {
        constructor: Q,

        push: function(item)
        {
            this._q.push(item);
            this._run();
        },

        _runNext: function(done)
        {
            var self = this;

            var workerDone = function()
            {
                if(self._q.length)
                    self._worker(self._q.shift(), workerDone);
                else
                    done();
            }

            workerDone();
        },

        _run: function()
        {
            var self = this;
            if(!self._running)
            {
                self._running = true;
                self._runNext(function()
                {
                    self._running = false;
                });
            }
        }
    };

    return Q;

});

;(function (name, definition) {
    var theModule = definition(),
    hasDefine = typeof define === 'function' && define.amd,
    hasExports = typeof module !== 'undefined' && module.exports;

    if(hasDefine) // AMD Module
        define(theModule);
    else if(hasExports) // Node.js Module
        module.exports = theModule;
    else
        this[name] = theModule;
})('SerialQueue', function() {

    'use strict';

    var Q = function(worker)
    {
        this._running = false;
        this._worker  = worker;
        this._q = [];
    };

    Q.prototype = {
        constructor: Q,

        push: function(item, worker)
        {
            this._q.push({item: item, worker: worker});
            this._run();
        },

        _runNext: function(done)
        {
            var self = this;
            var next = function()
            {
                if(self._q.length)
                {
                    var task = self._q.shift();
                    (task.worker || self._worker)(task.item, next);
                }
                else
                {
                    done();
                }

            }

            next();
        },

        _run: function()
        {
            var self = this;
            if(!self._running)
            {
                self._running = true;
                self._runNext(function()
                {
                    self._running = false;
                });
            }
        }
    };

    return Q;
});

Add support for task-specific workers


var async = require("async");
var bay6 = require("../lib/");
var expect = require("chai").expect;
var mongoose = require("mongoose");
var request = require("supertest");

describe("Model", function() {
  var app;
  var model;

  beforeEach(function() {
    app = bay6();
    app.options.prefix = "";
    model = app.model("Document", {
      title: String,
      contents: String
    });
  });

  describe("#limit", function() {
    it("should return a maximum of n documents", function(done) {
      model.limit(5);

      var server = app.serve(9000);

      var Document = app.mongoose.model("Document");
      async.each([1, 2, 3, 4, 5, 6], function(useless, done2) {
        var doc = new Document({ title: "war and peace", contents: "yolo" });
        doc.save(done2);
      }, function(err) {
        if (err) {
          throw err;
        }
        request(server).get("/documents").end(function(err, res) {
          expect(res.body.length).to.equal(5);
          server.close();
          done();
        });
      });
    });
  });

  afterEach(function(done) {
    app.mongoose.db.dropDatabase(done);
  });
});

var async = require("async");
var bay6 = require("../lib/");
var expect = require("chai").expect;
var mongoose = require("mongoose");
var request = require("supertest");

describe("Model", function() {
  var app;
  var server;
  var model;

  beforeEach(function() {
    app = bay6();
    app.options.prefix = "";
    model = app.model("Document", {
      title: String,
      contents: String
    });
  });

  describe("#limit", function() {
    it("should return a maximum of n documents", function(done) {
      model.limit(5);

      server = app.serve(9000);
      populateAndGet(function(err, res) {
        expect(res.body.length).to.equal(5);
        done();
      });
    });
  });

  afterEach(function(done) {
    app.mongoose.db.dropDatabase(done);
    server.close();
  });

  function populateAndGet(cb) {
    var Document = app.mongoose.model("Document");
    async.each([1, 2, 3, 4, 5, 6], function(useless, done2) {
      var doc = new Document({ title: "war and peace", contents: "yolo" });
      doc.save(done2);
    }, function(err) {
      if (err) {
        throw err;
      }
      request(server).get("/documents").end(cb);
    });
  }
});

Move populate/get into its own method


var chai = require("chai");
var expect = chai.expect;
var inspect = require("util").inspect;

var Cluster = require('../cluster');
var cluster;

describe("Init Test Suite", function() {
    it('should construct an instance', function() {
        cluster = new Cluster();
    });
    it('should deploy a worker per CPU core', function() {
        cluster.deploy();
        expect(cluster.totalWorkers()).to.be.gte(4);
    });
});

var chai = require("chai");
var expect = chai.expect;
var inspect = require("util").inspect;

var Cluster = require('../cluster');
var cluster;

describe("Init Test Suite", function() {
    it('should construct an instance', function() {
        cluster = new Cluster();
    });
    it('should deploy a worker per CPU core', function() {
        cluster.deploy();
        expect(cluster.totalWorkers()).to.be.gte(require('os').cpus().length);
    });
});

Set no. of cores test to available CPU cores


var window = exports;

window.window           = window;

window.DOMParser        = require("xmldom").DOMParser;

window.XMLHttpRequest   = require("xmlhttprequest").XMLHttpRequest;

window.alert            = function() { console.log.apply(null, arguments); }
window.prompt           = function() { console.log(null, arguments); return ""; }
window.confirm          = function() { console.log(null, arguments); return true; }

window.Image            = function() {};

var window = exports;

window.window           = window;

window.DOMParser        = require("xmldom").DOMParser;

window.XMLHttpRequest   = require("xmlhttprequest-ssl").XMLHttpRequest;

window.alert            = function() { console.log.apply(null, arguments); }
window.prompt           = function() { console.log(null, arguments); return ""; }
window.confirm          = function() { console.log(null, arguments); return true; }

window.Image            = function() {};

Use new name for XMLHTTPRequest module as we now use another module