import Button from './components/Button/Button.vue';
import FileSelect from './components/FileSelect/FileSelect.vue';
import Icon from './components/Icon/Icon.vue';
import Input from './components/Input/Input.vue';
import Range from './components/Range/Range.vue';
import Scroller from './components/Scroller/Scroller.vue';
import Table from './components/Table/Table.vue';
import ToggleGroup from './components/ToggleGroup/ToggleGroup.vue';
import Window from './components/Window/Window.vue';

import Draggable from './directives/Draggable.js';
import Resizable from './directives/Resizable.js';
import Dropbox from './directives/Dropbox.js';

export const directives = {
  Draggable,
  Resizable,
  Dropbox
};

export const components = {
  Button,
  FileSelect,
  Icon,
  Input,
  Range,
  Scroller,
  Table,
  ToggleGroup,
  Window
};

import PlmButton from './components/Button/Button.vue';
import PlmFileSelect from './components/FileSelect/FileSelect.vue';
import PlmIcon from './components/Icon/Icon.vue';
import PlmInput from './components/Input/Input.vue';
import PlmRange from './components/Range/Range.vue';
import PlmScroller from './components/Scroller/Scroller.vue';
import PlmTable from './components/Table/Table.vue';
import PlmToggleGroup from './components/ToggleGroup/ToggleGroup.vue';
import PlmWindow from './components/Window/Window.vue';

import PlmDraggable from './directives/Draggable.js';
import PlmResizable from './directives/Resizable.js';
import PlmDropbox from './directives/Dropbox.js';

export const components = {
  PlmButton,
  PlmFileSelect,
  PlmIcon,
  PlmInput,
  PlmRange,
  PlmScroller,
  PlmTable,
  PlmToggleGroup,
  PlmWindow
};

export const directives = {
  PlmDraggable,
  PlmResizable,
  PlmDropbox
};

export default {
  install (Vue) {
    Object.keys(components).forEach((name) => {
      Vue.component(name, components[name]);
    });
    Object.keys(directives).forEach((name) => {
      Vue.directive(name, directives[name]);
    });
  }
};

export {
  // directives
  PlmDraggable,
  PlmResizable,
  PlmDropbox,
  // components
  PlmButton,
  PlmFileSelect,
  PlmIcon,
  PlmInput,
  PlmRange,
  PlmScroller,
  PlmTable,
  PlmToggleGroup,
  PlmWindow
};

Change exports, add vue plugin installation support


// @flow

import 'babel-polyfill';

import program from 'commander';
import { blue, green, gray } from 'chalk';
import installer from '../installer';
import { androidClient, iosClient } from '../device-clients';

program
.command('install <hockeyAppName>')
.description('Install Hockey app on connected devices')
.action(hockeyAppName => installer.installAppByName('', hockeyAppName));

const displayDevices = (deviceClient: DeviceClientType, colorize: (text: string) => string) =>
  deviceClient.getDevices()
  .then(devices => devices.map(device => console.log(`${colorize(device.displayName)} (${device.osVersion}) - ${gray(device.id)}`)))
;

program
.command('devices')
.description('List connected devices')
.action(() => {
  displayDevices(androidClient, green);
  displayDevices(iosClient, blue);
});

program.parse(process.argv);

// @flow

import 'babel-polyfill';

import program from 'commander';
import { blue, green, gray } from 'chalk';
import installer from '../installer';
import { androidClient, iosClient } from '../device-clients';

program
.command('install <hockeyAppName>')
.description('Install Hockey app on connected devices')
.option('-u, --uninstall', 'Uninstall app before reinstalling')
.action((hockeyAppName, options) => installer.installAppByName('', hockeyAppName, !!options.uninstall));

const displayDevices = (deviceClient: DeviceClientType, colorize: (text: string) => string) =>
  deviceClient.getDevices()
  .then(devices => devices.map(device => console.log(`${colorize(device.displayName)} (${device.osVersion}) - ${gray(device.id)}`)))
;

program
.command('devices')
.description('List connected devices')
.action(() => {
  displayDevices(androidClient, green);
  displayDevices(iosClient, blue);
});

program.parse(process.argv);

Add uninstall option when installing app


module.exports = {
  UNKNOWN: '',
  BROWSER: 'browser',
  BROWSER_TEXT: 'browser:text',
  APP: 'app',
  APP_EMAIL: 'app:email',
  APP_GAME: 'app:game',
  APP_MEDIAPLAYER: 'app:mediaplayer',
  APP_FEEDREADER: 'app:feedreader',
  APP_PODCAST: 'app:podcast',
  APP_SOCIAL: 'app:social',
  APP_OFFICE: 'app:office',
  APP_EDITOR: 'app:editor',
  APP_DOWNLOAD: 'app:download',
  APP_SEARCH: 'app:search',
  APP_NEWS: 'app:news',
  APP_ANTIVIRUS: 'app:antivirus',
  APP_SHOPPING: 'app:shopping',
  APP_CHAT: 'app:chat',
};

module.exports = {
  UNKNOWN: 'unknown',
  BROWSER: 'browser',
  BROWSER_TEXT: 'browser:text',
  APP: 'app',
  APP_EMAIL: 'app:email',
  APP_GAME: 'app:game',
  APP_MEDIAPLAYER: 'app:mediaplayer',
  APP_FEEDREADER: 'app:feedreader',
  APP_PODCAST: 'app:podcast',
  APP_SOCIAL: 'app:social',
  APP_OFFICE: 'app:office',
  APP_EDITOR: 'app:editor',
  APP_DOWNLOAD: 'app:download',
  APP_SEARCH: 'app:search',
  APP_NEWS: 'app:news',
  APP_ANTIVIRUS: 'app:antivirus',
  APP_SHOPPING: 'app:shopping',
  APP_CHAT: 'app:chat',
};

Fix for UNKNOWN constants when used as object key


const nest = require('depnest')
const pull = require('pull-stream')
const Scroller = require('pull-scroll')
const next = require('../../../junk/next-stepper')

exports.gives = nest('router.html.page')
exports.needs = nest({
  'keys.sync.id': 'first',
  'feed.pull.mentions': 'first',
  'feed.pull.public': 'first',
  'message.html': {
    render: 'first'
  },
  'main.html.scroller': 'first'
})
exports.create = function (api) {
  return nest('router.html.page', (path) => {
    if (path !== '/notifications') return
    const id = api.keys.sync.id()
    const mentions = api.feed.pull.mentions(id)

    const { container, content } = api.main.html.scroller({})

    pull(
      mentions({old: false, limit: 100}),
      Scroller(container, content, api.message.html.render, true, false)
    )

    pull(
      mentions({reverse: true, limit: 100, live: false}),
      Scroller(container, content, api.message.html.render, false, false)
    )
    return container
  })
}

const nest = require('depnest')
const pull = require('pull-stream')
const Scroller = require('pull-scroll')
const next = require('../../../junk/next-stepper')

exports.gives = nest('router.html.page')
exports.needs = nest({
  'keys.sync.id': 'first',
  'feed.pull.mentions': 'first',
  'feed.pull.public': 'first',
  'message.html': {
    render: 'first'
  },
  'main.html.scroller': 'first'
})
exports.create = function (api) {
  return nest('router.html.page', (path) => {
    if (path !== '/mentions') return
    const id = api.keys.sync.id()
    const mentions = api.feed.pull.mentions(id)

    const { container, content } = api.main.html.scroller({})

    pull(
      next(mentions, {old: false, limit: 100}),
      Scroller(container, content, api.message.html.render, true, false)
    )

    pull(
      next(mentions, {reverse: true, limit: 100, live: false}),
      Scroller(container, content, api.message.html.render, false, false)
    )
    return container
  })
}

Use next to make endless scroll work.


import ContentAdd from 'material-ui/lib/svg-icons/content/add';
import IconButton from 'material-ui/lib/icon-button';
import TextField from 'material-ui/lib/text-field';
import React, { Component } from 'react';
import { connect } from 'react-redux';

import { addTodo } from '../actions';

const styles = {
  container: {
    marginLeft: 20
  }
}

let AddTodo = ({ dispatch }) => {
    let nodeRef;

    return (
      <div style={ styles.container }>
        <form onSubmit={ (e) =>  {
          e.preventDefault();
          dispatch(addTodo(nodeRef.getValue()));
          nodeRef.clearValue();
          }}>
          <TextField
            hintText="Add task"
            floatingLabelText="Add task"
            ref = { node => {
              nodeRef = node;
            }} />
        </form>
      </div>
    );
}

AddTodo = connect()(AddTodo);
export default AddTodo;

import ContentAdd from 'material-ui/lib/svg-icons/content/add';
import IconButton from 'material-ui/lib/icon-button';
import TextField from 'material-ui/lib/text-field';
import React, { Component } from 'react';
import { connect } from 'react-redux';

import { addTodo } from '../actions';

const styles = {
  container: {
    marginLeft: 20
  }
}

let AddTodo = ({ dispatch }) => {
    let nodeRef;

    return (
      <div style={ styles.container }>
        <form onSubmit={ (e) =>  {
          e.preventDefault();
          if (!nodeRef.getValue().trim()) {
            return;
          }

          dispatch(addTodo(nodeRef.getValue()));
          nodeRef.clearValue();
          }}>
          <TextField
            hintText="Add task"
            floatingLabelText="Add task"
            ref = { node => {
              nodeRef = node;
            }} />
        </form>
      </div>
    );
}

AddTodo = connect()(AddTodo);
export default AddTodo;

Add check for empty todo text


Add gcc 11.3 released on April 21, 2022


"use strict";

var _ = require("lodash");

module.exports = _.merge({},
  require("./es5.js"),
  require("../../rules/eslint/es6/walmart.js"), {
    "rules": {
      "strict": [2, "global"]
    }
  }
);

"use strict";

var _ = require("lodash");

module.exports = _.merge({},
  require("./es5.js"),
  require("../../rules/eslint/es6/walmart.js"), {
    "rules": {
      // All current React builds use Webpack, which bundle CommonJS or AMD style code into a
      // function. If using a _different_ build solution that goes to global scope, you may need to
      // override and tweak this option.
      "strict": [2, "global"]
    }
  }
);

Add disclaimer comment in ES6 base


import Vue from 'vue';
import Router from 'vue-router';

import Home from '../components/Home';
import About from '../components/About';
import Help from '../components/Help';
import Machine from '../components/settings/Machine';
import Kit from '../components/settings/Kit';
import Container from '../components/settings/Container';
import Build from '../components/tools/Build';
import Reset from '../components/tools/Reset';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  // scrollBehavior: () => ({ y: 0 }),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    { path: '/help', component: Help },

    { path: '/settings/machine', component: Machine },
    { path: '/settings/kits', component: Kit },
    { path: '/settings/containers/:type', component: Container },

    { path: '/tools/build', component: Build },
    { path: '/tools/reset', component: Reset },

    { path: '*', redirect: '/' },
  ],
});

export default router;

import Vue from 'vue';
import Router from 'vue-router';

import Home from '../components/Home';
import About from '../components/About';
import Help from '../components/Help';
import Machine from '../components/settings/Machine';
import Kit from '../components/settings/Kit';
import Container from '../components/settings/Container';
import Builder from '../components/tools/Builder';

Vue.use(Router);

const router = new Router({
  mode: 'history',
  // scrollBehavior: () => ({ y: 0 }),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    { path: '/help', component: Help },

    { path: '/settings/machine', component: Machine },
    { path: '/settings/kits', component: Kit },
    { path: '/settings/containers/:type', component: Container },

    { path: '/tools/builder', component: Builder },

    { path: '*', redirect: '/' },
  ],
});

export default router;

Rename Build to Builder and use /tools/builder as the routing url


$(document).ready(function() {
  // Listen events
  $('.btn-add').click(function() {
    // POST Add friend
    $.post('/api/users/' + this.id + '/friends', function(data) {
      console.log(data);
    })
  });
});

$(document).ready(function() {
  // Listen events
  $('.btn-add').click(function() {
    // POST Add friend
    $.post('/api/users/' + this.id + '/friends', function(data) {
      $('#' + data.friend).html('<i class="fa fa-heart"></i>').removeClass('btn-add').unbind("click");
    })
  });
});

Change status on add friend


import { strictEqual } from 'assert'
import { property } from '../src'

describe('property', () => {

  it('should generate a named property accessor for the provided string key', () => {

    const o = { a: 1, b: 2 }

    strictEqual(property('a')(o), 1)
    strictEqual(property('b')(o), 2)

  })

  it('should generate a property accessor that will return undefined for undefined properties', () => {

    const o = { a: 1, b: 2 }

    strictEqual(property('c')(o), undefined)

  })

  it('should generate a property accessor that will return undefined if call on an undefined object', () => {

    strictEqual(property('c')(undefined), undefined)

  })

  it('should generate property accessors that support dot notation for subproperties', () => {

    const o = { a: { aa: { aaa: 1 }, ab: 2 } }

    strictEqual(property('a.aa.aaa')(o), 1)
    strictEqual(property('a.ab')(o), 2)

  })

  it('should generate property accessors that return undefined if the accessor path is broken', () => {

    const o = { a: 1 }

    strictEqual(property('b.c.e')(o), undefined)

  })

})

import { strictEqual } from 'assert'
import { property } from '../src'

describe('property', () => {

  it('should generate a named property accessor for the provided string key', () => {

    const o = { a: 1, b: 2 }

    strictEqual(property('a')(o), 1)
    strictEqual(property('b')(o), 2)

  })

  it('should generate a property accessor that will return undefined for undefined properties', () => {

    const o = { a: 1, b: 2 }

    strictEqual(property('c')(o), undefined)

  })

  it('should generate a property accessor that will return undefined if call on an undefined object', () => {

    strictEqual(property('c')(undefined), undefined)

  })

  it('should generate property accessors that support dot notation for subproperties', () => {

    const o = { a: { aa: { aaa: 1 }, ab: 2 } }

    strictEqual(property('a.aa.aaa')(o), 1)
    strictEqual(property('a.ab')(o), 2)

  })

  it('should generate property accessors that return undefined if the accessor path is broken', () => {

    const o = { a: 1 }

    strictEqual(property('b.c.e')(o), undefined)

  })

  it('should return the full object if key is not provided', () => {

    const o = { a: 1 }

    strictEqual(property()(o), o)
    strictEqual(property(null)(o), o)
  })

})

Add test case for no key in "property"


var istanbul = require('istanbul'),

/**
 * Expose `Istanbul`.
 */
exports = module.exports = Istanbul;

/**
 * Initialize a new Istanbul reporter.
 *
 * @param {Runner} runner
 * @param {Object} options
 * @public
 */
function Istanbul(runner, options) {
    mocha.reporters.Base.call(this, runner);

    var reporterOpts = { dir: 'coverage' },
        reporters = ['text-summary', 'html'];

    options = options || {};
    if (options.reporters) reporters = options.reporters.split(',');
    if (process.env.ISTANBUL_REPORTERS) reporters = process.env.ISTANBUL_REPORTERS.split(',');
    if (options.reportDir) reporterOpts.dir = options.reportDir;
    if (process.env.ISTANBUL_REPORT_DIR) reporterOpts.dir = process.env.ISTANBUL_REPORT_DIR;

    runner.on('end', function(){
        var cov = global.__coverage__ || {},
            collector = new istanbul.Collector();

        collector.add(cov);

        reporters.forEach(function(reporter) {
            istanbul.Report.create(reporter, reporterOpts).writeReport(collector, true);
        });

    });

}

var istanbul = require('istanbul');

module.exports = function (runner, options) {
    mocha.reporters.Base.call(this, runner);

    var reporterOpts = { dir: 'coverage' },
        reporters = ['text-summary', 'html'];

    options = options || {};
    if (options.reporters) reporters = options.reporters.split(',');
    if (process.env.ISTANBUL_REPORTERS) reporters = process.env.ISTANBUL_REPORTERS.split(',');
    if (options.reportDir) reporterOpts.dir = options.reportDir;
    if (process.env.ISTANBUL_REPORT_DIR) reporterOpts.dir = process.env.ISTANBUL_REPORT_DIR;

    runner.on('end', function(){
        var cov = global.__coverage__ || {},
            collector = new istanbul.Collector();

        collector.add(cov);

        reporters.forEach(function(reporter) {
            istanbul.Report.create(reporter, reporterOpts).writeReport(collector, true);
        });

    });
};

Simplify a bit and obey code convention


var _ = require('lodash');
var np = require('named-parameters');

module.exports = function(args) {
  var parsedArgs = np.parse(args).
    require('name', 'string').
    require('pieces', 'object').
    require('forwardDirection', 'string').
    values();

  var name = parsedArgs.name;
  var forwardDirection = parsedArgs.forwardDirection;
  var Pieces = _.clone(parsedArgs.pieces);

  var instance = {
    name: name,
    forwardDirection: forwardDirection,
    Piece: Piece
  };

  return instance;

  function Piece(rank){
    if(!Pieces[rank]){
      throw("this army doesn not countain a piece for rank '" + rank + "'");
    }
    return function() { return Pieces[rank]({ army: instance }); };
  }
};

var _ = require('lodash');
var np = require('named-parameters');

module.exports = function(args) {
  var parsedArgs = np.parse(args).
    require('name', 'string').
    require('pieces', 'object').
    require('forwardDirection', 'string').
    values();

  var name = parsedArgs.name;
  var forwardDirection = parsedArgs.forwardDirection;
  var Pieces = _.clone(parsedArgs.pieces);

  var instance = {
    name: name,
    forwardDirection: forwardDirection,
    Piece: Piece
  };

  return instance;

  function Piece(rank){
    if(!Pieces[rank]){
      throw(new Error("this army doesn not countain a piece for rank '" + rank + "'"));
    }
    return function() { return Pieces[rank]({ army: instance }); };
  }
};

Use Error object in Army


const expect = require('chai').expect;

const myParseInt = require('../src/parse-int.js');

describe('my parse int', function () {
  it('turns a string into a number', function () {
    let expected = myParseInt('10');

    expect(expected).to.equal(10);
  });

  it('turns a string starting with 0 into an octal number', function () {
    let expected = myParseInt('010');

    expect(expected).to.equal(8);
  });
});

const expect = require('chai').expect;

const myParseInt = require('../src/parse-int.js');

describe('my parse int', function () {
  it('turns a string into a number (integer)', function () {
    let expected = myParseInt('10');

    expect(expected).to.equal(10);
  });

  it('turns a string starting with 0 into an octal number', function () {
    let expected = myParseInt('010');

    expect(expected).to.equal(8);
  });
});

Use regexp special char in testcase description


import Service from '@ember/service';
import Evented from '@ember/object/evented';

export default Service.extend(Evented, {

  shownComponents: null,
  data: null,
  showWindow: false,

  addComponent(path) {
    if(!this.get('shownComponents'))
      this.set('shownComponents', []);

    if (!this.get('shownComponents').includes(path)) {
      this.get('shownComponents').push(path);
    }
  },

  removeComponent(path) {
    if(!this.get('shownComponents'))
      return;

    var index = this.get('shownComponents').indexOf(path);
    if (index !== -1)
      this.get('shownComponents').splice(index, 1);

    // close everything when no components are left
    if (this.get('shownComponents.length') == 0)
      this.emptyAdditionalData()
  },

  emptyAdditionalData() {
    this.set('shownComponents', []);
    this.set('data', null);
  },

  closeAdditionalData() {
    this.set('showWindow', false);
    this.trigger('showWindow');
  },

  openAdditionalData() {
    this.set('showWindow', true);
    this.trigger('showWindow');
  }

});

import Service from '@ember/service';
import Evented from '@ember/object/evented';

export default Service.extend(Evented, {

  shownComponents: null,
  data: null,
  showWindow: false,

  addComponent(path) {
    if(!this.get('shownComponents'))
      this.set('shownComponents', []);

    if (!this.get('shownComponents').includes(path)) {
      this.get('shownComponents').push(path);
    }
  },

  removeComponent(path) {
    if(!this.get('shownComponents'))
      return;

    var index = this.get('shownComponents').indexOf(path);
    if (index !== -1)
      this.get('shownComponents').splice(index, 1);

    // close everything when no components are left
    if (this.get('shownComponents.length') == 0)
      this.emptyAdditionalData()
  },

  emptyAdditionalData() {
    this.closeAdditionalData();
    this.set('shownComponents.length', 0);
    this.set('data', null);
  },

  closeAdditionalData() {
    this.set('showWindow', false);
    this.trigger('showWindow');
  },

  openAdditionalData() {
    this.set('showWindow', true);
    this.trigger('showWindow');
  }

});

Fix bug causing components to not show up in data-selection


/*jshint node:true */
module.exports = function (grunt) {
  grunt.initConfig({
    intern: {
      complete: {
        options: {
          config: 'tests/intern',
          runType: 'runner'
        }
      },
      fast: {
        options: {
          config: 'tests/intern-watch',
          runType: 'runner'
        }
      }
    },
    selenium: {
      options: {
        jar: 'vendor/selenium/selenium-server-standalone-2.44.0.jar',
        port: 4444
      },
      main: {
        // Target-specific file lists and/or options go here.
      },
    },
    watch: {
      dev: {
        files: ['*.js', 'tests/**'],
        tasks: ['selenium-launch', 'intern:fast']
      }
    }
  });

  // Loading using a local git copy
  grunt.loadNpmTasks('intern');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-selenium-simple');

  // Register tasks
  grunt.registerTask('default', ['watch']);
  grunt.registerTask('test', ['selenium', 'intern:complete']);
};

/*jshint node:true */
module.exports = function (grunt) {
  grunt.initConfig({
    intern: {
      complete: {
        options: {
          config: 'tests/intern',
          runType: 'runner'
        }
      },
      fast: {
        options: {
          config: 'tests/intern-watch',
          runType: 'runner'
        }
      }
    },
    selenium: {
      options: {
        jar: 'vendor/selenium/selenium-server-standalone-2.45.0.jar',
        port: 4444
      },
      main: {
        // Target-specific file lists and/or options go here.
      },
    },
    watch: {
      dev: {
        files: ['*.js', 'tests/**'],
        tasks: ['intern:fast']
      }
    }
  });

  // Loading using a local git copy
  grunt.loadNpmTasks('intern');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-selenium-simple');

  // Register tasks
  grunt.registerTask('default', ['selenium', 'watch']);
  grunt.registerTask('test', ['selenium', 'intern:complete']);
};

Bump Selenium version and faster testing


'use strict';

module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jshint: {
            allFiles: ['Gruntfile.js', 'lib/**/*.js', 'test/**/*.js', 'index.js'],
            options: {
                jshintrc: '.jshintrc',
            }
        },
        mochacli: {
            all: ['test/**/*.js'],
            options: {
                reporter: 'spec',
                ui: 'tdd'
            }
        }
    })

    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-jshint')
    grunt.loadNpmTasks('grunt-mocha-cli')

    // Configure tasks
    grunt.registerTask('default', ['test'])
    grunt.registerTask('test', ['mochacli', 'jshint'])
}

'use strict';

module.exports = function(grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        jshint: {
            allFiles: ['Gruntfile.js', 'lib/**/*.js', 'test/**/*.js', 'index.js'],
            options: {
                jshintrc: '.jshintrc',
            }
        },
        mochacli: {
            all: ['test/**/*.js'],
            options: {
                reporter: 'spec',
                ui: 'tdd'
            }
        },
        'mocha_istanbul': {
            coveralls: {
                src: [ 'test/lib', 'test/lib/utils' ],
                options: {
                    coverage: true,
                    legend: true,
                    check: {
                        lines: 100,
                        statements: 99
                    },
                    root: './lib',
                    reportFormats: ['lcov']
                }
            }
        }
    })

    grunt.event.on('coverage', function(lcov, done){
        require('coveralls').handleInput(lcov, function(error) {
            if (error) {
                console.log(error)
                return done(error)
            }
            done()
        })
    })

    // Load the plugins
    grunt.loadNpmTasks('grunt-contrib-jshint')
    grunt.loadNpmTasks('grunt-mocha-cli')
    grunt.loadNpmTasks('grunt-mocha-istanbul')

    // Configure tasks
    grunt.registerTask('coveralls', ['mocha_istanbul:coveralls'])
    grunt.registerTask('default', ['test'])

    grunt.registerTask('test', ['mochacli', 'jshint', 'coveralls'])
}

Update grunt file to run coverage tests


var request = require('request')
var Q = require('Q')
var xml2js = require('xml2js')

var requestQ = function(url) {
	var defer = Q.defer()

	request(url, function(err, res, body) {
		if (err) {
			return defer.reject
		}

		return defer.resolve(body, res)
	})

	return defer.promise
}

var parseRSS = function(string) {
	var defer = Q.defer()
	xml2js.parseString(string, function(err, data) {
		if (err) {
			return defer.reject(err)
		}

		return defer.resolve(data)
	})

	return defer.promise
}

var add = function(db, url) {
	return requestQ(url).then(parseRSS).then(function(data) {
		var rss = data.rss.channel[0]
		var vals = [rss.title[0], rss.description[0], ((rss != null ? (ref$ = rss.ttl) != null ? ref$[0] : void 8 : void 8) || 30) * 60, url, rss.link[0]]
		var query = 'INSERT INTO Channels(title, description, ttl, url, link, last_update) VALUES(?, ?, ?, ?, ?, NOW() - 1)'

		return db.query(query, vals)
	})
}

module.exports = {
	add: add,
	parseRSS: parseRSS
}

var request = require('request')
var Q = require('Q')
var xml2js = require('xml2js')

var requestQ = function(url) {
	var defer = Q.defer()

	request(url, function(err, res, body) {
		if (err) {
			err.url = url
			return defer.reject(err)
		}

		return defer.resolve(body)
	})

	return defer.promise
}

var parseRSS = function(string) {
	var defer = Q.defer()
	xml2js.parseString(string, function(err, data) {
		if (err) {
			return defer.reject(err)
		}

		return defer.resolve(data)
	})

	return defer.promise
}

var add = function(db, url, group, title) {
	return requestQ(url).then(parseRSS).then(function(data) {
		var rss = data.rss.channel[0]
		var query = 'INSERT INTO Channels SET last_update = NOW() - 1, ?'

		var vals = {
			title: title || rss.title[0],
			group_id: group || 0,
			description: rss.description[0],
			ttl: (rss.ttl != null ? rss.ttl[0] : 5) * 60,
			url: url,
			link: rss.link[0]
		}
		console.log(vals)

		return db.query(query, vals)
	})
}

module.exports = {
	add: add,
	parseRSS: parseRSS
}

Use object notation to insert values to the db, looks nicer.


var spawn = require('child_process').spawn,
    objectAssign = require('object-assign');

module.exports = function exec(script, program) {
  var dotenvConfig = objectAssign({ silent: true }, {
    encoding: program.encoding,
    path: program.path
  });

  require('dotenv').config(dotenvConfig);

  var argvIndex = -1;
      firstArg = program.args[0];
  if (firstArg !== undefined) {
    argvIndex = process.argv.indexOf(firstArg);
  }
  var argv = argvIndex === -1 ? [] : process.argv.splice(argvIndex + 1),
      command = (typeof script === 'string' ? script : script.command) + ' ' + argv.join(' ');

  script.env = script.env || {};

  var env = objectAssign({}, process.env, script.env),
      sh = 'sh',
      shFlag = '-c';

  if (process.platform === 'win32') {
    sh = 'cmd';
    shFlag = '/c';
    command = '"' + command.trim() + '"';
  }

  if (!program.silent) {
    console.log('to be executed:', command);
  }
  spawn(sh, [shFlag, command], {
    env: env,
    windowsVerbatimArguments: process.platform === 'win32',
    stdio: 'inherit'
  }).on('close', function(code) {
    process.exit(code);
  });

};

var spawn = require('child_process').spawn,
    objectAssign = require('object-assign');

module.exports = function exec(script, program) {
  var dotenvConfig = objectAssign({ silent: true }, {
    encoding: program.encoding,
    path: program.path
  });

  require('dotenv').config(dotenvConfig);

  var argvIndex = -1,
      firstArg = program.args[0];
  if (firstArg !== undefined) {
    argvIndex = process.argv.indexOf(firstArg);
  }
  var argv = argvIndex === -1 ? [] : process.argv.splice(argvIndex + 1),
      command = (typeof script === 'string' ? script : script.command) + ' ' + argv.join(' ');

  script.env = script.env || {};

  var env = objectAssign({}, process.env, script.env),
      sh = 'sh',
      shFlag = '-c';

  if (process.platform === 'win32') {
    sh = 'cmd';
    shFlag = '/c';
    command = '"' + command.trim() + '"';
  }

  if (!program.silent) {
    console.log('to be executed:', command);
  }
  spawn(sh, [shFlag, command], {
    env: env,
    windowsVerbatimArguments: process.platform === 'win32',
    stdio: 'inherit'
  }).on('close', function(code) {
    process.exit(code);
  });

};

Fix definition of a global variable


module.exports = function (grunt) {

  /**
   * Configuration.
   */

  grunt.initConfig({
    uglify: {
      default: {
        options: {
          preserveComments: 'some'
        },
        files: {
          'angular-draganddrop.min.js': 'angular-draganddrop.js'
        }
      }
    }
  });

  /**
   * Tasks.
   */

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['uglify']);
};

module.exports = function (grunt) {

  /**
   * Configuration.
   */

  grunt.initConfig({
    uglify: {
      default: {
        options: {
          preserveComments: 'some',
          sourceMap: 'angular-draganddrop.min.map',
          sourceMappingURL: 'angular-draganddrop.min.map'
        },
        files: {
          'angular-draganddrop.min.js': 'angular-draganddrop.js'
        }
      }
    }
  });

  /**
   * Tasks.
   */

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['uglify']);
};

Add sourcemap options to uglify.


Ensembl.LayoutManager.showCookieMessage = function() {
  var cookiesAccepted = Ensembl.cookie.get('cookies_ok');

  if (!cookiesAccepted) {
    $(['
',
      '

',
      '
We use cookies to enhance the usability of our website. If you continue, we\'ll assume that you are happy to receive all cookies.
',
      '
<button>Don\'t show this again</button>
',
      '
Read more about EMBL-EBI policies: Cookies | Privacy.
',
      '
'
    ].join(''))
      .appendTo(document.body).show().find('button,div').on('click', function (e) {
        Ensembl.cookie.set('cookies_ok', 'yes');
        $(this).parents('div').first().fadeOut(200);
    }).filter('div').helptip({content:"Don't show this again"});
    return true;
  }

  return false;
};

Ensembl.LayoutManager.showCookieMessage = function() {
  var cookiesAccepted = Ensembl.cookie.get('cookies_ok');

  if (!cookiesAccepted) {
    $(['
',
      '
We use cookies to enhance the usability of our website. If you continue, we\'ll assume that you are happy to receive all cookies. ',
      'Read more about EMBL-EBI policies: Cookies | Privacy.',
      '
',
      'x',
      '
'
    ].join(''))
      .appendTo(document.body).show().find('span.close').on('click', function (e) {
        Ensembl.cookie.set('cookies_ok', 'yes');
        $(this).parents('div').first().fadeOut(200);
    });
    return true;
  }

  return false;
};

Update style on cookie warning


import './styles/styles.scss'

import React from 'react'
import ReactDOM from 'react-dom'
import { useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import { createHistory } from 'history'

import { Root } from './components/root'
import { initAuthAsync } from './core/auth'
import authRouteResolver from './core/auth/route-resolver'
import configureStore from './core/store'

import { fixScrollOn } from './page/fix-scroll'
import { checkIncognito } from './page/check-incognito'

import * as appActions from 'src/core/app'

const history = useRouterHistory(createHistory)({basename: '/'})

const store = configureStore()
const syncedHistory = syncHistoryWithStore(history, store)

// Initial auth loading action
store.dispatch(initAuthAsync())

ReactDOM.render((
  <Root history={syncedHistory} onEnter={authRouteResolver(store.getState)} store={store} />
), document.querySelector('.app-root'))

// Fix the scroll issues by default
fixScrollOn()

const isIncognito = checkIncognito()
if (isIncognito) {
  store.dispatch(appActions.isIncognito())
}

import './styles/styles.scss'

import React from 'react'
import ReactDOM from 'react-dom'
import { useRouterHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import { createHistory } from 'history'

import { Root } from './components/root'
import { initAuthAsync } from './core/auth'
import authRouteResolver from './core/auth/route-resolver'
import configureStore from './core/store'

import { fixScrollOn } from './page/fix-scroll'
import { checkIncognito } from './page/check-incognito'

// import * as appActions from 'src/core/app'

const history = useRouterHistory(createHistory)({basename: '/'})

const store = configureStore()
const syncedHistory = syncHistoryWithStore(history, store)

// Initial auth loading action
store.dispatch(initAuthAsync())

ReactDOM.render((
  <Root history={syncedHistory} onEnter={authRouteResolver(store.getState)} store={store} />
), document.querySelector('.app-root'))

// Fix the scroll issues by default
fixScrollOn()

const isIncognito = checkIncognito()
if (isIncognito) {
  // store.dispatch(appActions.isIncognito())
}

Disable incognito check because its not working


var { ToggleButton } = require('sdk/ui/button/toggle');
var tabs = require("sdk/tabs");

var button = ToggleButton({
  id: "tweet-that",
  label: "Tweet that link",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

var panel = require("sdk/panel").Panel({
  width: 320,
  height: 250,
  onHide: function() {
    button.state('window', {checked: false});
  }
});

function handleClick(state) {
  var twitter_uri = "https://twitter.com/intent/tweet?url=" +
    encodeURIComponent(tabs.activeTab.url) +
    "&text=" + encodeURIComponent(tabs.activeTab.title);
  panel.contentURL = twitter_uri;
  panel.show({ position: button });
}

var { ToggleButton } = require('sdk/ui/button/toggle');
var tabs = require("sdk/tabs");

var button = ToggleButton({
  id: "tweet-that",
  label: "Tweet that link",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

var panel = require("sdk/panel").Panel({
  width: 320,
  height: 270,
  onHide: function() {
    button.state('window', {checked: false});
  }
});

function handleClick(state) {
  var twitter_uri = "https://twitter.com/intent/tweet?url=" +
    encodeURIComponent(tabs.activeTab.url) +
    "&text=" + encodeURIComponent(tabs.activeTab.title);
  panel.contentURL = twitter_uri;
  panel.show({ position: button });
}

Make the panel slightly taller.


module.exports = function(grunt) {
    grunt.loadNpmTasks("grunt-mocha-test");
    grunt.loadNpmTasks("grunt-mocha-istanbul");

    var testOutputLocation = process.env.CIRCLE_TEST_REPORTS || "test_output";
    var artifactsLocation = process.env.CIRCLE_ARTIFACTS || "build_artifacts";
    grunt.initConfig({
        mochaTest: {
            test: {
                src: ["test/**/*.js"]
            },
            ci: {
                src: ["test/**/*.js"],
                options: {
                    reporter: "xunit",
                    captureFile: testOutputLocation + "/mocha/results.xml",
                    quiet: true
                }
            }
        },
        mocha_istanbul: {
            coverage: {
                src: ["test/**/*.js"],
                options: {
                    coverageFolder: artifactsLocation + "/coverage",
                    check: {
                        lines: 100,
                        statements: 100
                    },
                    reportFormats: ["lcov"]
                }
            }
        }
    });

    grunt.registerTask("test", ["mochaTest:test", "mocha_istanbul"]);
    grunt.registerTask("ci-test", ["mochaTest:ci", "mocha_istanbul"]);
    grunt.registerTask("default", "test");
};

module.exports = function(grunt) {
    grunt.loadNpmTasks("grunt-mocha-test");
    grunt.loadNpmTasks("grunt-mocha-istanbul");

    var testOutputLocation = process.env.CIRCLE_TEST_REPORTS || "test_output";
    var artifactsLocation = process.env.CIRCLE_ARTIFACTS || "build_artifacts";
    grunt.initConfig({
        mochaTest: {
            test: {
                src: ["test/**/*.js"]
            },
            ci: {
                src: ["test/**/*.js"],
                options: {
                    reporter: "xunit",
                    captureFile: testOutputLocation + "/mocha/results.xml",
                    quiet: true
                }
            }
        },
        mocha_istanbul: {
            coverage: {
                src: ["test/**/*.js"],
                options: {
                    coverageFolder: artifactsLocation + "/coverage",
                    check: {
                        lines: 100,
                        statements: 100,
                        branches: 100,
                        functions: 100
                    },
                    reportFormats: ["lcov"]
                }
            }
        }
    });

    grunt.registerTask("test", ["mochaTest:test", "mocha_istanbul"]);
    grunt.registerTask("ci-test", ["mochaTest:ci", "mocha_istanbul"]);
    grunt.registerTask("default", "test");
};

Check function and branch coverage


var module =  angular.module('ldsNavigation', ['ngRoute']);

module.directive('ldsNavigation', [function () {
    return {
        restrict: "E",
        scope: true,
        controller: ['$attrs', '$route', '$scope', 'lidsysFootballSchedule', function ($attrs, $route, $scope, footballSchedule) {
            var navItems = [],
                routeDef,
                route,
                currentRoute   = $route.current,
                routeScope = $scope.$new(),
                url,
                urlParamNum,
                urlParam,
                urlParamFind,
                urlParamReplace
            for (routeDef in $route.routes) {
                route            = $route.routes[routeDef]
                routeScope.route = route
                if ((!$attrs.filter || routeScope.$eval($attrs.filter)) &&
                    route.navigationLabel
                ) {
                    url = "#" + routeDef

                    for (urlParamNum = 0; urlParamNum < route.keys.length; urlParamNum++) {
                        urlParam        = route.keys[urlParamNum]
                        urlParamFind    = "/:" + urlParam.name
                        urlParamReplace = currentRoute.params[urlParam.name]

                        if (urlParam.optional) {
                            urlParamFind += "?"
                        }
                        else if (!urlParamReplace) {
                            throw "'" + urlParam.name + "' is required by navigation but cannot be found in current route"
                        }

                        url = url.replace(urlParamFind, "/" + urlParamReplace)
                    }

                    navItems.push({
                        url:      url,
                        label:    route.navigationLabel,
                        selected: (currentRoute.originalPath == route.originalPath)
                    })
                }
            }
            $scope.navItems = navItems
        }]
    }
}])

var module =  angular.module('ldsNavigation', ['ngRoute']);

module.directive('ldsNavigation', [function () {
    return {
        restrict: "E",
        scope: true,
        controller: ['$attrs', '$route', '$scope', function ($attrs, $route, $scope) {
            var navItems = [],
                routeDef,
                route,
                currentRoute   = $route.current,
                routeScope = $scope.$new(),
                url,
                urlParamNum,
                urlParam,
                urlParamFind,
                urlParamReplace
            for (routeDef in $route.routes) {
                route            = $route.routes[routeDef]
                routeScope.route = route
                if ((!$attrs.filter || routeScope.$eval($attrs.filter)) &&
                    route.navigationLabel
                ) {
                    url = "#" + routeDef

                    for (urlParamNum = 0; urlParamNum < route.keys.length; urlParamNum++) {
                        urlParam        = route.keys[urlParamNum]
                        urlParamFind    = "/:" + urlParam.name
                        urlParamReplace = currentRoute.params[urlParam.name]

                        if (urlParam.optional) {
                            urlParamFind += "?"
                        }
                        else if (!urlParamReplace) {
                            throw "'" + urlParam.name + "' is required by navigation but cannot be found in current route"
                        }

                        url = url.replace(urlParamFind, "/" + urlParamReplace)
                    }

                    navItems.push({
                        url:      url,
                        label:    route.navigationLabel,
                        selected: (currentRoute.originalPath == route.originalPath)
                    })
                }
            }
            $scope.navItems = navItems
        }]
    }
}])

Remove unused dependency and variable


const test = require('tape-catch');

import doxie from './module/index';

test('Does what the demo says', (is) => {
  const myData = [
    {isPrivate: false},
    {isPrivate: true},
    {isPrivate: false},
  ];

  is.deepEqual(
    doxie([])(myData),
    [
      {data: {isPrivate: false}},
      {data: {isPrivate: true}},
      {data: {isPrivate: false}},
    ],
    'without any plugins to pipe through'
  );

  const myFilter = ({data}) => !data.isPrivate;

  is.deepEqual(
    doxie([
      (comments) => comments.filter(myFilter),
    ])(myData),
    [
      {data: {isPrivate: false}},
      {data: {isPrivate: false}},
    ],
    'filtering data'
  );

  const myTemplate = ({data}, index) => ({data,
    output: `${data.isPrivate ?
      /* istanbul ignore next */ 'Private' :
      'Public'
    } n° ${index + 1}\n`
  });

  is.deepEqual(
    doxie([
      (comments) => comments.filter(myFilter),
      (comments) => comments.map(myTemplate),
      (comments) => comments.map(({output}) => (
        output ||
        /* istanbul ignore next */ ''
      )).join('')
    ])(myData),
    'Public n° 1\nPublic n° 2\n',
    'outputting docs for humans'
  );

  is.end();
});

const test = require('tape-catch');

import doxie from './module/index';

test('Does what the demo says', (is) => {
  const myData = [
    {isPrivate: false},
    {isPrivate: true},
    {isPrivate: false},
  ];

  is.deepEqual(
    doxie([])(myData),
    [
      {data: {isPrivate: false}},
      {data: {isPrivate: true}},
      {data: {isPrivate: false}},
    ],
    'without any plugins to pipe through'
  );

  const myFilter = ({data}) => !data.isPrivate;

  is.deepEqual(
    doxie([
      (comments) => comments.filter(myFilter),
    ])(myData),
    [
      {data: {isPrivate: false}},
      {data: {isPrivate: false}},
    ],
    'filtering data'
  );

  const myTemplate = ({data}, index) => ({data,
    output: `${data.isPrivate ? 'Private' : 'Public'} n° ${index + 1}\n`
  });

  is.deepEqual(
    doxie([
      (comments) => comments.filter(myFilter),
      (comments) => comments.map(myTemplate),
      (comments) => comments.map(({output}) => output || '').join('')
    ])(myData),
    'Public n° 1\nPublic n° 2\n',
    'outputting docs for humans'
  );

  is.end();
});

Revert "Ignore demo-specific statements from coverage"


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

    var config = require('./grunt_tasks/config');
    grunt.config.init(config);

    var packages = grunt.file.readJSON('./package.json');
    Object.keys(packages.devDependencies).forEach(function (p) {
        if (p.match(/^grunt-/)) {
            grunt.loadNpmTasks(p);
        }
    });

    grunt.registerTask('test', ['espower', 'karma']);
};

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

    var config = require('./grunt_tasks/config');
    grunt.config.init(config);

    var packages = grunt.file.readJSON('./package.json');
    Object.keys(packages.devDependencies).forEach(function (p) {
        if (p.match(/^grunt-/)) {
            grunt.loadNpmTasks(p);
        }
    });

    grunt.registerTask('test', ['espower', 'karma']);
    grunt.registerTask('development', ['sass:development']);
    grunt.registerTask('production', ['sass:production']);
};

Add tasks (development & production)


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

	// Display the execution time of grunt tasks
	require("time-grunt")(grunt);

	// Load all grunt-tasks in 'Build/Grunt-Options'.
	var gruntOptionsObj = require("load-grunt-configs")(grunt, {
		"config" : {
			src: "Build/Grunt-Options/*.js"
		}
	});
	grunt.initConfig(gruntOptionsObj);

	// Load all grunt-plugins that are specified in the 'package.json' file.
	require('jit-grunt')(grunt, {
		replace: 'grunt-text-replace'
	});

	/**
	 * Default grunt task.
	 * Compiles all .scss/.sass files with ':dev' options and
	 * validates all js-files inside Resources/Private/Javascripts with JSHint.
	 */
	grunt.registerTask("default", ["compass:dev", "jshint"]);

	/**
	 * Travis CI task
	 * Test all specified grunt tasks.
	 */
	grunt.registerTask("travis", ["init", "replace:init", "jshint", "deploy", "undeploy"]);

	/**
	 * Load custom tasks
	 * Load all Grunt-Tasks inside the 'Build/Grunt-Tasks' dir.
	 */
	grunt.loadTasks("Build/Grunt-Tasks");
};

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

	// Display the execution time of grunt tasks
	require("time-grunt")(grunt);

	// Load all grunt-tasks in 'Build/Grunt-Options'.
	var gruntOptionsObj = require("load-grunt-configs")(grunt, {
		"config" : {
			src: "Build/Grunt-Options/*.js"
		}
	});
	grunt.initConfig(gruntOptionsObj);

	// Load all grunt-plugins that are specified in the 'package.json' file.
	require('jit-grunt')(grunt, {
		replace: 'grunt-text-replace',
		cssmetrics: 'grunt-css-metrics'
	});

	/**
	 * Default grunt task.
	 * Compiles all .scss/.sass files with ':dev' options and
	 * validates all js-files inside Resources/Private/Javascripts with JSHint.
	 */
	grunt.registerTask("default", ["compass:dev", "jshint"]);

	/**
	 * Travis CI task
	 * Test all specified grunt tasks.
	 */
	grunt.registerTask("travis", ["init", "replace:init", "jshint", "deploy", "undeploy"]);

	/**
	 * Load custom tasks
	 * Load all Grunt-Tasks inside the 'Build/Grunt-Tasks' dir.
	 */
	grunt.loadTasks("Build/Grunt-Tasks");
};

Fix the mapping for the cssmetrics grunt task


import SPELLS from 'common/SPELLS';
import CoreCooldownThroughputTracker, { BUILT_IN_SUMMARY_TYPES } from 'parser/shared/modules/CooldownThroughputTracker';

class CooldownThroughputTracker extends CoreCooldownThroughputTracker {
  static cooldownSpells = [
    ...CoreCooldownThroughputTracker.cooldownSpells,
    {
      spell: SPELLS.ASCENDANCE_TALENT_ENHANCEMENT,
      summary: [
        BUILT_IN_SUMMARY_TYPES.DAMAGE,
      ],
    },
    {
      spell: SPELLS.BERSERKING,
      summary: [
        BUILT_IN_SUMMARY_TYPES.DAMAGE,
      ],
    },
  ];

  trackEvent(event) {
    this.activeCooldowns.forEach((cooldown) => {
      if (event.ability.guid !== SPELLS.DOOM_VORTEX.id) {
        cooldown.events.push(event);
      }
    });
  }
}

export default CooldownThroughputTracker;

import SPELLS from 'common/SPELLS';
import CoreCooldownThroughputTracker, { BUILT_IN_SUMMARY_TYPES } from 'parser/shared/modules/CooldownThroughputTracker';

class CooldownThroughputTracker extends CoreCooldownThroughputTracker {
  static cooldownSpells = [
    ...CoreCooldownThroughputTracker.cooldownSpells,
    {
      spell: SPELLS.ASCENDANCE_TALENT_ENHANCEMENT,
      summary: [
        BUILT_IN_SUMMARY_TYPES.DAMAGE,
      ],
    },
    {
      spell: SPELLS.ASTRAL_SHIFT,
      summary: [
        BUILT_IN_SUMMARY_TYPES.ABSORBED,
      ],
    },
    {
      spell: SPELLS.BERSERKING,
      summary: [
        BUILT_IN_SUMMARY_TYPES.DAMAGE,
      ],
    },
  ];

  trackEvent(event) {
    this.activeCooldowns.forEach((cooldown) => {
      if (event.ability.guid !== SPELLS.DOOM_VORTEX.id) {
        cooldown.events.push(event);
      }
    });
  }
}

export default CooldownThroughputTracker;

Add Astral shift to the absorbed ThroughputTracker


var hogan = require('hogan.js');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var getServiceProperties = require('./serviceProperties');

var templateFile = fs.readFileSync(path.resolve(__dirname, '../templates/spec.mustache'), 'utf-8');
var template = hogan.compile(templateFile);

var defaultRelease = 1;

function getReleaseNumber(release) {
  if (release) {
    return release;
  }

  return defaultRelease;
}

function getRequiredPackages(pkg) {
  return _.get(pkg, 'spec.requires', []);
}

function getExecutableFiles(pkg) {
  var name = pkg.name;
  var executableFiles = _.get(pkg, 'spec.executable', []).map(function (file) {
    return path.join('/usr/lib/', name, file);
  });

  return {
    executableFiles: executableFiles,
    hasExecutableFiles: executableFiles.length !== 0
  };
}

function getPostInstallCommands(pkg) {
  return _.get(pkg, 'spec.post', []);
}

module.exports = function (pkg, release) {
  var serviceProperties = Object.assign({
      release: getReleaseNumber(release),
      requires: getRequiredPackages(pkg),
      postInstallCommands: getPostInstallCommands(pkg),
      version: pkg.version
    },
    getExecutableFiles(pkg),
    getServiceProperties(pkg)
  );

  return template.render(serviceProperties);
};

var hogan = require('hogan.js');
var fs = require('fs');
var path = require('path');
var _ = require('lodash');
var getServiceProperties = require('./serviceProperties');

var templateFile = fs.readFileSync(path.resolve(__dirname, '../templates/spec.mustache'), 'utf-8');
var template = hogan.compile(templateFile);

var defaultRelease = 1;

function getReleaseNumber(release) {
  if (release) {
    return release;
  }

  return defaultRelease;
}

function getRequiredPackages(pkg) {
  return _.get(pkg, 'spec.requires', []);
}

function getExecutableFiles(pkg) {
  var name = pkg.name;
  var executableFiles = _.get(pkg, 'spec.executable', []).map(function (file) {
    return path.join('/usr/lib/', name, file);
  });

  return {
    executableFiles: executableFiles,
    hasExecutableFiles: executableFiles.length !== 0
  };
}

function getPostInstallCommands(pkg) {
  return _.get(pkg, 'spec.post', []);
}

module.exports = function (pkg, release) {
  var serviceProperties = _.assign({
      release: getReleaseNumber(release),
      requires: getRequiredPackages(pkg),
      postInstallCommands: getPostInstallCommands(pkg),
      version: pkg.version
    },
    getExecutableFiles(pkg),
    getServiceProperties(pkg)
  );

  return template.render(serviceProperties);
};

Use lodash assign to support earlier Node versions


/*
Copyright 2014 Spotify AB

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/* global require */

var gulp = require('gulp');
var qunit = require('gulp-qunit');
var jshint = require('gulp-jshint');
var htmlhint = require("gulp-htmlhint");
var csslint = require("gulp-csslint");

gulp.task('test', function() {
    return gulp.src('file://test.html').pipe(qunit());
});

gulp.task('jslint', function() {
    return gulp.src('*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(jshint.reporter('fail'));
});

gulp.task('htmllint', function() {
    return gulp.src(["*.html", "!test.html"])
        .pipe(htmlhint())
        .pipe(htmlhint.reporter())
        .pipe(htmlhint.failReporter());
});

gulp.task('csslint', function() {
    gulp.src('*.css')
        .pipe(csslint())
        .pipe(csslint.reporter())
        .pipe(csslint.failReporter());
});

/*
Copyright 2014 Spotify AB

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/* global require */

var gulp = require('gulp');
var qunit = require('gulp-qunit');
var jshint = require('gulp-jshint');
var htmlhint = require("gulp-htmlhint");
var csslint = require("gulp-csslint");

gulp.task('test', function() {
    return gulp.src('./test.html').pipe(qunit());
});

gulp.task('jslint', function() {
    return gulp.src('*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(jshint.reporter('fail'));
});

gulp.task('htmllint', function() {
    return gulp.src(["*.html", "!test.html"])
        .pipe(htmlhint())
        .pipe(htmlhint.reporter())
        .pipe(htmlhint.failReporter());
});

gulp.task('csslint', function() {
    gulp.src('*.css')
        .pipe(csslint())
        .pipe(csslint.reporter())
        .pipe(csslint.failReporter());
});

Revert "Fix headless unit test running"


/**
 * Poster v0.1.0
 * A React webapp to list upcoming movies and maintain a watchlist, powered by TMDb
 *
 * Author: Kushal Pandya <kushalspandya@gmail.com> (https://doublslash.com)
 * Date: 13 June, 2016
 * License: MIT
 *
 * Section > Jumbotron
 */

import React from "react";
import HTTP from "superagent";

import LoadingMessage from "../../Widgets/LoadingAnimation";

import SearchBox from "./Shared/SearchBox";
import MovieCardList from "./Shared/MovieCardList";

export default
class Jumbotron extends React.Component {
    constructor() {
        super();
    }

    handleSearch(query) {
        this.context.router.push({
            pathname: 'search',
            query: {
                query: query
            }
        });
    }

    render() {
        return (

Welcome to Poster!

A minimalist Movies catalog, powered by TMDb.

                <SearchBox handleSearch={this.handleSearch.bind(this)}/>

        );
    }
}

/*
 * Declare Context Properties
 */
Jumbotron.contextTypes = {
    router: React.PropTypes.object.isRequired
};

/**
 * Poster v0.1.0
 * A React webapp to list upcoming movies and maintain a watchlist, powered by TMDb
 *
 * Author: Kushal Pandya <kushalspandya@gmail.com> (https://doublslash.com)
 * Date: 13 June, 2016
 * License: MIT
 *
 * Section > Jumbotron
 */

import React from "react";

import LoadingMessage from "../../Widgets/LoadingAnimation";

import SearchBox from "./Shared/SearchBox";
import MovieCardList from "./Shared/MovieCardList";

export default
class Jumbotron extends React.Component {
    constructor() {
        super();
    }

    render() {
        return (

Welcome to Poster!

A minimalist Movies catalog, powered by TMDb.

                <SearchBox handleSearch={this.props.handleSearch}/>

        );
    }
}

Move Search handler to Home component.


module.exports = function bindSassMiddleware (keystone, app) {
	// the sass option can be a single path, or array of paths
	// when set, we configure the node-sass middleware

	var sassPaths = keystone.get('sass');
	var sassOptions = keystone.get('sass options') || {};
	var debug = require('debug')('keystone:core:bindSassMiddleware');

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

	if (Array.isArray(sassPaths)) {
		var sassMiddleware;
		try {
			debug('adding sass');
			sassMiddleware = require('node-sass-middleware');
		} catch(e) {
			if (e.code === 'MODULE_NOT_FOUND') {
				console.error(
					'\nERROR: node-sass not found.\n' +
					'\nPlease install the node-sass-middleware from npm to use the `sass` option.' +
					'\nYou can do this by running "npm install node-sass-middleware --save".\n'
				);
				process.exit(1);
			} else {
				throw e;
			}
		}
		sassPaths.forEach(function(path) {
			app.use(sassMiddleware(Object.assign({
				src: keystone.expandPath(path),
				dest: keystone.expandPath(path),
				outputStyle: keystone.get('env') === 'production' ? 'compressed' : 'nested'
			}, sassOptions)));
		});
	}
};

module.exports = function bindSassMiddleware (keystone, app) {
	// the sass option can be a single path, or array of paths
	// when set, we configure the node-sass middleware

	var sassPaths = keystone.get('sass');
	var sassOptions = keystone.get('sass options') || {};
	var debug = require('debug')('keystone:core:bindSassMiddleware');
	var _ = require('underscore');

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

	if (Array.isArray(sassPaths)) {
		var sassMiddleware;
		try {
			debug('adding sass');
			sassMiddleware = require('node-sass-middleware');
		} catch(e) {
			if (e.code === 'MODULE_NOT_FOUND') {
				console.error(
					'\nERROR: node-sass not found.\n' +
					'\nPlease install the node-sass-middleware from npm to use the `sass` option.' +
					'\nYou can do this by running "npm install node-sass-middleware --save".\n'
				);
				process.exit(1);
			} else {
				throw e;
			}
		}
		sassPaths.forEach(function(path) {
			app.use(sassMiddleware(_.extend({
				src: keystone.expandPath(path),
				dest: keystone.expandPath(path),
				outputStyle: keystone.get('env') === 'production' ? 'compressed' : 'nested'
			}, sassOptions)));
		});
	}
};

Use `_.extend` instead of `Object.assign` in Node code


const { createHash } = require("crypto");
const { spawn } = require("child_process");

function parseRTPPacket(buffer) {
  const hasExtensions = (buffer[0] << 3) >>> 7;

  const payload = buffer.slice(hasExtensions ? 16 : 12);
  const { length } = payload;

  return {
    id: buffer.readUInt16BE(2),
    timestamp: buffer.readUInt32BE(4),
    payload,
    length
  };
}

function parseRTCPPacket(buffer) {
  const payload = buffer;
  const timestamp = buffer.readUInt32BE(16);
  return {
    timestamp,
    payload
  };
}

function getMD5Hash(str) {
  const md5 = createHash("md5");
  md5.update(str);

  return md5.digest("hex");
}

function parseTransport(transport) {
  const obj = {};
  const transportParts = transport.split(";");

  for (let i = 0; i < transportParts.length; i++) {
    const part = transportParts[i];
    const index = part.indexOf("=");

    if (index !== part.length - 1) {
      obj[part.substring(0, index)] = part.substring(index + 1);
    }
  }

  return obj;
}

module.exports = {
  parseRTPPacket,
  parseRTCPPacket,
  getMD5Hash,
  parseTransport
};

const { createHash } = require("crypto");
const { spawn } = require("child_process");

function parseRTPPacket(buffer) {
  const hasExtensions = (buffer[0] << 3) >>> 7;
  const num_csrc_identifiers = (buffer[0] & 0x0F);

  const payload = buffer.slice((num_csrc_identifiers * 4) + (hasExtensions ? 16 : 12));
  const { length } = payload;

  return {
    id: buffer.readUInt16BE(2),
    timestamp: buffer.readUInt32BE(4),
    payload,
    length
  };
}

function parseRTCPPacket(buffer) {
  const payload = buffer;
  const timestamp = buffer.readUInt32BE(16);
  return {
    timestamp,
    payload
  };
}

function getMD5Hash(str) {
  const md5 = createHash("md5");
  md5.update(str);

  return md5.digest("hex");
}

function parseTransport(transport) {
  const obj = {};
  const transportParts = transport.split(";");

  for (let i = 0; i < transportParts.length; i++) {
    const part = transportParts[i];
    const index = part.indexOf("=");

    if (index !== part.length - 1) {
      obj[part.substring(0, index)] = part.substring(index + 1);
    }
  }

  return obj;
}

module.exports = {
  parseRTPPacket,
  parseRTCPPacket,
  getMD5Hash,
  parseTransport
};

Handle CSRC count in the RTP header


var gulp = require('gulp');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var sass = require('gulp-sass');

gulp.task('scripts', function() {
  return gulp.src(['resources/public/js/lib/*.js'])
    .pipe(uglify())
    .pipe(gulp.dest('resources/public/js'));
});

gulp.task('copy', function() {
  gulp.src('bower_components/normalize-css/normalize.css')
    .pipe(rename('_normalize.scss'))
    .pipe(gulp.dest('bower_components/normalize-css'));
});

gulp.task('styles', ['copy'], function() {
  var opts = {
    outputStyle: 'compressed',
    includePaths: [
      'bower_components/bourbon/app/assets/stylesheets',
      'bower_components/sass-mediaqueries',
      'bower_components/normalize-css'
    ]
  };

  gulp.src('scss/style.scss')
    .pipe(sass(opts))
    .pipe(gulp.dest('resources/public/css'));
});

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

gulp.task('build', ['scripts', 'copy', 'styles']);
gulp.task('default', ['build', 'watch']);

var gulp = require('gulp');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
var sass = require('gulp-sass');

gulp.task('scripts', function() {
  return gulp.src(['resources/public/js/lib/*.js'])
    .pipe(uglify())
    .pipe(gulp.dest('resources/public/js'));
});

gulp.task('copy', function() {
  return gulp.src('bower_components/normalize-css/normalize.css')
    .pipe(rename('_normalize.scss'))
    .pipe(gulp.dest('bower_components/normalize-css'));
});

gulp.task('styles', ['copy'], function() {
  var opts = {
    outputStyle: 'compressed',
    includePaths: [
      'bower_components/bourbon/app/assets/stylesheets',
      'bower_components/sass-mediaqueries',
      'bower_components/normalize-css'
    ]
  };

  return gulp.src('scss/style.scss')
    .pipe(sass(opts))
    .pipe(gulp.dest('resources/public/css'));
});

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

gulp.task('build', ['scripts', 'copy', 'styles']);
gulp.task('default', ['build', 'watch']);

Return the stream from all tasks so deps work.


// ($(this).val() && Number($(this).val()) > 0)

function isValidAmount(input) {
    return input && Number(input) > 0
}

exports.isValidAmount = isValidAmount

// ($(this).val() && Number($(this).val()) > 0)

function isValidAmount(input) {
    var maxVal = 100000000
    var minVal = 0

    var value = input.split('.')
    var pounds = value[0]
    var pence = value[1]
    pounds = pounds.replaceAll(/^£|[\s,]+/g, "")

    if(pence) {
        var lengthOfPence = pence.length
        if(lengthOfPence > 2) {
            return false
        }
    }

    var amount = Number(pounds * 100)
    if(pence) {
        amount += Number(pence)
    }

    if(amount) {
        console.log('Amount: ' + amount)
        if(amount > maxVal || amount < minVal) {
            return false
        }
    } else {
        return false
    }

    return true
}

exports.isValidAmount = isValidAmount

Add functionality for validating currency input


var Renderer = {
    create: function() {
        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(this.renderer.domElement);

        return this.renderer;
    },

    setCardboardEffect: function() {
        this.cbEffect = new THREE.CardboardEffect( this.renderer );
        this.cbEffect.setSize( window.innerWidth, window.innerHeight );

        return this.cbEffect;
    },

    handleResize: function () {
        this.renderer.setSize( window.innerWidth, window.innerHeight );
    }
};

module.exports = Renderer;

var Renderer = {
    create: function() {
        this.renderer = new THREE.WebGLRenderer();

        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.setPixelRatio(window.devicePixelRatio ? window.devicePixelRatio : 1);

        document.body.appendChild(this.renderer.domElement);

        return this.renderer;
    },

    setCardboardEffect: function() {
        this.cbEffect = new THREE.CardboardEffect( this.renderer );
        this.cbEffect.setSize( window.innerWidth, window.innerHeight );

        return this.cbEffect;
    },

    handleResize: function () {
        this.renderer.setSize( window.innerWidth, window.innerHeight );
    }
};

module.exports = Renderer;

Add pixel ratio renderer size support


var rules = [
    [/(\d{4})/, function(match, date) {
        date.start = match[0];
        date.end = match[1];
    }]
];

module.exports = {
    parse: function(str) {
        var date = {};

        rules.forEach(function(options) {
            var match = options[0].exec(str);
            if (match) {
                options[1](match, date);

                for (var prop in date) {
                    date[prop] = parseFloat(date[prop]);
                }
            }
        });

        return date;
    }
};

var rules = [
    [/^(\d{4})$/, function(match, date) {
        date.start = match[0];
        date.end = match[1];
    }]
];

// Punctuation
// (Both ASCII and Japanese)
// http://www.localizingjapan.com/blog/2012/01/20/regular-expressions-for-japanese-text/
// Include full width characters?
// Exclude the -, ?, / marks, they're used in some dates
var puncRegex = /[!"#$%&()*+,.:;<=>@[\\\]^_`{|}~\u3000-\u303F]/g;

module.exports = {
    parse: function(str) {
        var date = {};

        rules.forEach(function(options) {
            var match = options[0].exec(str);
            if (match) {
                options[1](match, date);

                for (var prop in date) {
                    date[prop] = parseFloat(date[prop]);
                }
            }
        });

        return date;
    },

    cleanString: function(str) {
        str = str.toLowerCase();
        str = this.stripPunctuation(str);
        return str;
    },

    stripPunctuation: function(str) {
        return str.replace(puncRegex, " ")
            .replace(/(\d+)'s/g, "$1s")
            .replace(/\s+/, " ")
            .trim();
    }
};

Bring in punctuation cleaning logic from romaji-name.


'use strict';

const childProcess = require('child_process');
const fs = require('fs');

module.exports = function(type) {
    process.argv.shift();
    process.argv.shift();
    var path = process.argv.length < 1 ? 'output_data' : process.argv[0];

    var process_generate = childProcess.spawn('./node_modules/podigg/bin/generate-' + type + '.js', process.argv);
    process_generate.stdout.pipe(process.stdout);
    process_generate.stderr.pipe(process.stderr);
    process_generate.on('close', (code_generate) => {
        if(!code_generate) {
            var process_convert = childProcess.spawn('./node_modules/gtfs2lc/bin/gtfs2lc.js', [path + '/gtfs', '-f', 'turtle', '-r', '-t', '-a']);
            process_convert.stdout.pipe(fs.createWriteStream(path + '/lc.ttl'));
            process_convert.stderr.pipe(process.stderr);
            process_convert.on('close', (code_convert) => {
                if (code_generate) {
                    throw new Error('Conversion exited with exit code ' + code_convert);
                }
            });
        } else {
            throw new Error('Generation exited with exit code ' + code_generate);
        }
    });
}

'use strict';

const childProcess = require('child_process');
const fs = require('fs');

module.exports = function(type) {
    process.argv.shift();
    process.argv.shift();
    var path = process.argv.length < 1 ? 'output_data' : process.argv[0];

    var process_generate = childProcess.spawn(__dirname + '/../node_modules/podigg/bin/generate-' + type + '.js', process.argv);
    process_generate.stdout.pipe(process.stdout);
    process_generate.stderr.pipe(process.stderr);
    process_generate.on('close', (code_generate) => {
        if(!code_generate) {
            var process_convert = childProcess.spawn(__dirname + '/../node_modules/gtfs2lc/bin/gtfs2lc.js', [path + '/gtfs', '-f', 'turtle', '-r', '-t', '-a']);
            process_convert.stdout.pipe(fs.createWriteStream(path + '/lc.ttl'));
            process_convert.stderr.pipe(process.stderr);
            process_convert.on('close', (code_convert) => {
                if (code_generate) {
                    throw new Error('Conversion exited with exit code ' + code_convert);
                }
            });
        } else {
            throw new Error('Generation exited with exit code ' + code_generate);
        }
    });
}

Fix external script invocation failing with ENOENT error


$(document).ready(function() {
  $('form input[name="subreddit"]').focus();
});

var CharmView = Backbone.View.extend({

  el: $("#charm-form"),

  events: {
    "submit": "submit"
  },

  initialize: function() {
  },

  submit: function(e) {
    $.ajax({
      url: "/charm",
      type: "POST",
      accepts: "application/json",
      data: this.$el.serialize(),
      success: function(data) {
        console.log(data);
      }
    });

    return false; // don't actually submit of the form.
  },
});

view = new CharmView();

Create a simple backbone view to test new ajax endpoint


/**
 * Convert a string to a number
 * @param {string} str
 * @returns {number} the hashed string
 * @see https://stackoverflow.com/a/51276700
 */
function hash(str) {
  let hash = 0x811c9dc5
  var prime = 0x000193

  for (let i = 0; i < str.length; i++) {
    hash = hash ^ str.charCodeAt(i)
    hash *= prime
  }

  return hash
}

export class OccurrenceCounter {
  constructor() {
    this._items = Object.create(null)
  }

  /**
   * Converting the CSS string to an integer because this collection potentially
   * becomes very large and storing the values as integers saves 10-70%
   *
   * @see https://github.com/projectwallace/css-analyzer/pull/242
   * @param {string} item
   * @returns {number} the count for this item
   */
  push(item) {
    const key = hash(item)

    if (this._items[key]) {
      return this._items[key]++
    }

    return this._items[key] = 1
  }

  count() {
    return Object.keys(this._items).length
  }
}

/**
 * Convert a string to a number
 * @param {string} str
 * @returns {number} the hashed string
 * @see https://stackoverflow.com/a/51276700
 */
function hash(str) {
  const prime = 403
  let hash = 167

  for (let i = 0; i < str.length; i++) {
    hash = hash ^ str.charCodeAt(i)
    hash *= prime
  }

  return hash
}

export class OccurrenceCounter {
  constructor() {
    this._items = Object.create(null)
  }

  /**
   * Converting the CSS string to an integer because this collection potentially
   * becomes very large and storing the values as integers saves 10-70%
   *
   * @see https://github.com/projectwallace/css-analyzer/pull/242
   * @param {string} item
   * @returns {number} the count for this item
   */
  push(item) {
    const key = hash(item)

    if (this._items[key]) return
    this._items[key] = 1
  }

  count() {
    return Object.keys(this._items).length
  }
}

Fix let/var in occurencecounter hash


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

module.exports = function ()
{
    return function (resource, next)
    {
        // create a new texture if the data is an Image object
        if (resource.data && resource.isImage)
        {
            var baseTexture = new core.BaseTexture(resource.data, null, core.utils.getResolutionOfUrl(resource.url));
            baseTexture.imageUrl = resource.url;
            resource.texture = new core.Texture(baseTexture);
            // lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
            core.utils.BaseTextureCache[resource.url] = resource.texture;
            core.utils.TextureCache[resource.url] = resource.texture;
        }

        next();
    };
};

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

module.exports = function ()
{
    return function (resource, next)
    {
        // create a new texture if the data is an Image object
        if (resource.data && resource.isImage)
        {
            var baseTexture = new core.BaseTexture(resource.data, null, core.utils.getResolutionOfUrl(resource.url));
            baseTexture.imageUrl = resource.url;
            resource.texture = new core.Texture(baseTexture);
            // lets also add the frame to pixi's global cache for fromFrame and fromImage fucntions
            core.utils.BaseTextureCache[resource.url] = baseTexture;
            core.utils.TextureCache[resource.url] = resource.texture;
        }

        next();
    };
};

Fix Texture objects in BaseTextureCache


/**
 * This file is part of Shuup.
 *
 * Copyright (c) 2012-2018, Shuup Inc. All rights reserved.
 *
 * This source code is licensed under the OSL-3.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

//-- jQuery
var jquery = require("jquery");
window.$ = window.jQuery = jquery;

const _ = require('lodash');
window._ = _;

window.Dropzone = require('dropzone');
Dropzone.autoDiscover = false;

import select2 from 'select2';
select2($);

require('bootstrap');
require('chart.js');
require('imagelightbox');
require('get-size');
require('desandro-matches-selector');
require('ev-emitter');
require('fizzy-ui-utils');
require('jquery.easing');
require('jquery.scrollbar');
require('moment');
require('outlayer');
require('popper.js');
require('summernote/dist/summernote-bs4.js');
require('tether');
require('@chenfengyuan/datepicker');

window.Shepherd = require('tether-shepherd');

const m = require('mithril');
window.m = m;

/**
 * This file is part of Shuup.
 *
 * Copyright (c) 2012-2018, Shuup Inc. All rights reserved.
 *
 * This source code is licensed under the OSL-3.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

//-- jQuery
var jquery = require("jquery");
window.$ = window.jQuery = jquery;

const _ = require('lodash');
window._ = _;

window.Dropzone = require('dropzone');
Dropzone.autoDiscover = false;

window.OrderCreator = require('../../modules/orders/static_src/create/index.js');
window.Shepherd = require('tether-shepherd');

const m = require('mithril');
window.m = m;

import select2 from 'select2';
select2($);

require('bootstrap');
require('chart.js');
require('imagelightbox');
require('get-size');
require('desandro-matches-selector');
require('ev-emitter');
require('fizzy-ui-utils');
require('jquery.easing');
require('jquery.scrollbar');
require('moment');
require('outlayer');
require('popper.js');
require('summernote/dist/summernote-bs4.js');
require('tether');
require('@chenfengyuan/datepicker');

Add OrderCreator to global scope


var Deffy = require("deffy")
  , Typpy = require("typpy")
  ;

var SEPARATOR = "_";

function SubElmId(type, name, parent) {

    if (Typpy(type, SubElm)) {
        parent = name;
        name = type.name;
        type = type.type;
    }

    this.type = type;
    this.name = name;
    this.parentId = parent;
}

SubElmId.prototype.toString = function () {
    return [this.type, this.parentId, this.name].join(SEPARATOR);
};

function SubElm(type, data, parent) {
    if (Typpy(data, SubElm)) {
        return data;
    }
    this.name = SubElm.Name(data);
    this.label = Deffy(data.label, this.name);
    this.type = type;
    this.id = new SubElmId(this, parent.id)
    this.lines = {};
}

SubElm.Name = function (input) {
    return input.name || input.event || input.serverMethod || input.method;
};

SubElm.Id = SubElmId;

module.exports = SubElm;

var Deffy = require("deffy")
  , Typpy = require("typpy")
  , Enny = require("enny")
  ;

var SEPARATOR = "_";

function SubElmId(type, name, parent) {

    if (Typpy(type, SubElm)) {
        parent = name;
        name = type.name;
        type = type.type;
    }

    this.type = type;
    this.name = name;
    this.parentId = parent;
}

SubElmId.prototype.toString = function () {
    return [this.type, this.parentId, this.name].join(SEPARATOR);
};

function SubElm(type, data, parent) {
    if (Typpy(data, SubElm)) {
        return data;
    }
    if (typeof type === "string") {
        type = Enny.TYPES[type];
    }
    this.icon = type.icon;
    this.name = SubElm.Name(data);
    this.label = Deffy(data.label, this.name);
    this.type = type.type;
    this.id = new SubElmId(this, parent.id)
    this.lines = {};
}

SubElm.Name = function (input) {
    return input.name || input.event || input.serverMethod || input.method;
};

SubElm.Id = SubElmId;

module.exports = SubElm;

Use Enny to get the types


import should from 'should'
import getJson from './getJson'

let endpoint = '/stats/homepagev2'
let query = {
  GameScope: 'Season',
  LeagueID: '00',
  PlayerOrTeam: 'Player',
  PlayerScope: 'All Players',
  Season: '2015-16',
  SeasonType: 'Regular Season',
  StatType: 'Traditional'
}

describe('utils/getJson', () => {
  it('returns response/error as a Promise', (done) => {
    let request = getJson(endpoint, { query })
    request.should.be.Promise()
    done()
  })

  it('resolves to JSON response', (done) => {
    getJson(endpoint, { query }).then((res) => {
      should.exist(res)
      res.should.have.property('body')
      done()
    })
  })

  it('throws 400 on invalid request', (done) => {
    getJson(endpoint, { query: {} }).catch((err) => {
      should.exist(err)
      err.statusCode.should.equal(400)
      done()
    })
  })
})

import should from 'should'
import getJson from './getJson'

let endpoint = '/stats/homepagev2'
let query = {
  GameScope: 'Season',
  LeagueID: '00',
  PlayerOrTeam: 'Player',
  PlayerScope: 'All Players',
  Season: '2015-16',
  SeasonType: 'Regular Season',
  StatType: 'Traditional'
}

describe('utils/getJson', () => {
  it('returns response/error as a Promise', (done) => {
    let request = getJson(endpoint, { query })
    request.should.be.Promise()
    done()
  })

  it('resolves to JSON response', (done) => {
    getJson(endpoint, { query }).then((res) => {
      should.exist(res)
      res.should.have.property('body')
      done()
    }).catch((e) => {
      console.log(e)
    })
  }).timeout(10000)

  it('throws 400 on invalid request', (done) => {
    getJson(endpoint, { query: {} }).catch((err) => {
      should.exist(err)
      err.statusCode.should.equal(400)
      done()
    })
  })
})

Increase timeout for request test


import SPECS from 'common/SPECS';
import SPEC_ANALYSIS_COMPLETENESS from 'common/SPEC_ANALYSIS_COMPLETENESS';

import CombatLogParser from './CombatLogParser';
import CHANGELOG from './CHANGELOG';

export default {
  spec: SPECS.DISCIPLINE_PRIEST,
  maintainer: '@Reglitch',
  completeness: SPEC_ANALYSIS_COMPLETENESS.GREAT, // When changing this please make a PR with ONLY this value changed, we will do a review of your analysis to find out of it is complete enough.
  changelog: CHANGELOG,
  parser: CombatLogParser,
};

import SPECS from 'common/SPECS';
import SPEC_ANALYSIS_COMPLETENESS from 'common/SPEC_ANALYSIS_COMPLETENESS';

import CombatLogParser from './CombatLogParser';
import CHANGELOG from './CHANGELOG';

export default {
  spec: SPECS.DISCIPLINE_PRIEST,
  maintainer: '@Reglitch',
  completeness: SPEC_ANALYSIS_COMPLETENESS.GOOD, // When changing this please make a PR with ONLY this value changed, we will do a review of your analysis to find out of it is complete enough.
  changelog: CHANGELOG,
  parser: CombatLogParser,
};

Change Disc Priest's completeness to Good since it doesn't have the module changes yet


// @flow

/* eslint-disable no-console */

import os from 'os';
import path from 'path';
import { sshConnect, sshExec } from '../util/ssh';
import { readFile } from '../util/fs';
import { exitError } from '../exit';

import typeof { default as Yargs } from 'yargs';
import type { BaseArgs } from './index';

const name = 'login';
const description =
  'Uses your SSH key to authenticate you with the amazee.io API';

export async function setup(yargs: Yargs): Promise<Object> {
  return yargs.usage(`$0 ${name} - ${description}`).argv;
}

type Args = BaseArgs;

export async function run(args: Args): Promise<number> {
  const { clog = console.log } = args;

  const privateKey = await readFile(path.join(os.homedir(), '.ssh', 'id_rsa'));
  const connection = await sshConnect({
    host: 'localhost',
    port: 2020,
    username: 'api',
    privateKey,
  });

  const output = await sshExec(connection, 'login');

  // TODO: Instead of logging the output, save it.
  clog(output.toString());

  // Be responsible and close the connection after our transaction.
  connection.end();

  return 0;
}

export default {
  setup,
  name,
  description,
  run,
};

// @flow

/* eslint-disable no-console */

import os from 'os';
import path from 'path';
import { sshConnect, sshExec } from '../util/ssh';
import { readFile, writeFile } from '../util/fs';
import { exitError } from '../exit';

import typeof { default as Yargs } from 'yargs';
import type { BaseArgs } from './index';

const name = 'login';
const description =
  'Uses your SSH key to authenticate you with the amazee.io API';

export async function setup(yargs: Yargs): Promise<Object> {
  return yargs.usage(`$0 ${name} - ${description}`).argv;
}

type Args = BaseArgs;

export async function run(args: Args): Promise<number> {
  const { clog = console.log } = args;

  // TODO: We need to make the ssh path lookup smarter or request it via prompt.
  const homeDir = os.homedir();
  const privateKeyFilePath = path.join(homeDir, '.ssh', 'id_rsa');
  const privateKey = await readFile(privateKeyFilePath);
  const connection = await sshConnect({
    host: 'localhost',
    port: 2020,
    username: 'api',
    privateKey,
  });

  const output = await sshExec(connection, 'login');
  const token = output.toString();
  const tokenFilePath = path.join(homeDir, '.ioauth');
  await writeFile(tokenFilePath, token);

  clog('Login successful');

  // Be responsible and close the connection after our transaction.
  connection.end();

  return 0;
}

export default {
  setup,
  name,
  description,
  run,
};

Write bearer token to user home dir.


'use strict';

var fs = require('fs');
var mkdirp = require('mkdirp');
var Path = require('path');

function path () {
  var segments = [].slice.call(arguments);
  segments.unshift('./test');
  return Path.join.apply(Path, segments);
}

function readFile (filepath) {
  return fs.readFileSync(filepath, 'utf8');
}

module.exports = {
  makeDir: function (filepath) {
    return mkdirp.sync(path(filepath));
  },

  readDir: function (filepath) {
    return fs.readdirSync(path(filepath));
  },

  readFixture: function (filename) {
    return readFile(path('fixtures', filename));
  },

  readResult: function (filename) {
    return readFile(path('dist', filename));
  }
};

'use strict';

var fs = require('fs');
var mkdirp = require('mkdirp');
var Path = require('path');

function path () {
  var segments = [].slice.call(arguments);
  segments.unshift('./test');
  return Path.join.apply(Path, segments);
}

function readFile (filepath) {
  return fs.readFileSync(filepath, 'utf8').trim();
}

module.exports = {
  makeDir: function (filepath) {
    return mkdirp.sync(path(filepath));
  },

  readDir: function (filepath) {
    return fs.readdirSync(path(filepath));
  },

  readFixture: function (filename) {
    return readFile(path('fixtures', filename));
  },

  readResult: function (filename) {
    return readFile(path('dist', filename));
  }
};

Make readFile utility return trimmed strings


import Promise from 'bluebird';
import Immutable from 'immutable';

export default function userState() {

  return (req, res, next) => {
    loadUserData(req).then(loadedData => {
      req.userState = Immutable.Map().merge(...loadedData);
      next();
    });
  };

}

// Gracefully settle all promises, ignore failed.
function loadUserData(req) {
  const dataSources = [
    loadTodos()
  ];

  return Promise.settle(dataSources).then(receivedData =>
    receivedData
      .filter(promise => promise.isFulfilled())
      .map(promise => promise.value())
  );
}

// Simulate async action.
function loadTodos() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const todos = {
        todos: {
          list: [
            {id: 2, title: 'relax'}
          ]
        }
      };

      resolve(todos);
    }, 20);
  });
}

import Promise from 'bluebird';
import Router from 'react-router';
import routes from '../../client/routes';
import {Map} from 'immutable';

export default function userState() {

  return (req, res, next) => {
    getRouterState(req.originalUrl)
      .then(routerState => loadUserData(routerState, req))
      .then(loadedData => {
        req.userState = Map().merge(...loadedData);
        next();
      });
  };

}

function getRouterState(originalUrl) {
  return new Promise((resolve, reject) => {
    Router.run(routes, originalUrl, (Root, state) => resolve(state));
  });
}

function loadUserData(routerState, req) {
  // We can use params and routesAsPath to preload only current route, which is
  // convenient  if we are using higher order components for client loading.
  // const {params, routes} = routerState;
  // const routesAsPath = routerState.routes
  //   .map(route => route.name)
  //   .filter(name => name)
  //   .join('/');

  const dataSources = [
    loadTodos()
  ];

  // Gracefully settle all promises, ignore failed.
  return Promise.settle(dataSources).then(receivedData =>
    receivedData
      .filter(promise => promise.isFulfilled())
      .map(promise => promise.value())
  );
}

// Simulate async action.
function loadTodos() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const todos = {
        todos: {
          list: [
            {id: 2, title: 'relax'}
          ]
        }
      };

      resolve(todos);
    }, 20);
  });
}

Add getRouterState for server render.


var cookie = require('cookie');

/*
 * A class that encapsulates information about the
 * current HTTP request from FastBoot. This is injected
 * on to the FastBoot service.
 */
function FastBootInfo(request, response) {
  this.request = request;
  this.response = response;

  this.cookies = this.extractCookies(request);
}

FastBootInfo.prototype.extractCookies = function(request) {
  // If cookie-parser middleware has already parsed the cookies,
  // just use that.
  if (request.cookies) {
    return request.cookies;
  }

  // Otherwise, try to parse the cookies ourselves, if they exist.
  var cookies = request.get('cookie');
  if (cookies) {
    return cookie.parse(cookies);
  }

  // Return an empty object instead of undefined if no cookies are present.
  return {};
};

/*
 * Registers this FastBootInfo instance in the registry of an Ember
 * ApplicationInstance. It is configured to be injected into the FastBoot
 * service, ensuring it is available inside instance initializers.
 */
FastBootInfo.prototype.register = function(instance) {
  instance.register('info:-fastboot', this, { instantiate: false });
  instance.inject('service:fastboot', '_fastbootInfo', 'info:-fastboot');
};

module.exports = FastBootInfo;

var cookie = require('cookie');

/*
 * A class that encapsulates information about the
 * current HTTP request from FastBoot. This is injected
 * on to the FastBoot service.
 */
function FastBootInfo(request, response) {
  this.request = request;
  this.response = response;

  this.cookies = this.extractCookies(request);
  this.headers = request.headers;
}

FastBootInfo.prototype.extractCookies = function(request) {
  // If cookie-parser middleware has already parsed the cookies,
  // just use that.
  if (request.cookies) {
    return request.cookies;
  }

  // Otherwise, try to parse the cookies ourselves, if they exist.
  var cookies = request.get('cookie');
  if (cookies) {
    return cookie.parse(cookies);
  }

  // Return an empty object instead of undefined if no cookies are present.
  return {};
};

/*
 * Registers this FastBootInfo instance in the registry of an Ember
 * ApplicationInstance. It is configured to be injected into the FastBoot
 * service, ensuring it is available inside instance initializers.
 */
FastBootInfo.prototype.register = function(instance) {
  instance.register('info:-fastboot', this, { instantiate: false });
  instance.inject('service:fastboot', '_fastbootInfo', 'info:-fastboot');
};

module.exports = FastBootInfo;

Add `request.headers` object to `FastBootInfo`


import React, { Component } from 'react';

class SearchBar extends Component {
  render(){
    return <input onChange={ event => console.log(event.target.value)} />;
  }
}

export default SearchBar;

import React, { Component } from 'react';

class SearchBar extends Component {
  constructor(props) {
    super(props);

    this.state = { term: ''};
  }
  render(){
    return (
      <div>
        <input onChange={ event => this.setState({ term: event.target.value })} />
        Value of the input: {this.state.term}
      </div>
      );
  }
}

export default SearchBar;

Initialize and set state best example


'use babel';

import toggleClassName from '../helper/toggle-class-name';

atom.config.observe('atom-material-ui.tabs.tintedTabBar', (value) => {
    toggleClassName('amu-tinted-tab-bar', value);

    if (!value) {
        atom.config.set('atom-material-ui.treeView.blendTabs', false);
    }
});

atom.config.observe('atom-material-ui.tabs.compactTabs', (value) => {
    toggleClassName('amu-compact-tab-bar', value);
});

atom.config.observe('atom-material-ui.tabs.noTabMinWidth', (value) => {
    toggleClassName('amu-no-tab-min-width', value);
});

'use babel';

import toggleClassName from '../helper/toggle-class-name';

atom.config.observe('atom-material-ui.tabs.tintedTabBar', (value) => {
    toggleClassName('amu-tinted-tab-bar', value);
});

atom.config.observe('atom-material-ui.tabs.compactTabs', (value) => {
    toggleClassName('amu-compact-tab-bar', value);
});

atom.config.observe('atom-material-ui.tabs.noTabMinWidth', (value) => {
    toggleClassName('amu-no-tab-min-width', value);
});

Remove blend tabs and tree-view


import React, { Component, PropTypes } from 'react';
import { connect } from 'stripes-connect';
import PatronForm from './PatronForm';

// One of multiple stripes-connected components in the patrons module
export default class PatronAdd extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired
  };

  // The manifest is provided in components by the module developer and consumed by 'stripes connect'
  static manifest = { 'apis/patrons': { remote: true,
                                        pk: '_id',  // The primary key of records from this end-point
                                                    //  (when it's not the default, "id")
                                        clientGeneratePk: false, // Set if the backend service requires
                                                                 // that it generates unique IDs for records
                                        records: 'patrons' // The name of the property in the JSON response
                                                           // that holds the records
                                      }};

  createPatron(data) {
    this.props.mutator['apis/patrons'].create(data);
    this.context.router.push('/patrons/list');
  }

  cancel(data) {
    this.context.router.push('/patrons/list');
  }

  render() {
      return <PatronForm onSubmit={this.createPatron.bind(this)}
                         cancelForm={this.cancel}
                         action={PatronForm.actionTypes['create']}/>
  }
}

// This function call might be implicit in a future version (invoked by the framework)
export default connect(PatronAdd, 'patrons');

import React, { Component, PropTypes } from 'react';
import { connect } from 'stripes-connect';
import PatronForm from './PatronForm';

// One of multiple stripes-connected components in the patrons module
export default class PatronAdd extends Component {
  static contextTypes = {
    router: PropTypes.object.isRequired
  };

  // The manifest is provided in components by the module developer and consumed by 'stripes connect'
  static manifest = { 'apis/patrons': { remote: true,
                                        pk: '_id',  // The primary key of records from this end-point
                                                    // Set this if not using the default, "id".
                                        clientGeneratePk: false // Set this if the backend service requires
                                                                // that it generates unique IDs for records
                                      }};

  createPatron(data) {
    this.props.mutator['apis/patrons'].create(data);
    this.context.router.push('/patrons/list');
  }

  cancel(data) {
    this.context.router.push('/patrons/list');
  }

  render() {
      return <PatronForm onSubmit={this.createPatron.bind(this)}
                         cancelForm={this.cancel}
                         action={PatronForm.actionTypes['create']}/>
  }
}

// This function call might be implicit in a future version (invoked by the framework)
export default connect(PatronAdd, 'patrons');

Remove obsolete setting. Tweak comments.


/*======================================================================
 *  Exhibit auto-create
 *  Code to automatically create the database, load the data links in
 *  <head>, and then to create an exhibit if there's no ex:ondataload
 *  handler on the body element.
 *
 *  You can avoid running this code by adding the URL parameter
 *  autoCreate=false when you include exhibit-api.js.
 *======================================================================
 */
SimileAjax.jQuery(document).ready(function() {
    var fDone = function() {
        window.exhibit = Exhibit.create();
        window.exhibit.configureFromDOM();
    };

    try {
        var s = Exhibit.getAttribute(document.body, "ondataload");
        if (s != null && typeof s == "string" && s.length > 0) {
            fDone = function() {
                var f = eval(s);
                if (typeof f == "function") {
                    f.call();
                }
            }
        }
    } catch (e) {
        // silent
    }

    var fLoadSubmissions = function() {
        window.database.loadSubmissionLinks(fDone);
    };

    Exhibit.Authentication.authenticate();
    window.database = Exhibit.Database.create();
    window.database.loadDataLinks(fLoadSubmissions);
});

/*======================================================================
 *  Exhibit auto-create
 *  Code to automatically create the database, load the data links in
 *  <head>, and then to create an exhibit if there's no ex:ondataload
 *  handler on the body element.
 *
 *  You can avoid running this code by adding the URL parameter
 *  autoCreate=false when you include exhibit-api.js.
 *======================================================================
 */

Exhibit.autoCreate = function() {
    if (Exhibit.params.autoCreate) {
	var fDone = function() {
            window.exhibit = Exhibit.create();
            window.exhibit.configureFromDOM();
	};

	try {
            var s = Exhibit.getAttribute(document.body, "ondataload");
            if (s != null && typeof s == "string" && s.length > 0) {
		fDone = function() {
                    var f = eval(s);
                    if (typeof f == "function") {
			f.call();
                    }
		}
            }
	} catch (e) {
            // silent
	}

	window.database = Exhibit.Database.create();
	window.database.loadDataLinks(fDone);
    }
}

SimileAjax.jQuery(document).ready(Exhibit.autoCreate);

Use jquery's document.ready instead of our custom asynchronous loader.


import SPELLS from 'common/SPELLS';

export const ABILITIES_AFFECTED_BY_MASTERY = [
  SPELLS.TIGER_PALM.id,
  SPELLS.BLACKOUT_KICK.id,
  SPELLS.FISTS_OF_FURY_CAST.id,
  SPELLS.RISING_SUN_KICK.id,
  SPELLS.CHI_WAVE_TALENT.id,
  SPELLS.FIST_OF_THE_WHITE_TIGER_TALENT.id,
  SPELLS.SPINNING_CRANE_KICK.id,
  SPELLS.FLYING_SERPENT_KICK.id,
  SPELLS.CRACKLING_JADE_LIGHTNING.id,
  SPELLS.WHIRLING_DRAGON_PUNCH_TALENT.id,
  SPELLS.TOUCH_OF_DEATH.id,
  SPELLS.CHI_BURST_TALENT.id,
  SPELLS.RUSHING_JADE_WIND_TALENT_WINDWALKER.id,
];

export const CHI_SPENDERS = [
  SPELLS.BLACKOUT_KICK.id,
  SPELLS.RISING_SUN_KICK.id,
  SPELLS.FISTS_OF_FURY_CAST.id,
  SPELLS.SPINNING_CRANE_KICK.id,
];

export default CHI_SPENDERS;

import SPELLS from 'common/SPELLS';

export const ABILITIES_AFFECTED_BY_MASTERY = [
  SPELLS.TIGER_PALM.id,
  SPELLS.BLACKOUT_KICK.id,
  SPELLS.FISTS_OF_FURY_CAST.id,
  SPELLS.RISING_SUN_KICK.id,
  SPELLS.CHI_WAVE_TALENT.id,
  SPELLS.FIST_OF_THE_WHITE_TIGER_TALENT.id,
  SPELLS.SPINNING_CRANE_KICK.id,
  SPELLS.FLYING_SERPENT_KICK.id,
  SPELLS.CRACKLING_JADE_LIGHTNING.id,
  SPELLS.WHIRLING_DRAGON_PUNCH_TALENT.id,
  SPELLS.TOUCH_OF_DEATH.id,
  SPELLS.CHI_BURST_TALENT.id,
  SPELLS.RUSHING_JADE_WIND_TALENT_WINDWALKER.id,
];

export const CHI_SPENDERS = [
  SPELLS.BLACKOUT_KICK.id,
  SPELLS.RISING_SUN_KICK.id,
  SPELLS.FISTS_OF_FURY_CAST.id,
  SPELLS.SPINNING_CRANE_KICK.id,
  SPELLS.RUSHING_JADE_WIND_TALENT_WINDWALKER.id,
];

export default CHI_SPENDERS;

Add Rushing Jade Wind to CHI_SPENDERS[] constant