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

const WEBPACK_FILELOADER_PATH_KEY = "default";

const LogoPath = require('../../../assets/logo.svg')[WEBPACK_FILELOADER_PATH_KEY];
const LogoSmallPath = require('../../../assets/logo-small.svg')[WEBPACK_FILELOADER_PATH_KEY];
const ScreenshotPath = require('../../../assets/plotscreenshot.png')[WEBPACK_FILELOADER_PATH_KEY];
const DemoVideoPath = require('../../../assets/demo.mp4')[WEBPACK_FILELOADER_PATH_KEY];
const InstallLessPath = require('../../../styles/install.less')[WEBPACK_FILELOADER_PATH_KEY];

const logo = String(fs.readFileSync(path.resolve(__dirname, LogoPath)));

const logoSmall = String(fs.readFileSync(path.resolve(__dirname, LogoSmallPath)));

const screenshot = path.resolve(__dirname, ScreenshotPath);

const demoVideo = path.resolve(__dirname, DemoVideoPath);

const installLess = path.resolve(__dirname, InstallLessPath);

module.exports = {logo, logoSmall, screenshot, demoVideo, installLess};

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

let LogoPath = '../../../assets/logo.svg';
let LogoSmallPath = '../../../assets/logo-small.svg';
let ScreenshotPath = '../../../assets/plotscreenshot.png';
let DemoVideoPath = '../../../assets/demo.mp4';
let InstallLessPath = '../../../styles/install.less';

// Environment variable set by consumer repository using Webpack Plugins via config.
if (process.env.USING_WEBPACK_FILELOADER_TO_BUNDLE) {
  const WEBPACK_FILELOADER_PATH_KEY = "default";

  LogoPath = require('../../../assets/logo.svg')[WEBPACK_FILELOADER_PATH_KEY];
  LogoSmallPath = require('../../../assets/logo-small.svg')[WEBPACK_FILELOADER_PATH_KEY];
  ScreenshotPath = require('../../../assets/plotscreenshot.png')[WEBPACK_FILELOADER_PATH_KEY];
  DemoVideoPath = require('../../../assets/demo.mp4')[WEBPACK_FILELOADER_PATH_KEY];
  InstallLessPath = require('../../../styles/install.less')[WEBPACK_FILELOADER_PATH_KEY];
}

const logo = String(fs.readFileSync(path.resolve(__dirname, LogoPath)));

const logoSmall = String(fs.readFileSync(path.resolve(__dirname, LogoSmallPath)));

const screenshot = path.resolve(__dirname, ScreenshotPath);

const demoVideo = path.resolve(__dirname, DemoVideoPath);

const installLess = path.resolve(__dirname, InstallLessPath);

module.exports = {logo, logoSmall, screenshot, demoVideo, installLess};

Add conditional logic to support asset path resolution for both autocomplete-python and atom-plugin.


Add basic structure of module and Morse map


/*jslint indent: 2, unparam: true*/
/*global $: false, document: false, togglbutton: false, createTag: false*/
'use strict';

togglbutton.render('#tickets-show:not(.toggl)', {observe: true}, function (elem) {

  var link,
    container = createTag('li', 'toggle-container'),
    description = $('span.ticket-number', elem).textContent + ' ' + $('.ticket-summary > h1').textContent,
    project = $('h1.header-w > span').textContent;

  link = togglbutton.createTimerLink({
    className: 'assembla',
    description: description,
    projectName: project,
  });

  container.appendChild(link);
  $('ul.menu-submenu').appendChild(container);
});

/*jslint indent: 2, unparam: true*/
/*global $: false, document: false, togglbutton: false, createTag: false*/
'use strict';

togglbutton.render('#tickets-show:not(.toggl)', {observe: true}, function (elem) {

  var link,
    container = createTag('li', 'toggle-container'),
    description = $('span.ticket-number', elem).textContent + ' ' + $('.ticket-summary > h1').textContent
      .replace("Copied!Copy to clipboard", ''),
    project = $('h1.header-w > span').textContent;

  link = togglbutton.createTimerLink({
    className: 'assembla',
    description: description,
    projectName: project,
  });

  container.appendChild(link);
  $('ul.menu-submenu').appendChild(container);
});

Remove copy-to-clipboard text in title.


const fs = require("fs")
const JSON5 = require("json5");
const path = require("path");

if (process.argv.length < 3) {
  process.exit(1);
}

const last = arr => arr[arr.length - 1];
const sep = process.platform === "win32" ? "\\\\" : "/";
const [, , nodeRootDir] = process.argv;

let isElectron = last(nodeRootDir.split(sep)).startsWith("iojs");

if (!isElectron) {
  try {
    // Not ideal, would love it if there were a full featured gyp package to do this operation instead.
    const { variables: { built_with_electron } } = JSON5.parse(
      fs.readFileSync(
        path.resolve(nodeRootDir, "include", "node", "config.gypi"),
        "utf8"
      )
    );

    if (built_with_electron) {
      isElectron = true;
    }
  } catch (e) {}
}

process.stdout.write(isElectron ? "1" : "0");

const fs = require("fs")
const JSON5 = require("json5");
const path = require("path");

if (process.argv.length < 3) {
  process.exit(1);
}

const last = arr => arr[arr.length - 1];
const [, , nodeRootDir] = process.argv;

let isElectron = last(nodeRootDir.split(path.sep)).startsWith("iojs");

if (!isElectron) {
  try {
    // Not ideal, would love it if there were a full featured gyp package to do this operation instead.
    const { variables: { built_with_electron } } = JSON5.parse(
      fs.readFileSync(
        path.resolve(nodeRootDir, "include", "node", "config.gypi"),
        "utf8"
      )
    );

    if (built_with_electron) {
      isElectron = true;
    }
  } catch (e) {}
}

process.stdout.write(isElectron ? "1" : "0");

Use path.sep for windows electron detection in node


if (!global.DEV_MODE) {
  process.on('uncaughtException', (error) => {
    console.error(error);
    Emitter.sendToGooglePlayMusic('error', {
      error: {
        message: error.message,
        stack: error.stack,
      },
    });
  });
}

process.on('uncaughtException', (error) => {
  console.error(error);
  if (global.DEV_MODE) return;
  Emitter.sendToGooglePlayMusic('error', {
    error: {
      message: error.message,
      stack: error.stack,
    },
  });
});

Change error handling in dev mode


import React, {PropTypes} from 'react'
import classnames from 'classnames'

const VisHeader = ({views, view, onToggleView, name}) => (

    {views.length
      ?

          {views.map(v => (

 onToggleView(v)}
              className={classnames({active: view === v})}
            >
              {v.charAt(0).toUpperCase() + v.slice(1)}

          ))}

      : null}

{name}

)

const {arrayOf, func, string} = PropTypes

VisHeader.propTypes = {
  views: arrayOf(string).isRequired,
  view: string.isRequired,
  onToggleView: func.isRequired,
  name: string.isRequired,
}

export default VisHeader

import React, {PropTypes} from 'react'
import classnames from 'classnames'
import _ from 'lodash'

const VisHeader = ({views, view, onToggleView, name}) => (

    {views.length
      ?

          {views.map(v => (

 onToggleView(v)}
              className={classnames({active: view === v})}
            >
              {_.upperFirst(v)}

          ))}

      : null}

{name}

)

const {arrayOf, func, string} = PropTypes

VisHeader.propTypes = {
  views: arrayOf(string).isRequired,
  view: string.isRequired,
  onToggleView: func.isRequired,
  name: string.isRequired,
}

export default VisHeader

Use lodash method instead of vanilla js


const vscode = require('vscode'); // eslint-disable-line import/no-unresolved

module.exports = (config =>
  ({
    autosave: config.get('autosave'),
    lastPart: config.get('lastPart'),
    preferredRange: config.get('preferredRange'),
    xRangeSymbol: config.get('xRangeSymbol'),
    excludePatterns: config.get('excludePatterns'),
  })
)(vscode.workspace.getConfiguration('dependency-formatter'));

Fix linter error after update


import marked from 'marked';

// TODO: Ensure security
const renderer = new marked.Renderer();
renderer.link = (href, title, text) =>
  `<a target="_blank" href="${href}" title="${title}">${text}</a>`;

function renderMarkdown(markdown) {
  return marked(markdown, { renderer });
}

export { renderMarkdown };

import marked from 'marked';

const renderer = new marked.Renderer();
renderer.link = (href, title, text) =>
  `<a target="_blank" href="${href}" title="${title}">${text}</a>`;

function renderMarkdown(markdown) {
  return marked(markdown, { renderer, sanitize: true });
}

export { renderMarkdown };

Enable sanatize html output of marked


$("[name='submit']").click(function(e) {
    e.preventDefault();
    var form = $(this).parents('form:first');
    var flag = $("input[name='flag']", form).val();
    var pid = $("input[name='pid']", form).val();
    if (flag == "") {
        Materialize.toast("Flag cannot be empty!", 2000);
        return;
    }
    submit_flag(pid, flag);
})

function submit_flag(pid, flag) {
    $.post("/api/submit_flag", {
        pid: pid,
        flag: flag
    }, function(data) {
        if (data == 1) {
            Materialize.toast("Correct!", 2000);
        } else if (data == 0) {
            Materialize.toast("Incorrect", 2000);
        } else if (data == -1) {
            Materialize.toast("You already solved this problem!", 2000)
        }
    });
}

function render_descriptions() {
    var desc = $('p[name=problem-desc]').map(function(){
                   return $.trim($(this).text());
                }).get();
    $("p[name=problem-desc]").each(function() {
        $(this).html(marked(desc[0]));
        desc = desc.splice(1, desc.length);
    });
}

$(document).ready(function() {
    render_descriptions();
});

$("[name='submit']").click(function(e) {
    e.preventDefault();
    var form = $(this).parents('form:first');
    var flag = $("input[name='flag']", form).val();
    var pid = $("input[name='pid']", form).val();
    if (flag == "") {
        Materialize.toast("Flag cannot be empty!", 2000);
        return;
    }
    submit_flag(pid, flag);
})

function submit_flag(pid, flag) {
    $.post("/api/submit_flag", {
        pid: pid,
        flag: flag
    }, function(data) {
        if (data == 1) {
            Materialize.toast("Correct!", 2000);
        } else if (data == 0) {
            Materialize.toast("Incorrect", 2000);
        } else if (data == -1) {
            Materialize.toast("You already solved this problem!", 2000)
        }
    });
}

function render_descriptions() {
    Renderer.prototype.paragraph = function(text) {
        return text;
    };

    var desc = $('p[name=problem-desc]').map(function(){
                   return $.trim($(this).text());
                }).get();
    $("p[name=problem-desc]").each(function() {
        $(this).html(marked(desc[0]));
        desc = desc.splice(1, desc.length);
    });
}

$(document).ready(function() {
    render_descriptions();
});

Remove <p> tags from rendered markdown


"use strict";

const EventImpl = require("./Event-impl").implementation;

class UIEventImpl extends EventImpl {
  initUIEvent(type, bubbles, cancelable, view, detail) {
    if (this._dispatchFlag) {
      return;
    }

    this.initEvent(type, bubbles, cancelable);
    this.view = view;
    this.detail = detail;
  }
}

module.exports = {
  implementation: UIEventImpl
};

"use strict";

const idlUtils = require("../generated/utils");
const UIEventInit = require("../generated/UIEventInit");
const EventImpl = require("./Event-impl").implementation;

// Until webidl2js gains support for checking for Window, this would have to do.
function isWindow(val) {
  if (typeof val !== "object") {
    return false;
  }
  const wrapper = idlUtils.wrapperForImpl(val);
  if (typeof wrapper === "object") {
    return wrapper === wrapper._globalProxy;
  }

  // `val` may be either impl or wrapper currently, because webidl2js currently unwraps Window objects (and their global
  // proxies) to their underlying EventTargetImpl during conversion, which is not what we want. But at the same time,
  // some internal usage call this constructor with the actual global proxy.
  return isWindow(idlUtils.implForWrapper(val));
}

class UIEventImpl extends EventImpl {
  constructor(args, privateData) {
    const eventInitDict = args[1] || UIEventInit.convert(undefined);

    // undefined check included so that we can omit the property in internal usage.
    if (eventInitDict.view !== null && eventInitDict.view !== undefined) {
      if (!isWindow(eventInitDict.view)) {
        throw new TypeError(`Failed to construct '${new.target.name.replace(/Impl$/, "")}': member view is not of ` +
                            "type Window.");
      }
    }

    super(args, privateData);
  }

  initUIEvent(type, bubbles, cancelable, view, detail) {
    if (view !== null) {
      if (!isWindow(view)) {
        throw new TypeError(`Failed to execute 'initUIEvent' on '${this.constructor.name.replace(/Impl$/, "")}': ` +
                            "parameter 4 is not of type 'Window'.");
      }
    }

    if (this._dispatchFlag) {
      return;
    }

    this.initEvent(type, bubbles, cancelable);
    this.view = view;
    this.detail = detail;
  }
}

module.exports = {
  implementation: UIEventImpl
};

Check Window type in UIEvent


import React from 'react';

export default class KataGroups extends React.Component {
  render() {
    const {kataGroups} = this.props;
    return (

        Menu

Kata groups

              {kataGroups.map(kataGroup =>

                {kataGroup.name} ({kataGroup.katasCount})

)}

    )
  }
}

import React from 'react';

export default class KataGroups extends React.Component {
  render() {
    const {kataGroups} = this.props;
    return (

        Menu

Kata groups

              {kataGroups.map(kataGroup =>

                <a href={`#kataGroup=${encodeURIComponent(kataGroup.name)}`} className="pure-menu-link">{kataGroup.name} ({kataGroup.katasCount})

)}

    )
  }
}

Change the url when clicking on a kata group.


function SwatActions(id, values, selected)
{
	var self = this;
	var is_ie = (document.addEventListener) ? false : true;

	this.id = id;
	this.flydown = document.getElementById(id + '_action_flydown');
	this.selected_element = (selected) ?
		document.getElementById(id + '_' + selected) : null;

	this.values = values;

	function handleChange(event)
	{
		if (self.selected_element) {
			self.selected_element.className += ' swat-hidden';
		}

		var id = self.id + '_' + self.values[self.flydown.selectedIndex];
		self.selected_element = document.getElementById(id);

		if (self.selected_element) {
			self.selected_element.className =
				self.selected_element.className.replace(/ *swat-hidden/, '');
		}
	}

	if (is_ie)
		this.flydown.attachEvent('onchange', handleChange);
	else
		this.flydown.addEventListener('change', handleChange, true);
}

function SwatActions(id, values, selected)
{
	var self = this;

	this.id = id;
	this.flydown = document.getElementById(id + '_action_flydown');
	this.selected_element = (selected) ?
		document.getElementById(id + '_' + selected) : null;

	this.values = values;

	function handleChange(event)
	{
		if (self.selected_element)
			YAHOO.util.Dom.addClass(self.selected_element, 'swat-hidden');

		var id = self.id + '_' + self.values[self.flydown.selectedIndex];
		self.selected_element = document.getElementById(id);

		if (self.selected_element)
			YAHOO.util.Dom.removeClass(self.selected_element, 'swat-hidden');
	}

	YAHOO.util.Event.addListener(this.flydown, 'change', handleChange);
}

Use Yahoo UI Library to abstract away some clunky code for css-class manipulation and event handling.


/* global describe, it, expect, Vector3, Particle */
describe('Particle', function () {
  'use strict';

  it('should be a constructor function', function () {
    expect(typeof Particle).toBe('function');
  });

  it('should initialize particle\'s properties when called with new',
    function () {
      var pos = new Vector3(1, 2, 3);
      var vel = new Vector3(2, 2, 2);
      var acc = new Vector3(3, 3, 3);
      var particle = new Particle({
        position: pos,
        velocity: vel,
        acceleration: acc,
        damping: 2,
        mass: 2
      });
      expect(particle.position).toBe(pos);
      expect(particle.velocity).toBe(vel);
      expect(particle.acceleration).toBe(acc);
      expect(particle.damping).toBe(2);
      expect(particle.inverseMass).toBe(0.5);
      expect(particle.mass).toBe(2);
      particle.mass = 4;
      expect(particle.inverseMass).toBe(0.25);
    });
});

/* global describe, it, expect, Vector3, Particle */
describe('Particle', function () {
  'use strict';

  it('should be a constructor function', function () {
    expect(typeof Particle).toBe('function');
  });

  it('should initialize particle\'s properties when called with new',
    function () {
      var pos = new Vector3(1, 2, 3);
      var vel = new Vector3(2, 2, 2);
      var acc = new Vector3(3, 3, 3);
      var particle = new Particle({
        position: pos,
        velocity: vel,
        acceleration: acc,
        damping: 2,
        mass: 2
      });
      expect(particle.position).toBe(pos);
      expect(particle.velocity).toBe(vel);
      expect(particle.acceleration).toBe(acc);
      expect(particle.damping).toBe(2);
      expect(particle.inverseMass).toBe(0.5);
      expect(particle.mass).toBe(2);
      particle.mass = 4;
      expect(particle.inverseMass).toBe(0.25);
    });

  it('should has a method integrate, which integrates ' +
      'the particle for duration',
      function () {
        var particle = new Particle({
          position: new Vector3(1, 1, 1),
          velocity: new Vector3(2, 2, 2),
          acceleration: new Vector3(1, 1, 1),
          damping: 1,
          mass: 2
        });
        expect(typeof particle.integrate).toBe('function');
      });
});

Add basic test for integrate


var _data_list = [];

function fetchDataAndRenderContent () {
  console.log("fetchDataAndRenderContent first time!");
  _data_list = [];
  extractDataAndUpdateContent();
}

function extractDataAndUpdateContent () {
  updateFetchProgress(100);

  extractGauageRowData();
  renderGaugeRowItemsWithAnimation();

  updateFetchCounter();
  updateFetchProgress(0);
}

function extractGauageRowData () {
  if (!_data_list.length) {
    fetchMockupData();
  }
  return _data_list.slice(-1)[0];
}

function fetchMockupData () {
  $.each(gauge_data, function (index, item) {
    item['time'] = new Date();
    item['value'] *= 1 + (Math.random() - 0.5) * 0.1;
  });
  _data_list.push(gauge_data);
}

var _data_list = [];

function fetchDataAndRenderContent () {
  console.log("fetchDataAndRenderContent first time!");
  _data_list = [];
  extractDataAndUpdateContent();
}

function extractDataAndUpdateContent () {
  updateFetchProgress(100);

  extractGauageRowData();
  renderGaugeRowItemsWithAnimation();

  updateFetchCounter();
  updateFetchProgress(0);
}

function extractGauageRowData () {
  if (!_data_list.length) {
    fetchMockupData();
  }
  var _list = _data_list.slice(-1)[0];
  $.each(gauge_data, function (index, item) {
    item.time = _list[index].time;
    item.value = _list[index].value;
  });
}

function fetchMockupData () {
  var _list = [];
  $.each(gauge_data, function (index, item) {
    var _item = {};
    _item.time = new Date();
    _item.value = item.value * (1 + (Math.random() - 0.5) * 0.1);
    _list.push(_item);
  });
  _data_list.push(_list);
}

Reduce duplicate info stored in _data_list


'use strict';

var fs = require('fs');

function read(filename) {
  return fs.readFileSync(filename, {'encoding': 'utf8'});
}

exports.revision = {
  'build': function(test) {
    var actual = read('tmp/index.html');
    var expected = read('test/expected/index.html');

    test.equal(actual, expected, 'should revision static files');

    test.done();
  },
};

'use strict';

const fs = require('fs');

function read(filename) {
  return fs.readFileSync(filename, {'encoding': 'utf8'});
}

exports.revision = {
  'build': (test) => {
    const actual = read('tmp/index.html');
    const expected = read('test/expected/index.html');

    test.equal(actual, expected, 'should revision static files');

    test.done();
  },
};

Use ES6 features in test


module.exports = {
  "extends": "airbnb-base/legacy",
  "parserOptions": {
    "ecmaVersion": 5
  },
  "env": {
    "browser": true,
    "node": true
  },
  "rules": {
    "indent": ["error", 2],
    "brace-style": ["error", "1tbs"],
    "curly": ["error", "all"],
    "func-call-spacing": ["error", "never"],
    "linebreak-style": "off",
    "quotes": ["error", "single"],
    "semi": ["error", "always"],
    "space-before-function-paren": ["error", "never"],
    "func-names": ["error", "never"],
    "no-unused-vars": "off",
    "no-underscore-dangle": "off"
  },
  "globals": {
    "chai": true,
    "rewire": true,
    "describe": true,
    "expect": true,
    "assert": true,
    "it": true,
    "$": true
  }
};

module.exports = {
  "root": true,
  "extends": "airbnb-base/legacy",
  "parserOptions": {
    "ecmaVersion": 5
  },
  "env": {
    "browser": true,
    "node": true
  },
  "rules": {
    "indent": ["error", 2],
    "brace-style": ["error", "1tbs"],
    "curly": ["error", "all"],
    "func-call-spacing": ["error", "never"],
    "linebreak-style": "off",
    "quotes": ["error", "single"],
    "semi": ["error", "always"],
    "space-before-function-paren": ["error", "never"],
    "func-names": ["error", "never"],
    "no-unused-vars": "off",
    "no-underscore-dangle": "off"
  },
  "globals": {
    "chai": true,
    "rewire": true,
    "describe": true,
    "expect": true,
    "assert": true,
    "it": true,
    "$": true
  }
};

Set eslint config as root


var replace = require( "../src/str-replace" );

module.exports = {
  replace_all: function( assert ) {
    var actual = replace
      .all( "/" )
        .from( "/home/dir" )
      .to( "\\" );
    var expected = "\\home\\dir";
    assert.strictEqual( actual, expected );
    assert.done();
  },
  replace_all_ignoring_case: function( assert ) {
    var actual = replace
      .all( "house" )
        .ignoreCase()
        .from( "Many Houses" )
      .to( "Horse" );
    var expected = "Many Horses";
    assert.strictEqual( actual, expected );
    assert.done();
  }
};

var replace = require( "../src/str-replace" );

module.exports = {
  replace_all: function( assert ) {
    var actual = replace
      .all( "/" )
        .from( "/home/dir" )
      .to( "\\" );
    var expected = "\\home\\dir";
    assert.strictEqual( actual, expected );
    assert.done();
  },
  replace_all_ignoring_case: function( assert ) {
    var actual = replace
      .all( "house" )
        .ignoreCase()
        .from( "Many Houses" )
      .to( "Horse" );
    var expected = "Many Horses";
    assert.strictEqual( actual, expected );
    assert.done();
  },
  replace_all_ignoring_case_only_the_first_occurrence: function( assert ) {
    var actual = replace
      .all( "/dir" )
        .ignoreCase()
        .from( "/Dir\\dir" )
      .to( "\\dir" );
      var expected = "\\dir\\dir";
      assert.strictEqual( actual, expected );
      assert.done();
  }
};

Test replacing the first substring occurrence


/**
 * Module dependencies.
 */

exports = module.exports = function(adapter, settings, logger) {

  return function subscribe(done) {
    var config = settings.get('connection') || {}
      , queues = config.queue || config.queues;

    if (!queues) { throw new Error('Misconfigured message queue: no queues'); }

    if (typeof queues == 'string') {
      queues = [ queues ];
    }

    var qi = 0;
    function qiter(err) {
      if (err) { return done(err); }

      var queue = queues[qi++];
      if (!queue) { return done(); }

      if (typeof queue == 'string') {
        queue = { name: queue };
      }
      queue.exclusive = queue.exclusive || false;

      logger.info('Subscribing to queue %s (%s)', queue.name, queue.exclusive ? 'x' : ' ');
      adapter.subscribe(queue.name, { exclusive: queue.exclusive }, function(err) {
        if (err) {
          logger.error(err.message);
          return qiter(err);
        }
        logger.debug('Subscribed to queue %s', queue.name);
        return qiter();
      });
    }
    qiter();
  }
}

/**
 * Component annotations.
 */
exports['@require'] = [ '../adapter', 'settings', 'logger' ];

/**
 * Module dependencies.
 */

exports = module.exports = function(adapter, settings, logger) {

  return function subscribe(done) {
    var config = settings.get('connection') || {}
      , queues = config.queue || config.queues;

    if (!queues) { throw new Error('Misconfigured message queue: no queues'); }

    if (typeof queues == 'string') {
      queues = [ queues ];
    }

    var qi = 0;
    function qiter(err) {
      if (err) { return done(err); }

      var queue = queues[qi++];
      if (!queue) { return done(); }

      if (typeof queue == 'string') {
        queue = { name: queue };
      }
      queue.exclusive = queue.exclusive || false;

      if (queue.subscribe === false) {
        process.nextTick(qiter);
      } else {
        logger.info('Subscribing to queue %s (%s)', queue.name, queue.exclusive ? 'x' : ' ');
        adapter.subscribe(queue.name, { exclusive: queue.exclusive }, function(err) {
          if (err) {
            logger.error(err.message);
            return qiter(err);
          }
          logger.debug('Subscribed to queue %s', queue.name);
          return qiter();
        });
      }
    }
    qiter();
  }
}

/**
 * Component annotations.
 */
exports['@require'] = [ '../adapter', 'settings', 'logger' ];

Add flag to skip queue subscription.


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

define([], function (util) {
  return {
    "interface": "__interface_html__",
    help: "__help_txt__",
    walkthrough: "__walkthrough_html__",
    names: "__names__"
  };
});

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

define([], function () {
  return {
    "interface": "__interface_html__",
    help: "__help_txt__",
    walkthrough: "__walkthrough_html__",
    names: "__names__"
  };
});

Remove unused leftover from a removed import


var FILE = require("file");
var ASSERT = require("assert");

var Haml = require("../lib/haml");

FILE.glob("test/*.haml").forEach(function(hamlFile) {
    exports["test " + hamlFile] = function() {
        var scopeFile = hamlFile.replace(/haml$/, "js");
        var htmlFile = hamlFile.replace(/haml$/, "html");

        var haml = FILE.read(hamlFile);
        var expected = FILE.read(htmlFile);
        var scope = FILE.exists(scopeFile) ? eval("("+FILE.read(scopeFile)+")") : {};

        var js = Haml.compile(haml);
        var js_opt = Haml.optimize(js);
        var actual = Haml.execute(js_opt, scope.context, scope.locals);
        ASSERT.equal(actual, expected);
    }
});

if (module == require.main)
    require("os").exit(require("test").run(exports));

var FILE = require("file");
var ASSERT = require("assert");

var Haml = require("../lib/haml");

FILE.glob("test/*.haml").forEach(function(hamlFile) {
    exports["test " + hamlFile] = function() {
        var scopeFile = hamlFile.replace(/haml$/, "js");
        var htmlFile = hamlFile.replace(/haml$/, "html");

        var haml = FILE.read(hamlFile);
        var expected = FILE.read(htmlFile);
        var scope = FILE.exists(scopeFile) ? eval("("+FILE.read(scopeFile)+")") : {};

        var js = Haml.compile(haml);
        var js_opt = Haml.optimize(js);
        var actual = Haml.execute(js_opt, scope.context, scope.locals);
        ASSERT.equal(actual.trim(), expected.trim());
    }
});

if (module == require.main)
    require("os").exit(require("test").run(exports));

Trim before testing for equality on unit tests.


/* eslint-env node, mocha, browser */
/* global expect */

import viewport from '../viewport';

describe('"viewport"', () => {
  it('Should return NULL if no document was found', () => {
    expect(viewport({})).to.be.null;
  });

  it('Should return either the Body or DOM element', () => {
    const { body, documentElement: html } = document;
    const bodyOrHtml = (elm) => elm === body || elm === html;
    const fakeDocCompat = { nodeType: 9, compatMode: 'BackCompat', body };
    const fakeDoc = { nodeType: 9, documentElement: html };

    expect(viewport(document.createElement('div'))).to.satisfy(bodyOrHtml);
    expect(viewport(document.createComment('Comment'))).to.satisfy(bodyOrHtml);
    expect(viewport(document.body)).to.satisfy(bodyOrHtml);
    expect(viewport(document.documentElement)).to.satisfy(bodyOrHtml);
    expect(viewport(window)).to.satisfy(bodyOrHtml);
    expect(viewport(document)).to.satisfy(bodyOrHtml);
    expect(viewport(null)).to.satisfy(bodyOrHtml);
    expect(viewport()).to.satisfy(bodyOrHtml);
    expect(viewport(fakeDoc)).to.satisfy(bodyOrHtml);
    expect(viewport(fakeDocCompat)).to.satisfy(bodyOrHtml);
  });
});

/* eslint-env node, mocha, browser */
/* global expect */

import viewport from '../viewport';

describe('"viewport"', () => {
  const { body, documentElement: html } = document;
  const bodyOrHtml = (elm) => elm === body || elm === html;

  it('Should return NULL if no document was found', () => {
    const fakeDocCompat = { nodeType: 9, compatMode: 'BackCompat', body };
    const fakeDoc = { nodeType: 9, documentElement: html };

    expect(viewport({})).to.be.null;
    expect(viewport(fakeDoc)).to.be.null;
    expect(viewport(fakeDocCompat)).to.be.null;
  });

  it('Should return either the Body or DOM element', () => {
    expect(viewport(document.createElement('div'))).to.satisfy(bodyOrHtml);
    expect(viewport(document.createComment('Comment'))).to.satisfy(bodyOrHtml);
    expect(viewport(document.body)).to.satisfy(bodyOrHtml);
    expect(viewport(document.documentElement)).to.satisfy(bodyOrHtml);
    expect(viewport(window)).to.satisfy(bodyOrHtml);
    expect(viewport(document)).to.satisfy(bodyOrHtml);
    expect(viewport(null)).to.satisfy(bodyOrHtml);
    expect(viewport()).to.satisfy(bodyOrHtml);
  });
});

Correct testcase to reflect updated isWindow/isDOMDocument methods


import test from 'ava';

test.todo('Write test for utils.inViewport');

import test from 'ava';
import { inViewport } from '../src/viewport';

window.innerWidth = 1280;
window.innerHeight = 700;

let stub = {
    getBoundingClientRect() {
        return {
            bottom: 232,
            height: 108,
            left: 196,
            right: 1084,
            top: 124,
            width: 888
        };
    }
};

test('inViewport returns a boolean', t => {
    t.true(typeof inViewport(stub) === 'boolean');
});

test('inViewport accepts an offset', t => {
    t.false(inViewport(stub, 250));
});

Add initial tests for inViewport


'use strict';
const webpack = require('webpack');
const merge = require('webpack-merge');
const validate = require('webpack-validator');
const config = require('./buildConfig');

const BASE_CONFIG = merge({
  entry: {
    main: `${config.PATHS.src}/index.ts`,
  },
  plugins: [
    new webpack.DefinePlugin({
      COMPILE_CONSTANTS: {
        env: JSON.stringify(process.env.NODE_ENV),
      },
    }),
  ],
});

module.exports = validate((() => {
  const devtool = { devtool: 'eval-source-map' };
  switch (process.env.NODE_ENV) {

    case 'development': return merge(BASE_CONFIG,
      devtool,
      config.generateHtml(),
      config.bundle.typeScript(),
      config.bundle.style(),
      config.devServer());

    case 'production': return merge(BASE_CONFIG,
      config.output(),
      config.extractBundle('vendor.js', ['mithril']),
      config.generateHtml(),
      config.bundle.typeScript(),
      config.bundle.style(true),
      config.uglifyJs());

    case 'test': return merge(BASE_CONFIG,
      devtool,
      config.definePlugins());

    default: throw new Error(`Build does not exist for environment: ${process.env.NODE_ENV}`);
  }
})());

'use strict';
const webpack = require('webpack');
const merge = require('webpack-merge');
const validate = require('webpack-validator');
const config = require('./buildConfig');

const BASE_CONFIG = merge({
  entry: {
    main: `${config.PATHS.src}/index.ts`,
  },
  plugins: [
    new webpack.DefinePlugin({
      COMPILE_CONSTANTS: {
        env: JSON.stringify(process.env.NODE_ENV),
      },
    }),
  ],
}, config.extractBundle('vendor.js', ['mithril']));

module.exports = validate((() => {
  const devtool = { devtool: 'eval-source-map' };
  switch (process.env.NODE_ENV) {

    case 'development': return merge(BASE_CONFIG,
      devtool,
      config.generateHtml(),
      config.bundle.typeScript(),
      config.bundle.style(),
      config.devServer());

    case 'production': return merge(BASE_CONFIG,
      config.output(),
      config.generateHtml(),
      config.bundle.typeScript(),
      config.bundle.style(true),
      config.uglifyJs());

    case 'test': return merge(BASE_CONFIG,
      devtool,
      config.definePlugins());

    default: throw new Error(`Build does not exist for environment: ${process.env.NODE_ENV}`);
  }
})());

Move vendor chunk to BASE_CONFIG


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

var BUILD_DIR = path.resolve(__dirname, 'views/js');
var APP_DIR = path.resolve(__dirname, 'jsx');

var config = {
    entry: {
        index: APP_DIR + '/index.jsx',
    }
    output: {
        path: BUILD_DIR,
        filename: '[name]-bundle.js'
  }
};

module.exports = config;

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

var BUILD_DIR = path.resolve(__dirname, 'views/js');
var APP_DIR = path.resolve(__dirname, 'jsx');

var config = {
    entry: {
        app: APP_DIR + '/app.jsx',
    },
    output: {
        path: BUILD_DIR,
        filename: '[name]-bundle.js'
    },
    module: {
        loaders: [
            {
                test: /\.jsx?/,
                include: APP_DIR,
                loader: 'babel'
            }
        ]
    }
};

module.exports = config;

Load JSX from jsx folder


module.exports = {
    entry: "./src/exports.js",
    output: {
        filename: 'bundle.js',
        library: 'ModelViewer',
        libraryTarget: 'var'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /(node_modules)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['babel-preset-es2015-script'],
                    }
                }
            },
        ]
    }
}

module.exports = {
    entry: "./src/exports.js",
    output: {
        filename: 'bundle.js',
        library: 'ModelViewer',
        libraryTarget: 'var'
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: function(modulePath)
                {
                    return /node_modules/.test(modulePath) &&
                    !/node_modules\/gl-matrix/.test(modulePath);
                },
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['babel-preset-es2015-script'],
                    }
                }
            },
        ]
    }
}

Fix bug where production build fails because of gl-matrix being ES6.


'use strict';

var webpack = require('webpack');

var plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
  }),
  new webpack.optimize.OccurenceOrderPlugin()
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        screw_ie8: true,
        warnings: false
      }
    })
  );
}

module.exports = {
  externals: {
    'react': 'React',
    'react-native': 'React'
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'Redux',
    libraryTarget: 'var'
  },
  plugins: plugins,
  resolve: {
    extensions: ['', '.js']
  }
};

'use strict';

var webpack = require('webpack');

var plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
  }),
  new webpack.optimize.OccurenceOrderPlugin()
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        screw_ie8: true,
        warnings: false
      }
    })
  );
}

var reactExternal = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
};

module.exports = {
  externals: {
    'react': reactExternal,
    'react-native': reactExternal
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'Redux',
    libraryTarget: 'umd'
  },
  plugins: plugins,
  resolve: {
    extensions: ['', '.js']
  }
};

Change browser build to UMD


const ExtractTextPlugin = require('extract-text-webpack-plugin')
const externals = require('webpack-node-externals')
const path = require('path')

const eslintRule = {
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'eslint-loader'
}

module.exports = [
  {
    entry: './client',
    output: {
      path: path.resolve('dist'),
      filename: 'client.js'
    },
    devtool: 'cheap-source-map',
    module: {
      rules: [
        {
          test: /\.less$/,
          use: ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: ['css-loader', 'less-loader']
          })
        },
        eslintRule
      ]
    },
    plugins: [
      new ExtractTextPlugin('client.css')
    ]
  },
  {
    entry: {
      server: './server',
      loader: './server/loader'
    },
    output: {
      path: path.resolve('dist'),
      filename: '[name].js'
    },
    devtool: 'cheap-source-map',
    module: {
      rules: [
        eslintRule
      ]
    },
    target: 'node',
    externals: externals(),
    node: false
  }
]

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const externals = require('webpack-node-externals')
const path = require('path')

const eslintRule = {
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'eslint-loader'
}

module.exports = [
  {
    entry: './client',
    output: {
      path: path.resolve('dist'),
      filename: 'client.js'
    },
    devtool: 'cheap-source-map',
    module: {
      rules: [
        eslintRule,
        {
          test: /\.less$/,
          use: ExtractTextPlugin.extract({
            fallback: 'style-loader',
            use: ['css-loader', 'less-loader']
          })
        }
      ]
    },
    plugins: [
      new ExtractTextPlugin('client.css')
    ]
  },
  {
    entry: {
      server: './server',
      loader: './server/loader'
    },
    output: {
      path: path.resolve('dist'),
      filename: '[name].js'
    },
    devtool: 'cheap-source-map',
    module: {
      rules: [
        eslintRule
      ]
    },
    target: 'node',
    externals: externals(),
    node: false
  }
]

Revert "Fix order of eslint-loader"


module.exports = {
  entry: "./src/app.js",
  output: {
    path: "./build",
    filename: "bundle.js",
    publicPath: 'http://localhost:8090/assets'
  },
  module: {
    loaders: [
      { test: /\.scss$/, loader: "style!css!sass" },
      { test: /\.css$/, loader: "style!css" },
      { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' },
      { test: /\.js$/, loader: "jsx-loader?insertPragma=React.DOM&harmony" },
      { test: /\.json$/, loader: "json" }
    ]
  },
  externals: {
    'react': 'React'
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  }
};

var webpack = require('webpack');

module.exports = {
  entry: "./src/app.js",
  output: {
    path: "./build",
    filename: "bundle.js",
    publicPath: 'http://localhost:8090/assets'
  },
  module: {
    loaders: [
      { test: /\.scss$/, loader: "style!css!sass" },
      { test: /\.css$/, loader: "style!css" },
      { test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' },
      { test: /\.js$/, loader: "jsx-loader?insertPragma=React.DOM&harmony" },
      { test: /\.json$/, loader: "json" }
    ]
  },
  externals: {
    'react': 'React'
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  plugins: [
    // Ignore extra languages for moment.js
    new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
  ]
};

Add plugin to ignore moment.js language packs.


var app = require('./app');
var config = require('../config.json');
app.listen(config.port);

var app = require('./app');
var config = require('../config.json');
app.listen(config.port, err => {
  if (err) {
    console.error(err)
  } else {
    console.log('Started sample server at https://localhost:' + config.port)
  }
});

Print sample server URL at startup


import tempy from 'tempy'
import fs from 'fs-extra'

export default function (test) {
  test.beforeEach(async (t) => {
    const directory = tempy.directory()
    await fs.ensureDir(directory)
    Object.assign(t.context, {directory})
  })

  test.afterEach.always(async (t) => {
    const {directory} = t.context
    await fs.remove(directory)
  })
}

import {temporaryDirectory} from 'tempy'
import fs from 'fs-extra'

export default function (test) {
  test.beforeEach(async (t) => {
    const directory = temporaryDirectory()
    await fs.ensureDir(directory)
    Object.assign(t.context, {directory})
  })

  test.afterEach.always(async (t) => {
    const {directory} = t.context
    await fs.remove(directory)
  })
}

Fix breaking usages of an updated version of tempy


import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('intercom-launcher',
                   'Integration | Component | intercom launcher', {
  integration: true
});

test('it renders', function(assert) {
  this.set('intercomAppID', 'foobar');

  this.render(hbs`
    {{#intercom-launcher intercomAppID=intercomAppID}}
      template block text
    {{/intercom-launcher}}
  `);

  assert.equal(
    this.$('#custom-intercom-link').text().trim(), 'template block text'
  );
});

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('intercom-launcher',
                   'Integration | Component | intercom launcher', {
  integration: true
});

test('it renders with a #customer-intercom-link', function(assert) {
  this.set('intercomAppID', 'foobar');

  this.render(hbs`
    {{#intercom-launcher intercomAppID=intercomAppID}}
      template block text
    {{/intercom-launcher}}
  `);

  /*
   * The #custom-intercom-link is set in Segment and is required for the
   * integration to work.
   */
  assert.equal(
    this.$('#custom-intercom-link').text().trim(), 'template block text'
  );
});

Add comment on intercom link ID


/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * Stub of Sample for Android.
 *
 * @format
 * @flow
 */

'use strict';

const warning = require('fbjs/lib/warning');

const Sample = {
  test: function() {
    warning('Not yet implemented for Android.');
  },
};

module.exports = Sample;

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * Stub of Sample for Android.
 *
 * @format
 * @flow
 */

'use strict';

const warning = require('fbjs/lib/warning');

const Sample = {
  test: function() {
    // $FlowFixMe warning expects a condition
    warning('Not yet implemented for Android.');
  },
};

module.exports = Sample;

Use libdefs for fbjs instead of types from node_modules


chrome.webRequest.onBeforeSendHeaders.addListener(
    function(details) {
        details.requestHeaders.push({
            name: "X-Molotov-Agent",
            value: "{\"app_id\":\"electron_app\",\"app_build\":2,\"app_version_name\":\"1.0.0\",\"type\":\"desktop\",\"os\":\"\",\"os_version\":\"\",\"manufacturer\":\"\",\"serial\":\"\",\"model\":\"\",\"brand\":\"\"}"
        });

        return {requestHeaders: details.requestHeaders};
    },
    {
        urls: [
            "https://fapi.molotov.tv/v2/auth/login",
            "https://fapi.molotov.tv/v2/auth/refresh/*"
        ],
        types: ["xmlhttprequest"]
    },
    ["blocking", "requestHeaders"]
);

chrome.webRequest.onCompleted.addListener(
    function(details) {
        // User successfully logged in.
        if (details.method == "POST"
            && details.url == "https://fapi.molotov.tv/v2/auth/login"
            && details.statusCode == "200") {
                chrome.tabs.reload();
        }
    },
    {
        urls: [
            "https://fapi.molotov.tv/v2/auth/login"
        ],
        types: ["xmlhttprequest"]
    }
);

chrome.browserAction.onClicked.addListener(
    function(details) {
        chrome.tabs.create({url: "http://app.molotov.tv/"});
    }
);

chrome.webRequest.onBeforeSendHeaders.addListener(
    function(details) {
        details.requestHeaders.push({
            name: "X-Molotov-Agent",
            value: "{\"app_id\":\"electron_app\",\"app_build\":3,\"app_version_name\":\"1.2.2\",\"type\":\"desktop\",\"electron_version\":\"1.4.12\",\"os\":\"Unknown\",\"os_version\":\"Unknown\",\"manufacturer\":\"MoloChrome\",\"serial\":\"Unknown\",\"model\":\"MoloChrome\",\"brand\":\"MoloChrome\"}"
        });

        return {requestHeaders: details.requestHeaders};
    },
    {
        urls: [
            "https://fapi.molotov.tv/v2/auth/login",
            "https://fapi.molotov.tv/v2/auth/refresh/*"
        ],
        types: ["xmlhttprequest"]
    },
    ["blocking", "requestHeaders"]
);

chrome.webRequest.onCompleted.addListener(
    function(details) {
        // User successfully logged in.
        if (details.method == "POST"
            && details.url == "https://fapi.molotov.tv/v2/auth/login"
            && details.statusCode == "200") {
                chrome.tabs.reload();
        }
    },
    {
        urls: [
            "https://fapi.molotov.tv/v2/auth/login"
        ],
        types: ["xmlhttprequest"]
    }
);

chrome.browserAction.onClicked.addListener(
    function(details) {
        chrome.tabs.create({url: "http://app.molotov.tv/"});
    }
);

Update "X-Molotov-Agent" header for Molotov version 1.2.2.


var browserify = require('broccoli-browserify');
var concat = require('broccoli-concat');
var ENV = process.env.ENVIRONMENT || 'development';
var es6class = require('es6-class');
var Filter = require('broccoli-filter');

function es6(inputTree) {
  var es6classFilter = new Filter(inputTree, {
    extensions: ['js'],
    targetExtensions: ['js']
  });
  es6classFilter.processString = function(source) {
    return es6class.compile(source);
  };
  return es6classFilter;
}

module.exports = function(broccoli) {
  var lib = 'lib';
  var test = 'test';
  var qunit = 'node_modules/qunit/node_modules/qunitjs/qunit';

  var fieldKit = browserify(es6(lib), {
    entries: ['./index'],
    outputFile: '/field-kit.js',
    bundle: { debug: false, standalone: 'FieldKit' }
  });

  var testSetup = browserify(test, {
    entries: ['./test_helper'],
    outputFile: '/test/setup.js'
  });

  var allTests = concat(test, {
    inputFiles: ['**/*_test.js'],
    outputFile: '/test/all.js'
  });

  switch (ENV) {
    case 'development':
      return [fieldKit, es6(testSetup), allTests, test, qunit];

    case 'production':
      return [fieldKit];
  }
};

var browserify = require('broccoli-browserify');
var concat = require('broccoli-concat');
var ENV = process.env.ENVIRONMENT || 'development';
var es6class = require('es6-class');
var Filter = require('broccoli-filter');
var mergeTrees = require('broccoli-merge-trees');

function es6(inputTree) {
  var es6classFilter = new Filter(inputTree, {
    extensions: ['js'],
    targetExtensions: ['js']
  });
  es6classFilter.processString = function(source) {
    return es6class.compile(source);
  };
  return es6classFilter;
}

var lib = 'lib';
var test = 'test';
var qunit = 'node_modules/qunit/node_modules/qunitjs/qunit';

var fieldKit = browserify(es6(lib), {
  entries: ['./index'],
  outputFile: '/field-kit.js',
  bundle: { debug: false, standalone: 'FieldKit' }
});

var testSetup = browserify(test, {
  entries: ['./test_helper'],
  outputFile: '/test/setup.js'
});

var allTests = concat(test, {
  inputFiles: ['**/*_test.js'],
  outputFile: '/test/all.js'
});

switch (ENV) {
  case 'development':
    module.exports = mergeTrees([fieldKit, es6(testSetup), allTests, test, qunit]);
    break;

  case 'production':
    module.exports = fieldKit;
    break;
}

Update build dependencies, especially broccoli.


var express = require('express');
var logger = require('morgan');
var bodyParser = require('body-parser');

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

var app = express();

if (process.env.NODE_ENV !== 'test') {
  app.use(logger('dev'));
}
app.use(bodyParser.json());

app.use('/', index);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

var express = require('express');
var logger = require('morgan');
var bodyParser = require('body-parser');

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

var app = express();

if (process.env.NODE_ENV !== 'test') {
  app.use(logger('dev'));
}
app.use(bodyParser.json());

app.use('/', index);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.json({
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.json({
    message: err.message,
    error: {}
  });
});

module.exports = app;

Return JSON in error handlers


import AuthenticatedRoute from 'ghost/routes/authenticated';
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
import styleBody from 'ghost/mixins/style-body';

var paginationSettings,
    UsersIndexRoute;

paginationSettings = {
    page: 1,
    limit: 20,
    status: 'active'
};

UsersIndexRoute = AuthenticatedRoute.extend(styleBody, PaginationRouteMixin, {
    classNames: ['settings-view-users'],

    setupController: function (controller, model) {
        this._super(controller, model);
        this.setupPagination(paginationSettings);
    },

    model: function () {
        var self = this;

        return self.store.find('user', {limit: 'all', status: 'invited'}).then(function () {
            return self.store.find('user', 'me').then(function (currentUser) {
                if (currentUser.get('isEditor')) {
                    // Editors only see authors in the list
                    paginationSettings.role = 'Author';
                }

                return self.store.filter('user', paginationSettings, function (user) {
                    if (currentUser.get('isEditor')) {
                        return user.get('isAuthor');
                    }
                    return true;
                });
            });
        });
    },

    actions: {
        reload: function () {
            this.refresh();
        }
    }
});

export default UsersIndexRoute;

import AuthenticatedRoute from 'ghost/routes/authenticated';
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
import styleBody from 'ghost/mixins/style-body';

var paginationSettings,
    UsersIndexRoute;

paginationSettings = {
    page: 1,
    limit: 20,
    status: 'active'
};

UsersIndexRoute = AuthenticatedRoute.extend(styleBody, PaginationRouteMixin, {
    classNames: ['settings-view-users'],

    setupController: function (controller, model) {
        this._super(controller, model);
        this.setupPagination(paginationSettings);
    },

    model: function () {
        var self = this;

        return self.store.find('user', {limit: 'all', status: 'invited'}).then(function () {
            return self.store.find('user', 'me').then(function (currentUser) {
                if (currentUser.get('isEditor')) {
                    // Editors only see authors in the list
                    paginationSettings.role = 'Author';
                }

                return self.store.filter('user', paginationSettings, function (user) {
                    if (currentUser.get('isEditor')) {
                        return user.get('isAuthor') || user === currentUser;
                    }
                    return true;
                });
            });
        });
    },

    actions: {
        reload: function () {
            this.refresh();
        }
    }
});

export default UsersIndexRoute;

Add self to list of filtered users for editors


sitemaps.add('/reports.xml', function() {
  var out = [], reports = Reports.find({}).fetch();
  _.each(reports, function(report) {
    out.push({
      page: 'rapport/' + report._id + '/' + slugify(report.project.name),
      lastmod: new Date(2014, 6, 20, 0, 0, 0, 0)
    });
  });
  return out;
});

sitemaps.add('/sitemap.xml', function() {
  return [
    {page: 'om/', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) },
    {page: 'kriterier/', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) },
    {page: 'rapporter/side/1', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) }
  ];
})

sitemaps.add('/reports.xml', function() {
  var out = [], reports = Reports.find({}).fetch();
  _.each(reports, function(report) {
    out.push({
      page: 'rapport/' + report._id + '/' + slugify(report.project.name),
      lastmod: report.lastModifiedAt == undefined ? new Date(2014, 6, 20, 0, 0, 0, 0) : report.lastModifiedAt
    });
  });
  return out;
});

sitemaps.add('/sitemap.xml', function() {
  return [
    {page: 'om/', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) },
    {page: 'kriterier/', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) },
    {page: 'rapporter/side/1', lastmod: new Date(2014, 6, 20, 0, 0, 0, 0) }
  ];
})

Use lastModifiedAt in the sitemap if possible


/*
* Copyright (C) Sam Parkinson 2014
*
* This file is part of ASLO.
*
* ASLO is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ASLO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with ASLO.  If not, see <http://www.gnu.org/licenses/>.
*/

exports.get = function (url, callback) {
  var key = 'HTTP_CACHE' + url;
  if (localStorage[key] !== undefined) {
    callback(JSON.parse(localStorage[key]));
  };

  $.get(url).done(function (response) {
    localStorage[key] = JSON.stringify(response);
    callback(response);
  });
};

/*
* Copyright (C) Sam Parkinson 2014
*
* This file is part of ASLO.
*
* ASLO is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* ASLO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with ASLO.  If not, see <http://www.gnu.org/licenses/>.
*/

exports.get = function (url, callback) {
  var key = 'HTTP_CACHE' + url;
  if (localStorage[key] !== undefined) {
    try {
        callback(JSON.parse(localStorage[key]));
    } catch (e) {};
  };

  $.get(url).done(function (response) {
    localStorage[key] = JSON.stringify(response);
    callback(response);
  });
};

Fix issue with js caching


var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var wims = new XMLHttpRequest();

wims.open("GET", "http://environment.data.gov.uk/water-quality/id/sampling-point/AN-WOODTON", false);
wims.send();

console.log(wims.status);
console.log(wims.statusText);
console.log(wims.responseText);

/*
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('test.db');

db.serialize(function() {

  db.run('CREATE TABLE lorem (info TEXT)');
  var stmt = db.prepare('INSERT INTO lorem VALUES (?)');

  for (var i = 0; i < 10; i++) {
    stmt.run('Ipsum ' + i);
  }

  stmt.finalize();

  db.each('SELECT rowid AS id, info FROM lorem', function(err, row) {
    console.log(row.id + ': ' + row.info);
  });
});

db.close();
*/
module.exports = router;

'use strict';

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var wims = new XMLHttpRequest();

wims.open("GET", "http://environment.data.gov.uk/water-quality/id/sampling-point?_limit=60000", false);
wims.send();

// status 200 = OK
console.log(wims.status);
console.log(wims.statusText);
//console.log(wims.responseText);

var json = JSON.parse(wims.responseText);
var count = Object.keys(json.items).length;
console.log(count);

//Get the file contents
// TODO: fix ReferenceError: File is not defined
/*
var txtFile = new File('sampling-points.txt');
txtFile.writeln(JSON.stringify(json.items));
txtFile.close();
*/

//console.log(JSON.parse(wims.responseText).length);

/*
var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database('test.db');

db.serialize(function() {

  db.run('CREATE TABLE lorem (info TEXT)');
  var stmt = db.prepare('INSERT INTO lorem VALUES (?)');

  for (var i = 0; i < 10; i++) {
    stmt.run('Ipsum ' + i);
  }

  stmt.finalize();

  db.each('SELECT rowid AS id, info FROM lorem', function(err, row) {
    console.log(row.id + ': ' + row.info);
  });
});

db.close();
*/
module.exports = router;

Add sample points API call


import React from 'react';
import ReactDOM from 'react-dom';
import { CrossStorageHub } from 'cross-storage';

import App from './App';

CrossStorageHub.init([
	{ origin: /\.appbase.io$/, allow: ['get'] },
	{ origin: /hardcore-hoover-0d4fea.netlify.com$/, allow: ['get'] },
	{ origin: /localhost:135$/, allow: ['get'] },
]);

ReactDOM.render(<App />, document.getElementById('root'));

import React from 'react';
import ReactDOM from 'react-dom';
import { CrossStorageHub } from 'cross-storage';

import App from './App';

CrossStorageHub.init([
	{ origin: /\.appbase.io$/, allow: ['get'] },
	{ origin: /localhost:1359$/, allow: ['get'] },
	{ origin: /localhost:1358$/, allow: ['get'] },
]);

ReactDOM.render(<App />, document.getElementById('root'));

Update permission for local development


(function() {
  'use strict'

  angular
    .module('webApp')
    .controller('boneController', boneController)
    .directive('boneTab', boneTab);

  boneController.$inject = ['$http'];

  function boneController($http) {
    var vm = this;

    vm.test = "test";

    vm.info = [];

    $http.get('../JSON/data.json').then(function(response) {
      console.log("Loaded data.json");
      // console.log(JSON.stringify(response));       // TODO remove

      vm.info = response.data.information;
    });
  };

  function boneTab() {
    return {
      restrict: 'EA',
      priority: 1001,
      templateUrl: '../TEMPLATES/tabs.html',
      controller: 'boneController',
      controllerAs: 'bone'
    };
  };

})();

(function() {
  'use strict'

  angular
    .module('webApp')
    .controller('boneController', boneController)
    .directive('boneTab', boneTab);

  boneController.$inject = ['$http'];

  function boneController($http) {
    var vm = this;

    vm.info = [];

    $http.get('../JSON/data.json').then(function(response) {
      console.log("Loaded data.json");
      vm.info = response.data.information;
    });
  };

  function boneTab() {
    return {
      restrict: 'EA',
      priority: 1001,
      templateUrl: '../TEMPLATES/tabs.html',
      controller: 'boneController',
      controllerAs: 'bone'
    };
  };

})();

Remove logging and redundant js


var Class = new Marionette.Application();

Class.addRegions({
  //Add application regions here
});

//Navigate to specific route
Class.navigate = function (route, options) {
  options || (options = {});
  Backbone.history.navigate(route, options);
};

//Returns current route
Class.getCurrentRoute = function () {
  return Backbone.history.fragment;
};

Class.on('initialize:after', function () {
  //Things to do after app initialize
});

var Class = new Marionette.Application();

Class.addRegions({
  //Add application regions here
});

//Navigate to specific route
Class.navigate = function (route, options) {
  options || (options = {});
  Backbone.history.navigate(route, options);
};

//Returns current route
Class.getCurrentRoute = function () {
  return Backbone.history.fragment;
};

Class.on('initialize:after', function () {
  //Things to do after app initialize
  if (Backbone.history) {
    Backbone.history.start({
      pushState: true
    });
  }
});

Test Fixes - Fixes tests related to the generator


import Ember from 'ember';
import { test } from 'ember-qunit';
import startApp from '../helpers/start-app';
var App;

module("Artist recommendation tests", {
  setup: function() {
    App = startApp();
  },
  teardown: function() {
    Ember.run(App, App.destroy);
    Ember.$.mockjax.clear();
  }
});

test("no similar artists", function() {
  expect(1);
  $.mockjax({
    url: 'http://api/api-token-auth/',
    contentType: 'application/json',
    responseText: {token: 'TOKEN'},
  });
  visit('/artists?name=Unknown').then(function() {
    equal(find('.panel').text().trim(), 'No artist found.', "Empty artist results text not found.");
  });
});

import Ember from 'ember';
import { test } from 'ember-qunit';
import startApp from '../helpers/start-app';
var App;

module("Artist recommendation tests", {
  setup: function() {
    App = startApp();
  },
  teardown: function() {
    Ember.run(App, App.destroy);
    Ember.$.mockjax.clear();
  }
});

test("no similar artists", function() {
  expect(1);
  $.mockjax({
    url: 'http://api/artists?name=Unknown',
    contentType: 'application/json',
    responseText: [],
  });
  visit('/artists?name=Unknown').then(function() {
    equal(find('.panel').text().trim(), 'No artist found.', "Empty artist results text not found.");
  });
});

Fix mocked URL in artists test


import {Perc, Label, GuideLabelStyle} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendLabelRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

var alignExpr = 'datum.' + Perc + '<=0?"left"'
  + ':datum.' + Perc + '>=1?"right":"center"';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      encode = {}, enter, update;

  encode.enter = enter = {
    opacity: zero,
    text: {field: Label}
  };
  addEncode(enter, 'fill', config.labelColor);
  addEncode(enter, 'font', config.labelFont);
  addEncode(enter, 'fontSize', config.labelFontSize);
  addEncode(enter, 'baseline', config.gradientLabelBaseline);
  addEncode(enter, 'limit', config.gradientLabelLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1}
  };

  enter.x = update.x = {
    field: Perc,
    mult: config.gradientWidth
  };

  enter.y = update.y = {
    value: config.gradientHeight,
    offset: config.gradientLabelOffset
  };

  enter.align = update.align = {signal: alignExpr};

  return guideMark(TextMark, LegendLabelRole, GuideLabelStyle, Perc, dataRef, encode, userEncode);
}

import {Perc, Label, GuideLabelStyle} from './constants';
import guideMark from './guide-mark';
import {TextMark} from '../marks/marktypes';
import {LegendLabelRole} from '../marks/roles';
import {addEncode} from '../encode/encode-util';

var alignExpr = 'datum.' + Perc + '<=0?"left"'
  + ':datum.' + Perc + '>=1?"right":"center"';

export default function(spec, config, userEncode, dataRef) {
  var zero = {value: 0},
      encode = {}, enter, update;

  encode.enter = enter = {
    opacity: zero
  };
  addEncode(enter, 'fill', config.labelColor);
  addEncode(enter, 'font', config.labelFont);
  addEncode(enter, 'fontSize', config.labelFontSize);
  addEncode(enter, 'baseline', config.gradientLabelBaseline);
  addEncode(enter, 'limit', config.gradientLabelLimit);

  encode.exit = {
    opacity: zero
  };

  encode.update = update = {
    opacity: {value: 1},
    text: {field: Label}
  };

  enter.x = update.x = {
    field: Perc,
    mult: config.gradientWidth
  };

  enter.y = update.y = {
    value: config.gradientHeight,
    offset: config.gradientLabelOffset
  };

  enter.align = update.align = {signal: alignExpr};

  return guideMark(TextMark, LegendLabelRole, GuideLabelStyle, Perc, dataRef, encode, userEncode);
}

Fix legend gradient label text to use update set.


/*
  jquery.popline.list.js 0.1.0-dev

  Version: 0.1.0-dev
  Updated: Aug 11th, 2014

  (c) 2014 by kenshin54
*/
;(function($) {

  $.popline.addButton({
    orderedList: {
      iconClass: "fa fa-list-ol",
      mode: "edit",
      action: function(event) {
        document.execCommand("InsertOrderedList");
      }
    },

    unOrderedList: {
      iconClass: "fa fa-list-ul",
      mode: "edit",
      action: function(event) {
        document.execCommand("InsertUnorderedList");
      }
    }
  });
})(jQuery);

/*
  jquery.popline.list.js 0.1.0-dev

  Version: 0.1.0-dev
  Updated: Aug 11th, 2014

  (c) 2014 by kenshin54
*/
;(function($) {

  var firefoxCleanupCheck = function(tag) {
    var focusNode = $.popline.utils.selection().focusNode();
    var node = $.popline.utils.findNodeWithTags(focusNode, tag);
    return node ? true : false;
  }

  var firefoxCleanup = function(addPTag) {
    $.popline.current.target.find("br[type=_moz]").parent().remove();
    if (addPTag) {
      document.execCommand("formatblock", false, "P");
      var selection = $.popline.utils.selection().obj();
      if (selection.anchorNode && (node = selection.anchorNode.parentNode.previousSibling) && node.tagName === "BR") {
        node.remove();
      }
      if (selection.focusNode && (node = selection.focusNode.parentNode.nextSibling) && node.tagName === "BR") {
        node.remove();
      }
      addPTag = null;
    }
  }

  $.popline.addButton({
    orderedList: {
      iconClass: "fa fa-list-ol",
      mode: "edit",
      action: function(event) {
        if ($.popline.utils.browser.firefox) {
          var addPTag = firefoxCleanupCheck('OL');
        }
        document.execCommand("InsertOrderedList");
        if ($.popline.utils.browser.firefox) {
          firefoxCleanup(addPTag);
        }
      }
    },

    unOrderedList: {
      iconClass: "fa fa-list-ul",
      mode: "edit",
      action: function(event) {
        if ($.popline.utils.browser.firefox) {
          var addPTag = firefoxCleanupCheck('UL');
        }
        document.execCommand("InsertUnorderedList");
        if ($.popline.utils.browser.firefox) {
          firefoxCleanup(addPTag);
        }
      }
    }
  });
})(jQuery);

Fix ol/ul bug under firefox.


/** @flow */

type Callback = (timestamp: number) => void;
type CancelAnimationFrame = (requestId: number) => void;
type RequestAnimationFrame = (callback: Callback) => number;

// Properly handle server-side rendering.
let win;
if (typeof window !== "undefined") {
  win = window;
} else if (typeof self !== "undefined") {
  win = self;
} else {
  win = this;
}

// requestAnimationFrame() shim by Paul Irish
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
const request =
  win.requestAnimationFrame ||
  win.webkitRequestAnimationFrame ||
  win.mozRequestAnimationFrame ||
  win.oRequestAnimationFrame ||
  win.msRequestAnimationFrame ||
  function(callback: Callback): RequestAnimationFrame {
    return (win: any).setTimeout(callback, 1000 / 60);
  };

const cancel =
  win.cancelAnimationFrame ||
  win.webkitCancelAnimationFrame ||
  win.mozCancelAnimationFrame ||
  win.oCancelAnimationFrame ||
  win.msCancelAnimationFrame ||
  function(id: number) {
    (win: any).clearTimeout(id);
  };

export const raf: RequestAnimationFrame = (request: any);
export const caf: CancelAnimationFrame = (cancel: any);

/** @flow */

type Callback = (timestamp: number) => void;
type CancelAnimationFrame = (requestId: number) => void;
type RequestAnimationFrame = (callback: Callback) => number;

// Properly handle server-side rendering.
let win;
if (typeof window !== "undefined") {
  win = window;
} else if (typeof self !== "undefined") {
  win = self;
} else {
  win = {};
}

// requestAnimationFrame() shim by Paul Irish
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
const request =
  win.requestAnimationFrame ||
  win.webkitRequestAnimationFrame ||
  win.mozRequestAnimationFrame ||
  win.oRequestAnimationFrame ||
  win.msRequestAnimationFrame ||
  function(callback: Callback): RequestAnimationFrame {
    return (win: any).setTimeout(callback, 1000 / 60);
  };

const cancel =
  win.cancelAnimationFrame ||
  win.webkitCancelAnimationFrame ||
  win.mozCancelAnimationFrame ||
  win.oCancelAnimationFrame ||
  win.msCancelAnimationFrame ||
  function(id: number) {
    (win: any).clearTimeout(id);
  };

export const raf: RequestAnimationFrame = (request: any);
export const caf: CancelAnimationFrame = (cancel: any);

Fix requestAnimationFrame case for SSR


(function init() {
    document.getElementById("input1").addEventListener("input", calc);
    document.getElementById("input2").addEventListener("input", calc);
    calc();
})();

function calc() {
    var str1 = document.getElementById("input1").value;
    var str2 = document.getElementById("input2").value;
    var daysString = DateCalc.daysBetween(str1, str2);
    var periodString = DateCalc.periodBetween(str1, str2);
    document.getElementById("output").value =
        daysString + " days (" + periodString + ")";
}

function parseDate(str) {
    var localDate = LocalDate.parse(str);
    return localDate.year + "-" + localDate.month + "-" + localDate.day;
}

(function init() {
    document.getElementById("input1").addEventListener("input", calc);
    document.getElementById("input2").addEventListener("input", calc);
    calc();
})();

function calc() {
    var str1 = document.getElementById("input1").value;
    var str2 = document.getElementById("input2").value;
    var days = DateCalc.daysBetween(str1, str2);
    if (isNaN(days)) {
        document.getElementById("output").value = "Please enter valid inputs.";
    } else {
        var daysString;
        if (days === 1) {
            daysString = days + " day";
        } else {
            daysString = days + " days";
        }
        var periodString = DateCalc.periodBetween(str1, str2);
        document.getElementById("output").value =
            daysString + " (" + periodString + ")";
    }
}

function parseDate(str) {
    var localDate = LocalDate.parse(str);
    return localDate.year + "-" + localDate.month + "-" + localDate.day;
}

Fix result's grammar issue. Show a message when inputs are invalid.


const child = require('child_process');

const forkCount =  parseInt(process.argv[2]);
const forkCalls =  parseInt(process.argv[3])
const intervalTime = parseInt(process.argv[4]);

for (var i = 0 ; i < forkCount; i++){
	process.stdout.write(`Process: ${i} at work`);
	let childProcess = child.fork('get-request.js',['www.google.com',forkCalls ,intervalTime]);

	childProcess.on('close', (code) => {`child process exited with code ${code}`})
}

const child = require('child_process');

const forkCount =  parseInt(process.argv[2]);
const forkCalls =  parseInt(process.argv[3])
const intervalTime = parseInt(process.argv[4]);
const targetURI = 'www.google.com';

for (var i = 0 ; i < forkCount; i++){
	process.stdout.write(`Process: ${i} at work`);
	let childProcess = child.fork('get-request.js',[targetURI,forkCalls ,intervalTime]);

	childProcess.on('close', (code) => {`child process exited with code ${code}`})
}

Add targetURI variable to make it easer to change the variable which controls the url which is pinged.


import path from 'path';

import Configuration from '../Configuration';
import FileUtils from '../FileUtils';
import ModuleFinder from '../ModuleFinder';
import findJsModulesFor from '../findJsModulesFor';

jest.mock('../ModuleFinder');
jest.mock('../FileUtils');

beforeEach(() => {
  ModuleFinder.getForWorkingDirectory.mockImplementation(() => ({
    find() {
      return Promise.resolve([{ path: './foo.js', isDefault: true }]);
    },
  }));
});

it('returns matching modules', () => findJsModulesFor(
  new Configuration('./bar.js'),
  'foo',
  './bar.js',
).then((jsModules) => {
  expect(jsModules.length).toEqual(1);
}));

describe('when a matching module is excluded', () => {
  beforeEach(() => {
    FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), {
      excludes: ['./*.js'],
    });
  });

  it('strips it out', () => findJsModulesFor(
    new Configuration('./bar.js'),
    'foo',
    './bar.js',
  ).then((jsModules) => {
    expect(jsModules.length).toEqual(0);
  }));
});

import path from 'path';

import Configuration from '../Configuration';
import FileUtils from '../FileUtils';
import ModuleFinder from '../ModuleFinder';
import findJsModulesFor from '../findJsModulesFor';

jest.mock('../ModuleFinder');
jest.mock('../FileUtils');

beforeEach(() => {
  ModuleFinder.getForWorkingDirectory.mockImplementation(() => ({
    find() {
      return Promise.resolve([{ path: './foo.js', isDefault: true }]);
    },
  }));
});

it('returns matching modules', () => findJsModulesFor(
  new Configuration('./bar.js'),
  'foo',
).then((jsModules) => {
  expect(jsModules.length).toEqual(1);
}));

describe('when a matching module is excluded', () => {
  beforeEach(() => {
    FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), {
      excludes: ['./*.js'],
    });
  });

  it('strips it out', () => findJsModulesFor(
    new Configuration('./bar.js'),
    'foo',
  ).then((jsModules) => {
    expect(jsModules.length).toEqual(0);
  }));
});

Remove extra args to findJsModulesFor


var _ = require("lodash");
var path = require("path");
var Bacon = require("baconjs");
var nodegit = require("nodegit");

var Logger = require("../logger.js");

var Application = require("../models/application.js");
var Git = require("../models/git.js")(path.resolve("."));

var create = module.exports = function(api, params) {
  var name = params.args[0];
  var orga = params.options.orga;
  var alias = params.options.alias;
  var region = params.options.region;

  var s_type = Application.getInstanceType(api, params.options.type);

  var s_app = s_type
    .flatMapLatest(function(type) {
      return Application.create(api, name, type, region, orga);
    })
    .flatMapLatest(function(app) {
      return Application.linkRepo(api, app.id);
    });

  s_app.onValue(function(app) {
    console.log("Your application has been successfully created!");
  });

  s_app.onError(Logger.error);
};

var _ = require("lodash");
var path = require("path");
var Bacon = require("baconjs");
var nodegit = require("nodegit");

var Logger = require("../logger.js");

var Application = require("../models/application.js");
var Git = require("../models/git.js")(path.resolve("."));

var create = module.exports = function(api, params) {
  var name = params.args[0];
  var orga = params.options.orga;
  var alias = params.options.alias;
  var region = params.options.region;

  var s_type = Application.getInstanceType(api, params.options.type);

  var s_app = s_type
    .flatMapLatest(function(type) {
      return Application.create(api, name, type, region, orga);
    })
    .flatMapLatest(function(app) {
      return Application.linkRepo(api, app.id, alias);
    });

  s_app.onValue(function(app) {
    console.log("Your application has been successfully created!");
  });

  s_app.onError(Logger.error);
};

Use provided alias when creating an application


import React from 'react'
import GraphContainer from './components/GraphContainer'
import { connect } from 'react-redux'
import { PropTypes } from 'prop-types'
import { fetchInitialTimeseries, fetchSchedule, fetchRecentTimeseries } from './actions'
import moment from 'moment'
import Grid from 'react-bootstrap/lib/Grid'
import Col from 'react-bootstrap/lib/Col'

class App extends React.PureComponent {
  static propTypes = {
    fetchInitialTimeseries: PropTypes.func.isRequired,
    fetchSchedule: PropTypes.func.isRequired,
    fetchRecentTimeseries: PropTypes.func.isRequired
  }

  componentWillMount () {
    this.props.fetchInitialTimeseries()
    this.props.fetchSchedule()

    setInterval(() => this.props.fetchRecentTimeseries(moment().subtract(1, 'hours').toDate()), 60 * 1000)
  }

  render () {
    return (
      <Grid>

Return Home

        <Col xsHidden smHidden>
          <GraphContainer fullscreen />
        </Col>
        <Col lgHidden className='section'>

Oops!

Currently, advanced graphs are only supported on desktop. Return Home

        </Col>
      </Grid>
    )
  }
}

export default connect(null, { fetchInitialTimeseries, fetchSchedule, fetchRecentTimeseries })(App)

import React from 'react'
import GraphContainer from './components/GraphContainer'
import { connect } from 'react-redux'
import { PropTypes } from 'prop-types'
import { fetchInitialTimeseries, fetchSchedule, fetchRecentTimeseries } from './actions'
import moment from 'moment'
import Grid from 'react-bootstrap/lib/Grid'
import Col from 'react-bootstrap/lib/Col'

class App extends React.PureComponent {
  static propTypes = {
    fetchInitialTimeseries: PropTypes.func.isRequired,
    fetchSchedule: PropTypes.func.isRequired,
    fetchRecentTimeseries: PropTypes.func.isRequired
  }

  componentWillMount () {
    this.props.fetchInitialTimeseries()
    this.props.fetchSchedule()

    setInterval(() => this.props.fetchRecentTimeseries(moment().subtract(1, 'hours').toDate()), 60 * 1000)
  }

  render () {
    return (
      <Grid>

Return Home

        <Col xsHidden smHidden>
          <GraphContainer fullscreen />
        </Col>
        <Col lgHidden mdHidden className='section'>

Oops!

Currently, advanced graphs are only supported on desktop. Return Home

        </Col>
      </Grid>
    )
  }
}

export default connect(null, { fetchInitialTimeseries, fetchSchedule, fetchRecentTimeseries })(App)

Allow advanced graph on medium sized displays


import FormControlsFfInputComponent from './ff-input';
import { arg } from 'ember-arg-types';
import { string } from 'prop-types';
import { action } from '@ember/object';

export default class FormControlsFfCurrencyComponent extends FormControlsFfInputComponent {
  @arg(string)
  prefix = '$ ';

  @action
  handleChange(value) {
    if (this.readonly && value.preventDefault) {
      value.preventDefault();
      return false;
    }

    if (this.args.onChange) {
      const value = parseFloat(value);
      if (value) {
        return this.args.onChange(value);
      }
    }
  }
}

import FormControlsFfInputComponent from './ff-input';
import { arg } from 'ember-arg-types';
import { string } from 'prop-types';
import { action } from '@ember/object';

export default class FormControlsFfCurrencyComponent extends FormControlsFfInputComponent {
  @arg(string)
  prefix = '$ ';

  @action
  handleChange(value) {
    if (this.readonly && value.preventDefault) {
      value.preventDefault();
      return false;
    }

    if (this.args.onChange) {
      const parsedValue = parseFloat(value);
      if (parsedValue) {
        return this.args.onChange(parsedValue);
      }
    }
  }
}

Fix redefinition of value on currency input


console.log("Helllo world");
var virus = document.querySelector("div");
virus.style.top = "400px";
var x = 1;
var y = 0;
var vy = 0;
var velocity = .1; // px per millisecond
var startTime = Date.now();
var clickTime;
timer = setInterval(function animate() {
	var t = Date.now() - startTime;
	x = velocity * t;
	virus.style.left = x + "px";
	if ( x > document.body.clientWidth) {
		startTime = Date.now();
	}
	if (vy >= .1) {
		var t = Date.now() - clickTime;
		y = vy * t + 400;
		virus.style.top = y + "px";
	}
},20); // ms  | 1000/20 = 50 frames per second (50 fps)

virus.addEventListener("click", function onclick(event) {
	vy = .1;
	clickTime = Date.now();
});

var virus = document.querySelector("div");
var x = 1;
var y = 0;
var vy = 0;
var ay = 0;
var vx = .1; // px per millisecond
var startTime = Date.now();
var clickTime;
timer = setInterval(function animate() {
	var t = Date.now() - startTime;
	x = vx * t;
	y = vy * t + 400;

	virus.style.left = x + "px";
	virus.style.top = y + "px";

	if ( x > document.body.clientWidth) {
		startTime = Date.now();
	}
	if (ay >= .001) {
		var t = Date.now() - clickTime;
		vy = ay * t;
	}
},20); // ms  | 1000/20 = 50 frames per second (50 fps)

virus.addEventListener("click", function onclick(event) {
	ay = .001;
	clickTime = Date.now();
});

Add acceleration, leads to more natural movement when Ufo is clicked and falls


require('./style.scss')

var Game = require("./game")
var canvas = document.getElementById('canvas')
var context = canvas.getContext('2d');
var game = new Game(canvas, context)

game.setup();

requestAnimationFrame(function test() {
  if (!game.snake.isDead()) {
    game.gameLoop()
    setTimeout(function(){
      requestAnimationFrame(test);
    }, game.speed * 50);
  }
    else {
      game.render.displayGameOver();
  }
});

require('./style.scss');

var Game = require("./game");
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var game = new Game(canvas, context);

game.setup();

requestAnimationFrame(function test() {
  if (!game.snake.isDead()) {
    game.gameLoop();
    setTimeout(function(){
      requestAnimationFrame(test);
    }, game.speed * 50);
  }
    else {
      game.render.displayGameOver();
      updateHighScores(getHighScores(), game.score);
  }
});

function updateHighScores(scores, currentScore) {
    scores.push(currentScore);
    var sortedScores = scores.sort(function(a, b) {
      return parseInt(b) - parseInt(a);
    });
    localStorage.setItem("highScores", sortedScores.slice(0, 9))
    console.log(localStorage.highScores)
  }

function getHighScores() {
  if (!localStorage.highScores) {
    localStorage.setItem("highScores", "0");
    return [localStorage.getItem("highScores")];
  }
  else {
    return localStorage.getItem("highScores").split(",");
  }
}

Add local storage for high scores


import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import './Guilds.scss'
import API from '../api'
import Guild from '../components/Guild'

export default class Guilds extends Component {
  state = {
    guilds: null,
  }

  async componentDidMount() {
    const guilds = await API.get('/api/guilds')
    this.setState({ guilds })
  }

  render() {
    const { guilds } = this.state

    let content

    if (guilds == null) {
      content =
Loading servers...

    } else if (guilds.length !== 0) {
      const guildNodes = guilds.map((guild) => (

          <Link to={`/guilds/${guild.id}`}>
            <Guild guild={guild} />
          </Link>

      ))

      content = (
        <>

Click on a server below to edit its configuration:

{guildNodes}

        </>
      )
    } else {
      content =
No servers.

    }

    return (

Servers

        {content}

    )
  }
}

import React, { Component } from 'react'
import { Link } from 'react-router-dom'

import './Guilds.scss'
import API from '../api'
import Notice from '../components/Notice'
import Guild from '../components/Guild'

export default class Guilds extends Component {
  state = {
    guilds: null,
    error: null,
  }

  async componentDidMount() {
    try {
      const guilds = await API.get('/api/guilds')
      this.setState({ guilds })
    } catch (error) {
      this.setState({ error })
    }
  }

  render() {
    const { guilds, error } = this.state

    let content

    if (guilds == null) {
      content =
Loading servers...

    } else if (error != null) {
      content = <Notice mood="danger">Failed to load servers: {error}</Notice>
    } else if (guilds.length !== 0) {
      const guildNodes = guilds.map((guild) => (

          <Link to={`/guilds/${guild.id}`}>
            <Guild guild={guild} />
          </Link>

      ))

      content = (
        <>

Click on a server below to edit its configuration:

{guildNodes}

        </>
      )
    } else {
      content =
No servers.

    }

    return (

Servers

        {content}

    )
  }
}

Handle and display guild list fetching errors


/**
 * Created by AlexanderC on 9/15/15.
 */

/* eslint no-unused-vars: 1 */

'use strict';

var exports = module.exports = function(callback) {
  var microservice = this.microservice;
  var provisioning = this.provisioning;

  if (this.isUpdate) {
    console.log('Update! Skipping public bucket location retrieval post deploy hook...');

    callback();
    return;
  }

  console.log('Start retrieving public bucket location in "' + microservice.identifier + '" post deploy hook.');

  var s3 = provisioning.s3;
  var publicBucket = provisioning.config.s3.buckets.public.name;

  s3.getBucketLocation({Bucket: publicBucket}, function(error, data) {
    if (error) {
      console.error('Error while retrieving public bucket(' + publicBucket + ') location: ' + error);
    } else {
      var region = data.LocationConstraint || 'unknown';

      console.log('Public bucket(' + publicBucket + ') is located in "' + region + '" region.');
    }

    callback();

    return;
  });
};

/**
 * Created by AlexanderC on 9/15/15.
 */

/* eslint no-unused-vars: 0 */

'use strict';

var exports = module.exports = function(callback) {
  var microservice = this.microservice;
  var provisioning = this.provisioning;

  if (this.isUpdate) {
    console.log('Update! Skipping public bucket location retrieval post deploy hook...');

    callback();
    return;
  }

  console.log('Start retrieving public bucket location in "' + microservice.identifier + '" post deploy hook.');

  var s3 = provisioning.s3;
  var publicBucket = provisioning.config.s3.buckets.public.name;

  s3.getBucketLocation({Bucket: publicBucket}, function(error, data) {
    if (error) {
      console.error('Error while retrieving public bucket(' + publicBucket + ') location: ' + error);
    } else {
      var region = data.LocationConstraint || 'unknown';

      console.log('Public bucket(' + publicBucket + ') is located in "' + region + '" region.');
    }

    callback();

    return;
  });
};

Change rule from warning to off


import safeEval from 'safe-eval';
import dir from 'node-dir';
import path from 'path';
import {ipcRenderer} from 'electron';
console.log(__dirname);
console.log(process.cwd());
import {scripts} from './../../client/util/';
const babel = require('babel-core');
const babelOptions = {
  presets: ['es2015']
}

let script = process.env.script;

scripts.addScript(script, (script) => {

  if(script.status === 'OK') {
    ipcRenderer.send('code', {code: script.code, dir: script});
  } else {
    console.log(script.status);
    //Handle not OK scripts.
  }
});

import safeEval from 'safe-eval';
import dir from 'node-dir';
import path from 'path';
import {ipcRenderer} from 'electron';
import {scripts} from './../../client/util/';
import {setUserRequire} from './../../client/util/';
import lib from './../../client/lib/';

const babel = require('babel-core');
const babelOptions = {
  presets: ['es2015']
}

const dev = process.env.NODE_ENV ? !!process.env.NODE_ENV.match(/dev/) : true;

let scriptPath = process.env.script;

scripts.addScript(scriptPath, (script) => {

  if(script.status === 'OK') {

    let userContext = {
      require: setUserRequire(lib, script),
      console: {
        log: scripts.addLog(scriptPath, dev)
      },
      setTimeout,
      setImmediate,
      __dirname: scriptPath,
      Math
    };
    try {
      safeEval(script.code, userContext);
    } catch(e) {
      scripts.addError(scriptPath, e)
    }
  } else {
    console.log(script.status);
  }
});

Add execution of user script to renderer process


const cls = {
  main: 'ps',
  element: {
    thumb: x => `ps__thumb-${x}`,
    rail: x => `ps__rail-${x}`,
    consuming: 'ps__child--consume',
  },
  state: {
    focus: 'ps--focus',
    active: x => `ps--active-${x}`,
    scrolling: x => `ps--scrolling-${x}`,
  },
};

export default cls;

/*
 * Helper methods
 */
const scrollingClassTimeout = { x: null, y: null };

export function addScrollingClass(i, x) {
  const classList = i.element.classList;
  const className = cls.state.scrolling(x);

  if (classList.contains(className)) {
    clearTimeout(scrollingClassTimeout[x]);
  } else {
    classList.add(className);
  }
}

export function removeScrollingClass(i, x) {
  scrollingClassTimeout[x] = setTimeout(
    () => i.element.classList.remove(cls.state.scrolling(x)),
    i.settings.scrollingThreshold
  );
}

export function setScrollingClassInstantly(i, x) {
  addScrollingClass(i, x);
  removeScrollingClass(i, x);
}

const cls = {
  main: 'ps',
  element: {
    thumb: x => `ps__thumb-${x}`,
    rail: x => `ps__rail-${x}`,
    consuming: 'ps__child--consume',
  },
  state: {
    focus: 'ps--focus',
    active: x => `ps--active-${x}`,
    scrolling: x => `ps--scrolling-${x}`,
  },
};

export default cls;

/*
 * Helper methods
 */
const scrollingClassTimeout = { x: null, y: null };

export function addScrollingClass(i, x) {
  const classList = i.element.classList;
  const className = cls.state.scrolling(x);

  if (classList.contains(className)) {
    clearTimeout(scrollingClassTimeout[x]);
  } else {
    classList.add(className);
  }
}

export function removeScrollingClass(i, x) {
  scrollingClassTimeout[x] = setTimeout(
    () => i.isActive && i.element.classList.remove(cls.state.scrolling(x)),
    i.settings.scrollingThreshold
  );
}

export function setScrollingClassInstantly(i, x) {
  addScrollingClass(i, x);
  removeScrollingClass(i, x);
}

Add active check in timeout


'use strict';

var buildPolicyString = require('./utils')['buildPolicyString'];

module.exports = {
  'csp-headers': {
    name: 'csp-headers',
    description: 'Generate Content-Security-Policy headers',
    works: 'insideProject',
    availableOptions: [
      {
        name: 'environment',
        type: String,
        aliases: [ 'e' ],
        default: 'development'
      },
      {
        name: 'report-uri',
        type: String
      }
    ],

    run: function(options) {
      var config = this.project.config(options.environment);
      var reportUri = options.reportUri;

      if (!!reportUri) {
        config.contentSecurityPolicy['report-uri'] = reportUri;
      }

      var policyObject = config.contentSecurityPolicy;
      this.ui.writeLine(buildPolicyString(policyObject));
    }
  }
};

'use strict';

var buildPolicyString = require('./utils')['buildPolicyString'];
var chalk = require('chalk');

module.exports = {
  'csp-headers': {
    name: 'csp-headers',
    description: 'Generate Content-Security-Policy headers',
    works: 'insideProject',
    availableOptions: [
      {
        name: 'environment',
        type: String,
        aliases: [ 'e' ],
        default: 'development'
      },
      {
        name: 'report-uri',
        type: String
      }
    ],

    run: function(options) {
      var config = this.project.config(options.environment);
      var reportUri = options.reportUri;

      if (!!reportUri) {
        config.contentSecurityPolicy['report-uri'] = reportUri;
      }

      this.ui.writeLine(chalk.dim.cyan('# Content Security Policy Header Configuration'));
      this.ui.writeLine(chalk.dim.cyan('#'));
      this.ui.writeLine(chalk.dim.cyan('# for Apache: Header set ' + config.contentSecurityPolicyHeader + ' "..."'));
      this.ui.writeLine(chalk.dim.cyan('# for Nginx : add_header ' + config.contentSecurityPolicyHeader + ' "...";') + '\n');

      var policyObject = config.contentSecurityPolicy;
      this.ui.writeLine(buildPolicyString(policyObject), 'ERROR');
    }
  }
};

Add preamble with settings for some famous web servers


import React, { Component } from 'react'

import VoudeOnibusPng from '../../img/voudeonibus.png'
import VoudeOnibusHorizontalPng from '../../img/voudeonibus-horizontal.png'

export default class About extends Component {
  render () {
    const imgs = `${VoudeOnibusHorizontalPng} 640w, ${VoudeOnibusPng} 800w`
    return (

    )
  }
}

import React, { Component } from 'react'

import VoudeOnibusPng from '../../img/voudeonibus.png'
import VoudeOnibusHorizontalPng from '../../img/voudeonibus-horizontal.png'

const imgs = `${VoudeOnibusHorizontalPng} 640w, ${VoudeOnibusPng} 800w`

export default class About extends Component {
  render () {
    return (

    )
  }
}

Move `const imgs` from `render`


import {exec} from 'node-promise-es6/child-process';
import fs from 'node-promise-es6/fs';

async function run() {
  const {linkDependencies = {}} = await fs.readJson('package.json');
  for (const dependencyName of Object.keys(linkDependencies)) {
    const dependencyPath = linkDependencies[dependencyName];

    const {stdout: diff} = await exec(
      'git diff-index HEAD', {cwd: dependencyPath});
    if (diff.trim().indexOf('package.json') === -1) { continue; }

    process.stdout.write(`Committing 'vinsonchuong/${linkDependencies}'\n`);

    await exec(
      `git config user.email 'vinsonchuong@gmail.com'`,
      {cwd: dependencyPath}
    );
    await exec(
      `git config user.name 'Vinson Chuong'`,
      {cwd: dependencyPath}
    );
    await exec(
      [
        'git commit',
        `-m 'Automatically update dependencies'`,
        'package.json'
      ].join(' '),
      {cwd: dependencyPath}
    );
    await exec(
      [
        'git push',
        `https://${process.env.GITHUB_TOKEN}@github.com/vinsonchuong/${dependencyName}`,
        'master'
      ].join(' '),
      {cwd: dependencyPath}
    );
  }
}

run().catch(e => {
  process.stderr.write(`${e.stack}\n`);
  process.exit(1);
});

import {exec} from 'node-promise-es6/child-process';
import fs from 'node-promise-es6/fs';

async function run() {
  const {linkDependencies = {}} = await fs.readJson('package.json');
  for (const dependencyName of Object.keys(linkDependencies)) {
    const dependencyPath = linkDependencies[dependencyName];

    const {stdout: diff} = await exec(
      'git diff-index HEAD', {cwd: dependencyPath});
    if (diff.trim().indexOf('package.json') === -1) { continue; }

    process.stdout.write(diff + '\n');
    process.stdout.write(`Committing 'vinsonchuong/${dependencyName}'\n`);

    await exec(
      `git config user.email 'vinsonchuong@gmail.com'`,
      {cwd: dependencyPath}
    );
    await exec(
      `git config user.name 'Vinson Chuong'`,
      {cwd: dependencyPath}
    );
    await exec(
      [
        'git commit',
        `-m 'Automatically update dependencies'`,
        'package.json'
      ].join(' '),
      {cwd: dependencyPath}
    );
    await exec(
      [
        'git push',
        `https://${process.env.GITHUB_TOKEN}@github.com/vinsonchuong/${dependencyName}`,
        'master'
      ].join(' '),
      {cwd: dependencyPath}
    );
  }
}

run().catch(e => {
  process.stderr.write(`${e.stack}\n`);
  process.exit(1);
});

Add logging statement for debugging Travis CI


/* eslint no-shadow: "off" */
import moment from 'moment';

export default function(server) {
  const user = server.create('user');
  const session = server.create('session');
  const offerings = server.createList('offering', 2, {
    session
  });
  const now = moment().hour(8).minute(0).second(0);
  server.create('userEvent', {
    user,
    startDate: now.format(),
    endDate: now.clone().add(1, 'hour').format(),
    offering: offerings[0],
    instructors: [
      'Coolest Guy',
      'Not as Cool of a guy'
    ],
    learningMaterials: [
      {
        "id": "1",
        "session": "1",
        "course": "1",
        "required": true,
        "title": "Medical Knowledge",
        "description": "abbreviations",
        "originalAuthor": "Agent 99",
        "absoluteFileUri": "/lm/test",
        "filename": "ilios_demofile.pdf",
        "mimetype": "application/pdf",
        "sessionTitle": "Skill Session",
        "courseTitle": "Medicine",
        "instructors": []
      }
    ]
  });
  server.create('userEvent', {
    user,
    startDate: now.clone().add(1, 'day').format(),
    endDate: now.clone().add(1, 'day').add(1, 'hour').format(),
    offering: offerings[1],
    instructors: [
      'Professor Smart',
      'Agent 99'
    ],
    learningMaterials: [
      {
        "id": "1",
        "session": "1",
        "course": "1",
        "required": true,
        "title": "Medical Knowledge",
        "description": "abbreviations",
        "originalAuthor": "Agent 99",
        "absoluteFileUri": "/lm/test",
        "filename": "ilios_demofile.pdf",
        "mimetype": "application/pdf",
        "sessionTitle": "Skill Session",
        "courseTitle": "Medicine",
        "instructors": []
      },
      {
        "id": "2",
        "session": "1",
        "course": "1",
        "required": false,
        "title": "Important Stuff",
        "description": "abbreviations",
        "originalAuthor": "Agent 99",
        "absoluteFileUri": "/lm/test",
        "filename": "ilios_demofile.pdf",
        "mimetype": "application/pdf",
        "sessionTitle": "Skill Session",
        "courseTitle": "Medicine",
        "instructors": []
      }
    ]

  });
}

Remove scenarios we never use


 //= require action_cable
 //= require_self
 //= require_tree ./channels

  (function() {
    this.App || (this.App = {});
    App.cable = ActionCable.createConsumer();
   }).call(this);

 //= require action_cable
 //= require_self

  (function() {
    this.App || (this.App = {});
    App.cable = ActionCable.createConsumer();
   }).call(this);

Fix small require JS error