// Scans your stylesheet for pseudo classes and adds a class with the same name.
// Thanks to Knyle Style Sheets for the idea.
(function () {

'use strict';

var toArray = function(arr) {
  return Array.prototype.slice.call(arr, 0);
};

var add = function(a, b) { return a + b; };

// Compile regular expression.
var pseudos = ['link', 'visited', 'hover', 'active', 'focus', 'target', 'enabled', 'disabled', 'checked'];
var pseudoRe = new RegExp(":((" + pseudos.join(")|(") + "))", "gi");
var processedPseudoClasses = toArray(document.styleSheets).filter(function(ss) {
  return !(ss.href != null);
}).map(function(ss) {
  return toArray(ss.cssRules).filter(function(rule) {
    // Keep only rules with pseudo classes.
    return rule.selectorText && rule.selectorText.match(pseudoRe);
  }).map(function(rule) {
    // Replace : with . and encoded :
    return rule.cssText.replace(pseudoRe, ".\\3A $1");
  }).reduce(add);
}).reduce(add, '');
if (processedPseudoClasses.length) {
  // Add a new style element with the processed pseudo class styles.
  return $('head').append($('<style />').text(processedPseudoClasses));
}

}());

// Scans your stylesheet for pseudo classes and adds a class with the same name.
// Thanks to Knyle Style Sheets for the idea.
(function () {

'use strict';

var toArray = function(arr) { return Array.prototype.slice.call(arr, 0); };
var add = function(a, b) { return a + b; };

// Compile regular expression.
var pseudos = [ 'link', 'visited', 'hover', 'active', 'focus', 'target',
                'enabled', 'disabled', 'checked' ];
var pseudoRe = new RegExp(":((" + pseudos.join(")|(") + "))", "gi");
var processedPseudoClasses = toArray(document.styleSheets).filter(function(ss) {
  return !(ss.href != null);
}).map(function(ss) {
  return toArray(ss.cssRules).filter(function(rule) {
    // Keep only rules with pseudo classes.
    return rule.selectorText && rule.selectorText.match(pseudoRe);
  }).map(function(rule) {
    // Replace : with . and encoded :
    return rule.cssText.replace(pseudoRe, ".\\3A $1");
  }).reduce(add);
}).reduce(add, '');
if (processedPseudoClasses.length) {
  // Add a new style element with the processed pseudo class styles.
  var styleEl = document.createElement('style');
  styleEl.innerText = processedPseudoClasses;
  return document.querySelectorAll('head')[0].appendChild(styleEl);
}

}());

Remove bonzo and qwery dependencies


describe('Smooth Scroll', function () {

  describe('init', function () {
    it('should include the smoothScroll module', function () {
      expect(!!smoothScroll).toBe(true);
    });
  });

});

describe('Smooth Scroll', function () {

    describe('API', function () {
        it('should export the smoothScroll module', function () {
            expect(smoothScroll).toBeDefined();
        });

        it('should expose public functions', function () {
            expect(smoothScroll.init).toEqual(jasmine.any(Function));
            expect(smoothScroll.destroy).toEqual(jasmine.any(Function));
            expect(smoothScroll.animateScroll).toEqual(jasmine.any(Function));
        });
    });
});

Add simple public API tests


import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
import { OHIF } from 'meteor/ohif:core';

const toolMap = {
    bidirectional: 'targets'
};

OHIF.measurements.toggleLabelButton = options => {
    const removeButtonView = () => {
        if (!options.instance.buttonView) {
            return;
        }

        Blaze.remove(options.instance.buttonView);
        options.instance.buttonView = null;
    };

    if (options.instance.buttonView) {
        removeButtonView();
    }

    const tool = toolMap[options.toolData.toolType];
    const toolCollection = options.measurementApi[tool];
    const measurement = toolCollection.findOne(options.toolData.id);

    const data = {
        measurement,
        tool,
        position: options.position,
        threeColumns: true,
        hideCommon: true,
        toolType: options.toolData.toolType,
        doneCallback(location, description) {
            options.callback(options, location, description);

            toolCollection.update(measurement._id, {
                $set: {
                    location,
                    description
                }
            });

            removeButtonView();
        }
    };
    const view = Blaze.renderWithData(Template.measureFlow, data, options.element);
    options.instance.buttonView = view;
};

import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
import { OHIF } from 'meteor/ohif:core';

const toolMap = {
    bidirectional: 'targets'
};

OHIF.measurements.toggleLabelButton = options => {
    const removeButtonView = () => {
        if (!options.instance.buttonView) {
            return;
        }

        Blaze.remove(options.instance.buttonView);
        options.instance.buttonView = null;
    };

    if (options.instance.buttonView) {
        removeButtonView();
    }

    const tool = toolMap[options.toolData.toolType];
    const toolCollection = options.measurementApi[tool];
    const measurement = toolCollection.findOne(options.toolData._id);

    const data = {
        measurement,
        tool,
        position: options.position,
        threeColumns: true,
        hideCommon: true,
        toolType: options.toolData.toolType,
        doneCallback(location, description) {
            options.callback(options, location, description);

            toolCollection.update(measurement._id, {
                $set: {
                    location,
                    description
                }
            });

            removeButtonView();
        }
    };
    const view = Blaze.renderWithData(Template.measureFlow, data, options.element);
    options.instance.buttonView = view;
};

Fix bug with loading measurement flow


const gulp = require('gulp');
const config = require('config');
const runner = require('punchcard-runner');

const options = runner.config({
  application: {
    library: {
      src: [
        'lib',
        'config',
        'content-types',
        'input-plugins'
      ],
    }
  },
  tasks: {
    nodemon: {
      extension: 'js html yml'
    },
    build: {
      clean: [
        'clean:public',
      ],
      assets: [
        'sass',
        'imagemin',
        'js',
        'punchcard:js',
        'punchcard:images'
      ],
    }
  },
  server: {
    port: config.env.port,
    host: config.env.host
  }
});

runner(gulp, options);

gulp.task('punchcard:js', () => {
  return gulp.src('node_modules/punchcard-cms/src/js/**/*.js')
    .pipe(concat('punchcard.js'))
    .pipe(uglify())
    .pipe(gulp.dest(path.join(options.assets._folders.public, options.assets.js.dest)));
});

gulp.task('punchcard:images', () => {
  return gulp.src('node_modules/punchcard-cms/src/images/**/*')
    .pipe(imagemin(options.tasks.images.build.options))
    .pipe(gulp.dest(path.join(options.assets._folders.public, options.assets.images.dest)));
});

const gulp = require('gulp');
const config = require('config');
const runner = require('punchcard-runner');
const concat = require('gulp-concat');
const uglify = require('gulp-uglify');
const imagemin = require('gulp-imagemin');
const path = require('path');

const options = runner.config({
  application: {
    library: {
      src: [
        'lib',
        'config',
        'content-types',
        'input-plugins'
      ],
    }
  },
  tasks: {
    nodemon: {
      extension: 'js html yml'
    },
    build: {
      clean: [
        'clean:public',
      ],
      assets: [
        'sass',
        'imagemin',
        'js',
        'punchcard:js',
        'punchcard:images'
      ],
    }
  },
  server: {
    port: config.env.port,
    host: config.env.host
  }
});

runner(gulp, options);

gulp.task('punchcard:js', () => {
  return gulp.src('node_modules/punchcard-cms/src/js/**/*.js')
    .pipe(concat('punchcard.js'))
    .pipe(uglify())
    .pipe(gulp.dest(path.join(options.assets._folders.public, options.assets.js.dest)));
});

gulp.task('punchcard:images', () => {
  return gulp.src('node_modules/punchcard-cms/src/images/**/*')
    .pipe(imagemin(options.tasks.images.build.options))
    .pipe(gulp.dest(path.join(options.assets._folders.public, options.assets.images.dest)));
});

Fix Punchcard JS and images compilation


var gulp = require('gulp'),
	less = require('gulp-less'),
	autoprefixer = require('gulp-autoprefixer'),
	minifycss = require('gulp-minify-css'),
	notify = require('gulp-notify'),
	rename = require('gulp-rename');

gulp.task('less', function() {
	return gulp.src('less/caffeine.less')
		.pipe(less())
		.pipe(autoprefixer())
		.pipe(gulp.dest(''))
		.pipe(rename({
			suffix: '.min'
		}))
		.pipe(minifycss())
		.pipe(gulp.dest(''))
		.pipe(notify({
			message: 'Styles task complete'
		}));
});

var gulp = require('gulp'),
	less = require('gulp-less'),
	autoprefixer = require('gulp-autoprefixer'),
	minifycss = require('gulp-minify-css'),
	notify = require('gulp-notify'),
	rename = require('gulp-rename');

gulp.task('less', function() {
	return gulp.src('less/caffeine.less')
		.pipe(less())
		.pipe(autoprefixer({
            cascade: true
        }))
		.pipe(gulp.dest(''))
		.pipe(rename({
			suffix: '.min'
		}))
		.pipe(minifycss())
		.pipe(gulp.dest(''))
		.pipe(notify({
			message: 'Styles task complete'
		}));
});

Set gulp autoprefixer cascade to true


// You still need to register Vuetify itself
// src/plugins/vuetify.js

import Vuetify from 'vuetify/lib'
import PbsLogo from '@/assets/PbsLogo.svg'
import GoogleLogo from '@/assets/GoogleLogo.svg'
import eCampLogo from '@/assets/eCampLogo.svg'
import i18n from '@/plugins/i18n'

class VuetifyLoaderPlugin {
  install (Vue, options) {
    Vue.use(Vuetify)

    const opts = {
      lang: {
        t: (key, ...params) => i18n.t(key, params)
      },
      icons: {
        values: {
          pbs: { component: PbsLogo },
          google: { component: GoogleLogo },
          ecamp: { component: eCampLogo }
        }
      }
    }

    vuetify = new Vuetify(opts)
  }
}

export let vuetify

export default new VuetifyLoaderPlugin()

// You still need to register Vuetify itself
// src/plugins/vuetify.js

import Vuetify from 'vuetify/lib'
import PbsLogo from '@/assets/PbsLogo.svg'
import GoogleLogo from '@/assets/GoogleLogo.svg'
import eCampLogo from '@/assets/eCampLogo.svg'
import i18n from '@/plugins/i18n'
import colors from 'vuetify/lib/util/colors'

class VuetifyLoaderPlugin {
  install (Vue, options) {
    Vue.use(Vuetify)

    const opts = {
      lang: {
        t: (key, ...params) => i18n.t(key, params)
      },
      icons: {
        values: {
          pbs: { component: PbsLogo },
          google: { component: GoogleLogo },
          ecamp: { component: eCampLogo }
        }
      },
      theme: {
        themes: {
          light: {
            error: colors.red.darken2
          }
        }
      }
    }

    vuetify = new Vuetify(opts)
  }
}

export let vuetify

export default new VuetifyLoaderPlugin()

Adjust error color to be darker


import Ember from 'ember';
import DS from 'ember-data';
import ENV from '../config/environment';

function getToken() {
    var token;
    var session = window.localStorage['ember_simple_auth:session'];
    if (session) {
        token = JSON.parse(session)['authenticated'];
        if ('attributes' in token) {
            return token['attributes']['accessToken'];
        }
        return token;
    }
}

export default DS.JSONAPIAdapter.extend({
    session: Ember.inject.service(),
    host: ENV.osfAPIUrl,
    namespace: 'v2',
    ajax(url, method, hash) {
        hash = hash || {};
        hash.crossOrigin = true;
        hash.xhrFields = { withCredentials: false };
        hash.headers = hash.headers || {};
        hash.headers['AUTHORIZATION'] = 'Bearer ' + getToken();
        return this._super(url, method, hash);
    },
    buildURL() {
        var base = this._super(...arguments);
        return `${base}/`;
    }
});

import Ember from 'ember';
import DS from 'ember-data';
import ENV from '../config/environment';

function getToken() {
    var token;
    var session = window.localStorage['ember_simple_auth-session'];
    if (session) {
        token = JSON.parse(session)['authenticated'];
        if ('attributes' in token) {
            return token['attributes']['accessToken'];
        }
        return token;
    }
}

export default DS.JSONAPIAdapter.extend({
    session: Ember.inject.service(),
    host: ENV.osfAPIUrl,
    namespace: 'v2',
    ajax(url, method, hash) {
        hash = hash || {};
        hash.crossOrigin = true;
        hash.xhrFields = { withCredentials: false };
        hash.headers = hash.headers || {};
        hash.headers['AUTHORIZATION'] = 'Bearer ' + getToken();
        return this._super(url, method, hash);
    },
    buildURL() {
        var base = this._super(...arguments);
        return `${base}/`;
    }
});

Fix property name for ember-simple-auth


const checkDate = () => {
  return;
}
module.exports = checkDate;

const checkDate = (dateString) => {
  if (isNaN(Date.parse(dateString))) {
    return false;
  }
  return true;
}
module.exports = checkDate;

Implement checkDate function for date string arguments


$('#dripbot-title').css({
	"display": "inline-block",
	"margin-right": "20px"
});

$('#dripbot').css({
    "text-align": "left"
});

$('#dripbot-toggle.stop').css({
    "background-color": "#e9656d",
    "color": "white",
	"margin-top": "-10px"
});

$('#dripbot ul li p').css({
	"margin-bottom":"5px",
	"margin-right": "40px",
	"display": "inline-block"
});

$('img#dripbot-logo').css({
	"margin-bottom": "10px",
	"margin-right": "5px"
});

$('div#dripbot-update').css({
	"background-color": "#47a447",
	"padding": "10px"
});

$('div#dripbot-update h1').css({
	"font-weight": "800",
});

$('#save-game').css({
	"background-color": "#5cb85c",
	"color": "white",
	"margin-left": "20px"
});

$('div#leaderBoard table tbody tr td.leader-diff').css({
	"color": "#47a447"
});

Remove css to apply each time.


// ==UserScript==
// @name         agar-mass-ejector
// @namespace    http://github.com/dimotsai/
// @version      0.02
// @description  A faster, continuous mass ejector for agar.
// @author       dimotsai
// @license      MIT
// @match        http://agar.io/
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    var $ = window.jQuery;

    $(window).load(function() {
        var onkeydown = window.onkeydown;
        var onkeyup = window.onkeyup;
        var amount = 6;
        var duration = 50; //ms

        var overwriting = function(evt) {
            if (evt.keyCode === 69) { // KEY_E
                for (var i = 0; i < amount; ++i) {
                    setTimeout(function() {
                        onkeydown({keyCode: 87}); // KEY_W
                        onkeyup({keyCode: 87});
                    }, i * duration);
                }
            } else {
                onkeydown(evt);
            }
        };

        if (onkeydown === overwriting) return;

        window.onkeydown = overwriting;
    });
})();

// ==UserScript==
// @name         agar-mass-ejector
// @namespace    http://github.com/dimotsai/
// @version      0.03
// @description  A faster, continuous mass ejector for agar.
// @author       dimotsai
// @license      MIT
// @match        http://agar.io/*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    var amount = 6;
    var duration = 50; //ms

    var overwriting = function(evt) {
        if (evt.keyCode === 69) { // KEY_E
            for (var i = 0; i < amount; ++i) {
                setTimeout(function() {
                    window.onkeydown({keyCode: 87}); // KEY_W
                    window.onkeyup({keyCode: 87});
                }, i * duration);
            }
        }
    };

    window.addEventListener('keydown', overwriting);
})();

Increase compatibility with other plugins


window.onload = initialize;

var DATAFILE = "research.json";
var DONE_READYSTATE = 4;
var DONE_STATUS = 200;
var OFFICIAL_URL = "http://www.ecst.csuchico.edu/~kbuffardi/";
var OFFICIAL_HOST = "www.ecst.csuchico.edu"

var references = {};

function initialize()
{
  validateHost();
  //loadExternalData();
}

function validateHost()
{
  if( window.location.hostname != OFFICIAL_HOST )
  {
    window.location.href = OFFICIAL_URL;
  }
}

function loadExternalData()
{
  var json = new XMLHttpRequest();
  json.overrideMimeType("application/json");
  //event listener: when json file load is "done"
  json.onreadystatechange = function() {
    if (this.readyState == DONE_READYSTATE
        && this.status == DONE_STATUS)
    {
      references=JSON.parse(this.responseText);
      console.log(references);
    }
  }
  json.open("GET", DATAFILE);
  json.send();
}

window.onload = initialize;

var DATAFILE = "research.json";
var DONE_READYSTATE = 4;
var DONE_STATUS = 200;
var OFFICIAL_URL = "https://kbuffardi.github.io/ScholarWebsite/";
var OFFICIAL_HOST = "kbuffardi.github.io"

var references = {};

function initialize()
{
  validateHost();
  //loadExternalData();
}

function validateHost()
{
  if( window.location.hostname != OFFICIAL_HOST )
  {
    window.location.href = OFFICIAL_URL;
  }
}

function loadExternalData()
{
  var json = new XMLHttpRequest();
  json.overrideMimeType("application/json");
  //event listener: when json file load is "done"
  json.onreadystatechange = function() {
    if (this.readyState == DONE_READYSTATE
        && this.status == DONE_STATUS)
    {
      references=JSON.parse(this.responseText);
      console.log(references);
    }
  }
  json.open("GET", DATAFILE);
  json.send();
}

Switch to GitHub Pages as Host


'use strict';

var request = require('request');
var randomstring = require('randomstring');
var db = require('./database');

var handlers = {

    showIntro: function(req, res) {
        res.render('intro');
    },

    createGame: function(req, res) {
        var gameKey = randomstring.generate(5);
        db.getOrCreate(gameKey, function() {
            res.redirect('/p/' + gameKey);
        });
    },

    observeGame: function(req, res) {
        var joinURL = 'http://' + req.headers.host + '/c/' + req.params.game;

        res.render('master', {
            joinURL: joinURL,
            game: req.params.game
        });
    },

    playGame: function(req, res) {
        res.render('client', {game: req.params.game});
    },

    showQR: function(req, res) {
        var joinURL = 'http://' + req.headers.host + '/c/' + req.params.game;
        var url = 'http://api.qrserver.com/v1/create-qr-code/?size=300x300&data=' + joinURL;
        request.get(url).pipe(res);
    },

    bind: function(app) {
        app.get('/', handlers.showIntro);
        app.get('/p/', handlers.createGame);
        app.get('/p/:game', handlers.observeGame);
        app.get('/c/:game', handlers.playGame);
        app.get('/qr/:game', handlers.showQR);
    }
};

module.exports = handlers;

'use strict';

var request = require('request');
var randomstring = require('randomstring');
var db = require('./database');

var handlers = {

    showIntro: function(req, res) {
        res.render('intro');
    },

    createGame: function(req, res) {
        var gameKey = randomstring.generate(5);
        db.getOrCreate(gameKey, function() {
            res.redirect('/p/' + gameKey);
        });
    },

    observeGame: function(req, res) {
        var joinURL = req.protocol + '://' + req.headers.host + '/c/' + req.params.game;

        res.render('master', {
            joinURL: joinURL,
            game: req.params.game
        });
    },

    playGame: function(req, res) {
        res.render('client', {game: req.params.game});
    },

    showQR: function(req, res) {
        var joinURL = req.protocol + '://' + req.headers.host + '/c/' + req.params.game;
        var url = 'http://api.qrserver.com/v1/create-qr-code/?size=300x300&data=' + joinURL;
        request.get(url).pipe(res);
    },

    bind: function(app) {
        app.get('/', handlers.showIntro);
        app.get('/p/', handlers.createGame);
        app.get('/p/:game', handlers.observeGame);
        app.get('/c/:game', handlers.playGame);
        app.get('/qr/:game', handlers.showQR);
    }
};

module.exports = handlers;

Determine protocol when generating game links


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Demo login UI.
 */

/**
 * Handles a user clicking anywhere on the screen. This will log the demo user
 * in. Yes, this actually _is the intention.
 */
onClick = function() {
  chrome.send('launchDemoUser');
};

/**
 * Initializes the click handler.
 */
initialize = function() {
  document.addEventListener('click', onClick);
};

disableTextSelectAndDrag();
document.addEventListener('DOMContentLoaded', initialize);

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Demo login UI.
 */

/**
 * Handles a user clicking anywhere on the screen. This will log the demo user
 * in. Yes, this actually _is the intention.
 */
onClick = function(e) {
  document.removeEventListener('click', onClick);
  e.stopPropagation();
  chrome.send('launchDemoUser');
};

/**
 * Initializes the click handler.
 */
initialize = function() {
  document.addEventListener('click', onClick);
};

disableTextSelectAndDrag();
document.addEventListener('DOMContentLoaded', initialize);

Fix possible issue with multiple clicks on demo login screen. Though this doesn't currently repro, there is a possibility that if the demo login flow takes too long, a user clicking really fast on the login screen may see unexpected behavior due to multiple login attempts being kicked off. This CL will ensure that that doesn't happen.


Template.registerWizard.helpers({
  'steps': function () {
    return [
      {
        id: 'registrant',
        title: 'Registrant',
        schema: WizardSchemas.registrant
      },
      {
        id: 'contact',
        title: 'Contact',
        schema: WizardSchemas.contact
      }
    ]
  }
});

Template.registerWizard.helpers({
  'steps': function () {
    return [
      {
        id: 'registrant',
        title: 'Registrant',
        schema: WizardSchemas.registrant,
        template: "wizardRegistrant",
        formId: "wizard-registrant"
      },
      {
        id: 'contact',
        title: 'Contact',
        schema: WizardSchemas.contact
      }
    ]
  }
});

Use custom template for registrant step


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

module.exports = {
  entry: [path.resolve(__dirname, '../client/index.js')],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }, {
        test: /\.css/,
        loader: ExtractTextPlugin.extract('css')
      }
    ],
    preLoaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'eslint-loader'
    }]
  },
  output: {
    path: path.resolve(__dirname, '../public'),
    filename: 'client.js'
  },
  plugins: [
    new ExtractTextPlugin('style.css', {
      allChunks: true
    }),
    new webpack.ProvidePlugin({
      fetch: 'imports?this=>global!exports?global.fetch!whatwg-fetch'
    })
  ],
  resolve: {
    root: path.resolve(__dirname, '../client'),
    extensions: ['', '.js']
  }
}

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

module.exports = {
  entry: [path.resolve(__dirname, '../client/index.js')],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }, {
        test: /\.css/,
        loader: ExtractTextPlugin.extract('css')
      }, {
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
        loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]'
      }
    ],
    preLoaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'eslint-loader'
    }]
  },
  output: {
    path: path.resolve(__dirname, '../public'),
    filename: 'client.js'
  },
  plugins: [
    new ExtractTextPlugin('style.css', {
      allChunks: true
    }),
    new webpack.ProvidePlugin({
      fetch: 'imports?this=>global!exports?global.fetch!whatwg-fetch'
    })
  ],
  resolve: {
    root: path.resolve(__dirname, '../client'),
    extensions: ['', '.js']
  }
}

Configure bundling for images and fonts


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

require('./lib/polyfill');
module.exports = require('../dist/bin/cli/harmonic');

Fix bin entry point for Unix-based OS's


myApp.controller('InventoryController', function($scope, $window, $location, $routeParams, inventoryService) {
    inventoryService.loadInventories()
        .then(function(inventories) {
            console.log("Loaded stored inventories: ", inventories);
            $scope.inventories = inventories;
        });
    $scope.inventory = inventoryService.getInventory($routeParams.id);

    $scope.goBack = function() {
        $window.history.go(-1);
    };

    $scope.newInventory = function() {
        var inventory = inventoryService.newInventory();
        $location.path(`/new/${inventory.id}`);
    };

    $scope.viewInventory = function(inv) {
        // TODO: remove old setCurrentInventory method
        // inventoryService.setCurrentInventory(inv);
        $location.path('/view');
    };

    $scope.addInventory = function() {
        $scope.inventories.push($scope.inventory);
        inventoryService.putInventories($scope.inventories);
    };

    $scope.editInventory = function(inv) {
        // TODO: remove old setCurrentInventory method
        // inventoryService.setCurrentInventory(inv);
        $location.path('/edit');
    };

    $scope.newItem = function() {
        $location.path('/item/new');
    };

    $scope.addItem = function() {
        $scope.inventory.items.push(item);
        inventoryService.putInventories($scope.inventories);
    };
});

myApp.controller('InventoryController', function($scope, $window, $location, $routeParams, inventoryService) {
    inventoryService.loadInventories()
        .then(function(inventories) {
            console.log("Loaded stored inventories: ", inventories);
            $scope.inventories = inventories;
            $scope.apply();
        });
    $scope.inventory = inventoryService.getInventory($routeParams.id);

    $scope.goBack = function() {
        $window.history.go(-1);
    };

    $scope.newInventory = function() {
        var inventory = inventoryService.newInventory();
        $location.path(`/new/${inventory.id}`);
    };

    $scope.viewInventory = function(inv) {
        // TODO: remove old setCurrentInventory method
        // inventoryService.setCurrentInventory(inv);
        $location.path('/view');
    };

    $scope.addInventory = function() {
        $scope.inventories.push($scope.inventory);
        inventoryService.putInventories($scope.inventories);
    };

    $scope.editInventory = function(inv) {
        // TODO: remove old setCurrentInventory method
        // inventoryService.setCurrentInventory(inv);
        $location.path('/edit');
    };

    $scope.newItem = function() {
        $location.path('/item/new');
    };

    $scope.addItem = function() {
        $scope.inventory.items.push(item);
        inventoryService.putInventories($scope.inventories);
    };
});

Add .apply() to inventory loading to refresh ng-repeat


define(['backbone.marionette', 'app', 'hbs!../templates/exam'],
  function (Marionette, App, template) {
    'use strict';

    return Marionette.ItemView.extend({
      tagName: 'tr',
      template: template,

      events: {
        'click .remove': function () {
          App.execute('removeModule', this.model.id);
        }
      },

      modelEvents: {
        change: 'render'
      },

      onRender: function () {
        this.$el.addClass('color' + this.model.get('color'))
          .toggleClass('clash', this.model.get('clash'));
      }
    });
  });

define(['backbone.marionette', 'app', 'hbs!../templates/exam'],
  function (Marionette, App, template) {
    'use strict';

    return Marionette.ItemView.extend({
      tagName: 'tr',
      template: template,

      events: {
        'click .remove': function () {
          App.request('removeModule', this.model.id);
        }
      },

      modelEvents: {
        change: 'render'
      },

      onRender: function () {
        this.$el.addClass('color' + this.model.get('color'))
          .toggleClass('clash', this.model.get('clash'));
      }
    });
  });

Fix removing module from exam timetable


var express = require('express');
var router = express.Router();
var usersController = require('../controllers/users');

/**
 * Get all
 */
router.get('/', usersController.all);

/**
 * Get by id
 */
router.get('/:userId', usersController.user);

/**
 * Create
 */
router.post('/', usersController.create);

/**
 * Update
 */
router.put('/', usersController.update);

/**
 * Delete
 */
router.delete('/:userId', usersController.destroy);

module.exports = router;

var express = require('express');
var router = express.Router();
var usersController = require('../controllers/users');

/**
 * Get all
 */
router.get('/', usersController.all);

/**
 * Get by id
 */
router.get('/:userId', usersController.user);

/**
 * Create
 */
router.post('/', usersController.create);

/**
 * Update
 */
router.put('/', usersController.update);

/**
 * Delete
 */
router.delete('/:userId', usersController.destroy);

/**
 * Login
 */
router.post('/login', usersController.login);

/**
 * Logout
 */
router.get('/logout', usersController.logout);

module.exports = router;

Add login and logout route


#!/usr/bin/env node

// Requires
var _ = require('underscore');

var fs = require('fs');

// Comannder
var prog = require('commander');

// etcd-dump's package.json file
var pkg = require('../package.json');

// Dumper class
var dumper = require('../')();

// General options
prog
.version(pkg.version)
.option('-f, --file [json_file]', 'Path to JSON dump file for dumping/storing', './etcd_dump.json');

// Dump command
prog
.command('dump')
.action(function() {
    return dumper.dump()
    .then(function(data) {
        // Write file to disk
        fs.writeFileSync(prog.file, JSON.stringify(data));
    })
    .done();
});

prog
.command('restore')
.action(function() {
    var entries = JSON.parse(fs.readFileSync(prog.file));

    return dump.restore(entries)
    .then(function() {
        console.log('Restore succeeded');
    })
    .done();
});

// Parse and fallback to help if no args
if(_.isEmpty(prog.parse(process.argv).args)) prog.help();

#!/usr/bin/env node

// Requires
var _ = require('underscore');

var fs = require('fs');

// Comannder
var prog = require('commander');

// etcd-dump's package.json file
var pkg = require('../package.json');

// Dumper class
var dumper = require('../')();

// General options
prog
.version(pkg.version)
.option('-f, --file [json_file]', 'Path to JSON dump file for dumping/storing', './etcd_dump.json');

// Dump command
prog
.command('dump')
.action(function() {
    return dumper.dump()
    .then(function(data) {
        // Write file to disk
        fs.writeFileSync(prog.file, JSON.stringify(data));
    })
    .done();
});

prog
.command('restore')
.action(function() {
    var entries = JSON.parse(fs.readFileSync(prog.file));

    return dumper.restore(entries)
    .then(function() {
        console.log('Restore succeeded');
    })
    .done();
});

// Parse and fallback to help if no args
if(_.isEmpty(prog.parse(process.argv).args)) prog.help();

Fix typo "dump" => "dumper"


import Ember from "ember";
import translations from "croodle/lang/translations";
/* global Croodle */

export default Ember.View.extend({
  templateName: 'language-switch',

  languages: function() {
    var languages = [];
    for(var lang in translations) {
      languages.push(lang);
    }
    return languages;
  }.property(),

  languageChanged: function() {
    // change language
    var language = this.get('controller.language.selected');

    // save language in cookie
    document.cookie="language=" + language + ";" +
            // give it an lifetime of one year
            "max-age=" + 60*60*24*356 + ";";

    // rerender page
    Croodle.reset();
  }.observes('controller.language.selected')
});

import Ember from "ember";
import translations from "croodle/lang/translations";
/* global Croodle */

export default Ember.View.extend({
  templateName: 'language-switch',

  languages: function() {
    var languages = [];
    for(var lang in translations) {
      languages.push(lang);
    }
    return languages;
  }.property(),

  languageChanged: function() {
    // change language
    var language = this.get('controller.language.selected');

    // save language in cookie
    document.cookie="language=" + language + ";" +
            // give it an lifetime of one year
            "max-age=" + 60*60*24*356 + ";";

    // rerender page
    window.location.reload();
  }.observes('controller.language.selected')
});

Fix not working language switch in production environment


export class AdjacencyList {
    constructor(graph) {
        this.a = constructAdjacencyList(graph);
    }
    depthFirstSearch(start, earlyCallback) {
        depthFirstSearch(this.a, start, earlyCallback);
    }
}

function constructAdjacencyList(graph) {
    // new Array(vertexCount).fill([]) does not work because it reuses the same array instance for
    // every element.
    let a = Array.from(new Array(graph.vertexCount), () => []);

    for (let [x, y] of graph.edges) {
        insertEdge(a, x, y, graph.directed);
    }

    return a;
}

function insertEdge(a, x, y, directed) {
    a[x].push(y);
    if (!directed) {
        insertEdge(a, y, x, true);
    }
}

function depthFirstSearch(a, start, earlyCallback) {
    let processed = new Array(a.length);

    let dfs = x => {
        if (processed[x]) {
            return;
        }
        processed[x] = true;
        earlyCallback(x);
        a[x].forEach(dfs);
    };

    dfs(start);
}

export class AdjacencyList {
    constructor(graph) {
        this.a = constructAdjacencyList(graph);
    }
    depthFirstSearch(start, earlyCallback) {
        depthFirstSearch(this.a, start, earlyCallback);
    }
}

function constructAdjacencyList(graph) {
    // new Array(vertexCount).fill([]) does not work because it reuses the same array instance for
    // every element.
    let a = Array.from(new Array(graph.vertexCount), () => []);

    for (let [x, y] of graph.edges) {
        insertEdge(a, x, y, graph.directed);
    }

    return a;
}

function insertEdge(a, x, y, directed) {
    a[x].push(y);
    if (!directed) {
        insertEdge(a, y, x, true);
    }
}

function depthFirstSearch(a, start, earlyCallback) {
    let processed = new Array(a.length);

    function dfs(x) {
        if (processed[x]) {
            return;
        }
        processed[x] = true;
        earlyCallback(x);
        a[x].forEach(dfs);
    }

    dfs(start);
}

Replace fat arrow by traditional function for clarity


import cx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import MediaLoadingIndicator from './MediaLoadingIndicator';

const LoadingRow = ({
  className,
  selected = false,
  ...attrs
}) => (

    <MediaLoadingIndicator className="MediaListRow-loader" />

      {' … '}

      {' … '}

      {' … '}

);

LoadingRow.propTypes = {
  className: PropTypes.string,
  selected: PropTypes.bool,
};

export default LoadingRow;

Fix loading media list row layout


'use strict'

const sitemap = require('./../index')
const express = require('express')

const app = express()
const core = new express.Router()
const other = new express.Router()
app.use('/core', core)
app.use(other)

// express routing
core.get('/', function(req, res) {
    res.send('hello /')
}).get('/admin', function(req, res) {
    res.send('hello /admin')
}).post('/admin', function(req, res) {
    res.send('hello /admin')
}).get('/duplicate', function(req, res) {
    res.send('hello /duplicate')
}).get('/duplicate/:id', function(req, res) {
    res.send('hello /duplicate')
})
other.post('/foo', function(req, res) {
    res.send('hello /foo')
}).put('/nooo', function(req, res) {
    res.send('hello /nooo')
}).get('/zas', function(req, res) {
    res.end('hello /zas')
})

/*
 * sitemap
 */
app.get('/sitemap', sitemap(app))
/**
 * Auto generated Swagger UI
 */
sitemap.swagger('Demo', app)

// server starting
app.listen(3000)
console.log('starting "sitemap example" on port 3000')

'use strict'

const sitemap = require('./../index')
const express = require('express')

const app = express()
const core = new express.Router()
const other = new express.Router()
app.use(express.urlencoded({extended: false}))
app.use(express.json())
app.use('/core', core)
app.use(other)

// express routing
core.get('/', function(req, res) {
    res.send('hello /')
}).get('/admin', function(req, res) {
    res.send('hello /admin')
}).post('/admin', function(req, res) {
    res.send('hello /admin')
}).get('/duplicate', function(req, res) {
    const master = req.query.master
    res.send(`hello /duplicate with:
        master = ${master} and  ${req.query.boss}`)
}).get('/duplicate/:id', function(req, res) {
    res.send(`hello /duplicate with id = ${req.params.id}`)
})
other.post('/foo', function(req, res) {
    res.send(`hello /foo with:
        master = ${req.body.master} and  ${req.body.boss}`)
}).put('/nooo', function(req, res) {
    res.send('hello /nooo')
}).get('/zas', function(req, res) {
    res.end('hello /zas')
})

/*
 * sitemap
 */
app.get('/sitemap', sitemap(app))
/**
 * Auto generated Swagger UI
 */
sitemap.swagger('Demo', app)

// server starting
app.listen(3000)
console.log('starting "sitemap example" on port 3000')

Update example to check for query and body parameters.


var request = require('request');

var {processAddress, prefetchAddress} = require('./utils');

const GEOCODE_BASE_URL = 'http://open.mapquestapi.com/geocoding/v1/address';

function MapQuest(apiKey) {
  this.key = apiKey;
  return this;
}

MapQuest.prototype.geocode = function (address, location) {
  return new Promise((resolve, reject) => {
    let prefetched = prefetchAddress(address, location);
    if (prefetched) {
      resolve(prefetched);
    }

    address = processAddress(address);
    let uri = `${GEOCODE_BASE_URL}?key=${this.key}&street=${address}&county=Oahu&state=HI`;

    request({uri, json: true}, (err, _, response) => {
      // There should be a location at the county level.
      if (response.results[0].locations.length > 0) {
        let location = response.results[0].locations[0];
        (location.geocodeQuality === 'STREET') ? resolve(location) : resolve(null);
      }
      else {
        // Let's just resolve this for now. Not really an error yet.
        resolve(null);
      }
    });
  });
}

module.exports = MapQuest;

var request = require('request');

var {processAddress, prefetchAddress} = require('./utils');

const GEOCODE_BASE_URL = 'http://open.mapquestapi.com/geocoding/v1/address';

function MapQuest(apiKey) {
  this.key = apiKey;
  return this;
}

MapQuest.prototype.geocode = function (address, location) {
  return new Promise((resolve, reject) => {
    let prefetched = prefetchAddress(address, location);
    if (prefetched) {
      resolve(prefetched);
    }

    address = processAddress(address);
    let uri = `${GEOCODE_BASE_URL}?key=${this.key}&street=${address}&county=Oahu&state=HI`;

    request({uri, json: true}, (err, _, response) => {
      // There should be a location at the county level.
      if (response.results && response.results[0].locations.length > 0) {
        let location = response.results[0].locations[0];
        (location.geocodeQuality === 'STREET') ? resolve(location) : resolve(null);
      }
      else {
        // Let's just resolve this for now. Not really an error yet.
        resolve(null);
      }
    });
  });
}

module.exports = MapQuest;

Fix bug that was crashing worker.


import React from 'react'
import AceEditor from 'react-ace'
import 'brace/mode/yaml'
import 'brace/theme/github'

import './ConfigEditor.scss'

export default function ConfigEditor(props) {
  return (
    <AceEditor mode="yaml" theme="github" name="config-editor" {...props} />
  )
}

import React from 'react'
import AceEditor from 'react-ace'
import 'brace/mode/yaml'
import 'brace/theme/dawn'

import './ConfigEditor.scss'

export default function ConfigEditor(props) {
  return <AceEditor mode="yaml" theme="dawn" name="config-editor" {...props} />
}

Change config editor theme to dawn


import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize(serialized) {
    const date = moment(serialized).format('DD MMMM YYYY');

    return date;
  },

  serialize(deserialized) {
    const date = moment(deserialized).format('YYYY/MM/DD');

    return date;
  }
});

import DS from 'ember-data';

export default DS.Transform.extend({
  deserialize(serialized) {
    const date = moment(serialized).format('DD MMMM');

    return date;
  },

  serialize(deserialized) {
    const date = moment(deserialized).format('YYYY/MM/DD');

    return date;
  }
});

Hide year of birth in notification component


'use strict';

var events = [];
var requestInterval = 5000;

window.addEventListener('click', function(e) {
    e = event || window.event;

    events.push(processEvent(e));
});

var processEvent = function(e) {

  // Event attributes
  var eventProps = ['type', 'timeStamp'];

  // Event target attributes
  var targetProps = ['nodeName', 'innerHTML'];

  // Trimmed event
  var result = {};

  eventProps.forEach(function(prop) {
    if (e[prop]) { result[prop] = e[prop]; }
  });

  if(e.target) {
    targetProps.forEach(function(prop) {
      if(e.target[prop]) { result[prop] = e.target[prop]; }
    });
  }

  console.log('event result: ' + JSON.stringify(result));
  return result;
};

var PostRequest = function() {
  var xhr;

  try {
    xhr = new XMLHttpRequest();
  } catch(e) {
    throw new Error('No XHR object');
  }

  var url = 'http://sextant-ng-b.herokuapp.com/api/0_0_1/data';

  xhr.open('POST', url, true);
  xhr.setRequestHeader('Content-Type', 'application/json');

  return xhr;
};

var sendEvents = setInterval(function() {
  if (!events.length) return;

  var request = new PostRequest();
  request.send(JSON.stringify(events));

  events = [];
}, requestInterval);

'use strict';

var events = [];
var requestInterval = 5000;

window.addEventListener('click', function(e) {
    e = event || window.event;

    events.push(processEvent(e));
});

var processEvent = function(e) {

  // Event attributes
  var eventProps = ['type', 'timeStamp'];

  // Event target attributes
  var targetProps = ['nodeName', 'innerHTML'];

  // Trimmed event
  var result = {};

  eventProps.forEach(function(prop) {
    if (e[prop]) { result[prop] = e[prop]; }
  });

  if(e.target) {
    targetProps.forEach(function(prop) {
      if(e.target[prop]) { result[prop] = e.target[prop]; }
    });
  }

  console.log('event result: ' + JSON.stringify(result));
  return result;
};

var ajax = {};

ajax.postUrl ='http://sextant-ng-b.herokuapp.com/api/0_0_1/data';

ajax.createXHR = function() {
  try {
    return new XMLHttpRequest();
  } catch(e) {
    throw new Error('No XHR object.');
  }

};

ajax.post = function(data) {
  var xhr = this.createXHR();

  xhr.open('POST', this.postUrl, true);
  xhr.setRequestHeader('Content-Type', 'application/json');
  xhr.send(data);
};

var sendEvents = setInterval(function() {
  if (!events.length) return;

  ajax.post(JSON.stringify(events));

  events = [];
}, requestInterval);

Refactor xhr functionality into ajax object


import Ember from 'ember';

/* global moment */
export default Ember.Route.extend({
  model: function() {
    return this.store.filter('raid', { 'current': true }, function(raid) {
      return moment(raid.get('date')).subtract(6, 'hours').isAfter();
    });
  },

  setupController: function (controller, model) {
    controller.set('model', model);
    controller.set('roles', this.store.all('role'));
  }
});

import Ember from 'ember';

/* global moment */
export default Ember.Route.extend({
  model: function() {
    return this.store.filter('raid', {}, function(raid) {
      return moment(raid.get('date')).subtract(6, 'hours').isAfter();
    });
  },

  setupController: function (controller, model) {
    controller.set('model', model);
    controller.set('roles', this.store.all('role'));
  }
});

Use an empty query when grabbing filtered raids


import { DefaultDOMElement } from 'substance'

const EMPTY_JATS = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving DTD v1.0 20120330//EN" "JATS-journalarchiving.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ali="http://www.niso.org/schemas/ali/1.0">
  <front>
    <article-meta>
      <title-group>
        <article-title></article-title>
      </title-group>
      <abstract>
      </abstract>
    </article-meta>
  </front>
  <body>
  </body>
  <back>
  </back>
</article>`

export default function createEmptyJATS () {
  return DefaultDOMElement.parseXML(EMPTY_JATS)
}

import { DefaultDOMElement } from 'substance'
import { DEFAULT_JATS_SCHEMA_ID, DEFAULT_JATS_DTD } from '../../ArticleConstants'

// TODO: we need a way to specify which namespaces should be declared

const EMPTY_JATS = `<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "${DEFAULT_JATS_SCHEMA_ID}" "${DEFAULT_JATS_DTD}">
<article xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ali="http://www.niso.org/schemas/ali/1.0">
  <front>
    <article-meta>
      <title-group>
        <article-title></article-title>
      </title-group>
      <abstract>
      </abstract>
    </article-meta>
  </front>
  <body>
  </body>
  <back>
  </back>
</article>`

export default function createEmptyJATS () {
  return DefaultDOMElement.parseXML(EMPTY_JATS)
}

Use default schema id for empty articles.


/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

describe('Bridge', function() {
    if (cordova.platformId == 'android') {
        it("bridge.spec.1 should reject bridge from iframe with data: URL", function() {
            var ifr = document.createElement('iframe');
            var done = false;
            ifr.src = 'data:text/html,';
            ifr.onload = function() {
                var stolenSecret = ifr.contentWindow.prompt('', 'gap_init:');
                done = true;
                expect(stolenSecret).toBe(null);
            };
            document.body.appendChild(ifr);
            waitsFor(function() { return done; });
        });
    }
});

/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

describe('Bridge', function() {
    if (cordova.platformId == 'android') {
        it("bridge.spec.1 should reject bridge from iframe with data: URL", function() {
            var ifr = document.createElement('iframe');
            var done = false;
            ifr.src = 'data:text/html,';
            ifr.onload = function() {
                var stolenSecret = ifr.contentWindow.prompt('', 'gap_init:');
                done = true;
                expect(!!stolenSecret).toBe(false);
            };
            document.body.appendChild(ifr);
            waitsFor(function() { return done; });
        });
    }
});

Fix bridge test failure due to "" vs null


var chai = require('chai');
chai.should();
// var expect = chai.expect;
// var should = chai.should();

var jetconfig = require('../index.js');

describe('#get()', function (){
    it("should return a default value", function () {
        jetconfig.get('foo', true).should.equal(true);

    });
});

var chai = require('chai');
chai.should();
// var expect = chai.expect;
// var should = chai.should();

var jetconfig = require('../index.js');

before(function (done) {
    console.dir(process.env);
    done(new Error("Does this work?"));
});

describe('#get()', function (){
    it("should return a default value", function () {
        jetconfig.get('foo', true).should.equal(true);

    });
});

Create a failing before-all hook.


import test from 'ava';
import { search, searchContinuously } from '..';

test('it makes a request', t =>
  search()
    .then(items => {
      t.true(Array.isArray(items));
    })
);

test('it subscribes to a stream', t =>
  searchContinuously()
    .take(1)
    .toPromise()
    .then(items => {
      t.true(Array.isArray(items));
    })
);

import test from 'ava';
import { search, searchContinuously } from '..';

test('it makes a request', t =>
  search()
    .then(items => {
      t.true(Array.isArray(items));
    }),
);

test('it subscribes to a stream', t =>
  searchContinuously()
    .take(1)
    .toPromise()
    .then(items => {
      t.true(Array.isArray(items));
    }),
);

Add trailing commas where appropriate


import React, { Component } from 'react';
import ReactDOM from 'react-dom';

import { Board } from './containers';
import './styles/app.scss';

class App extends Component {
  render() {
    return <Board />;
  }
}

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

import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import ReactDOM from 'react-dom';

import { Board } from './containers';
import './styles/app.scss';

const store = createStore(() => { return {}; });

class App extends Component {
  render() {
    return <Board />;
  }
}

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('app')
);

Add basic Redux Provider with store


// Copyright (c) Rotorz Limited. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root.

import given from "mocha-testdata";
import should from "should";

import webreed from "../src";

describe("#setup(options)", function () {

  it("is a function", function () {
    webreed
      .should.be.a.Function();
  })

  it("is named 'setup'", function () {
    webreed.name
      .should.be.eql("setup");
  })

})

// Copyright (c) Rotorz Limited. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root.

// Packages
import given from "mocha-testdata";
import should from "should";

// Project
import webreed from "../src";

describe("#setup(options)", function () {

  it("is a function", function () {
    webreed
      .should.be.a.Function();
  })

  it("is named 'setup'", function () {
    webreed.name
      .should.be.eql("setup");
  })

})

Add header comments to keep system, package and project imports separate.


import {dest} from 'vinyl-fs';
import drFrankenstyle from './dr-frankenstyle';

const argv = require('yargs')
  .usage('Usage: dr-frankenstyle <output-dir>')
  .example('dr-frankenstyle my_assets_dir')
  .demand(1, 'Please provide an output directory')
  .boolean('rails')
  .argv;

const output = argv._[0];

let stream = drFrankenstyle();

if (argv.rails) {
  stream = stream.pipe(drFrankenstyle.railsUrls());
}

stream
  .pipe(dest(output));

import {dest} from 'vinyl-fs';
import drFrankenstyle from './dr-frankenstyle';

const argv = require('yargs')
  .usage('Usage: dr-frankenstyle [options] <output-dir>')
  .example('dr-frankenstyle my_assets_dir')
  .demand(1, 'Please provide an output directory')
  .boolean('rails')
  .describe('rails', "Use Rails' asset-url helper instead of url in CSS")
  .argv;

const output = argv._[0];

let stream = drFrankenstyle();

if (argv.rails) {
  stream = stream.pipe(drFrankenstyle.railsUrls());
}

stream
  .pipe(dest(output));

Document rails option in CLI tool


// Tentative schema for the overall app store:
//
//
//   interface Media {
//       id: string;
//       kind: 'audio' | 'video';
//       owner: string;
//       stream: Object;
//       audioState: 'active' | 'muted' | 'not-available' | 'error';
//       videoState: 'active' | 'muted' | 'not-available' | 'error';
//       videoType: 'camera' | 'screen' | '';
//   }
//
//   interface Participant {
//       id: string;
//       name: string;
//       gravatar: string;
//       moderator: boolean;
//       speaking: boolean;
//   }
//
//   interface Statistics {
//       participant: string;
//       bitrateUp: number;
//       bitrateDown: number;
//       packetLossUp: number;
//       packetLossDown: number;
//       // ...etc
//   }
//
//   interface Room {
//       id: string;
//       joined: boolean;
//       locked: boolean;
//       sharedVideo: string;
//       streamingState: 'starting' | 'streaming' | 'error' | '';
//       mediaConnectionState: 'connecting' | 'connected' | 'interrupted' | 'disconnected';
//   }
//
//   interface AppState {
//       room: Room;
//       user: Participant;
//       participants: Map<string, Participant>;
//       statistics: Map<string, Statistics>;
//       localMedia: Media;
//       remoteMedia: Map<string, Media>;
//       selectedMedia: string;
//       sharingScreen: boolean;
//       modalID: string;
//       fullScreen: boolean;
//       connectionState: 'connected' | 'disconnected' | 'connecting';
//   }

export function stub(state = {}, action) {
    return state;
}

Add the tentative schema for the redux store


import url      from "url";
import mixin    from "merge-descriptors";
import wildcard from "wildcard-named";

export default {
    callbacks : {},

    when( uri ) {
        return new Promise( resolve => {
            this.callbacks[ url.resolve( this.base, uri ) ] = resolve;
        } );
    },

    check( uri, req, res ) {
        for ( const index in this.callbacks ) {
            const requested = wildcard( uri, index );
            const callback  = this.callbacks[ index ];

            if ( uri === index || requested ) {
                mixin( req.params, requested || {} );

                callback( { req, res, uri } );
            }
        }
    }
};

import url      from "url";
import request  from "retry-request";
import mixin    from "merge-descriptors";
import wildcard from "wildcard-named";

export default {
    callbacks : {},

    when( uri ) {
        return new Promise( resolve => {
            this.callbacks[ url.resolve( this.base, uri ) ] = resolve;
        } );
    },

    get( uri ) {
        if ( !uri.startsWith( this.base ) ) {
            uri = url.resolve( this.base, uri );
        }

        return new Promise( ( resolve, reject ) => {
            request( uri, ( error, response ) => {
                if ( error || response.statusCode != 200 ) {
                    reject( error || uri );
                }

                const req = {};
                const res = response;

                // Set circular references:
                res.req = req;
                req.res = res;

                // Alter the prototypes:
                req.__proto__ = this.req;
                res.__proto__ = this.res;

                resolve( { req, res, uri } );
            } );
        } );
    },
    check( uri, req, res ) {
        for ( const index in this.callbacks ) {
            const requested = wildcard( uri, index );
            const callback  = this.callbacks[ index ];

            if ( uri === index || requested ) {
                mixin( req.params, requested || {} );

                callback( { req, res, uri } );
            }
        }
    }
};

Add get method to request a single resource


/**
 * autocompleteme.js
 * Chrome extension to remove autocomplete=off attributes from all elements on the page.
 *
 * https://github.com/martone/autocompleteme
 * Andy Martone (amartone@gmail.com)
 */
(function() {
  var elements = document.querySelectorAll('input[autocomplete=off]');
  if (elements.length) {
    console.groupCollapsed(
        'Removing autocomplete=off from the following %d element(s):',
        elements.length);
    Array.prototype.forEach.call(elements, function(e) {
      console.log(e);
      e.removeAttribute('autocomplete');
    });
    console.groupEnd();
  }
})();

/**
 * autocompleteme.js
 * Chrome extension to remove autocomplete=off attributes from all elements on the page.
 *
 * https://github.com/martone/autocompleteme
 * Andy Martone (amartone@gmail.com)
 */
(function() {
  var elements = document.querySelectorAll('[autocomplete=off]');
  if (elements.length) {
    console.groupCollapsed(
        'Removing autocomplete=off from the following %d element(s):',
        elements.length);
    Array.prototype.forEach.call(elements, function(e) {
      console.log(e);
      e.removeAttribute('autocomplete');
    });
    console.groupEnd();
  }
})();

Apply to all elements, not just input.


import Dependency from './Dependency'

export default class Composer extends Dependency {

    default()
    {
        this.dependencyName = 'PHP Composer'
        this.required = true
    }

    mac() {
        this.dependencyLink = 'https://github.com/laravel/valet'
        this.dependencyDocumentation = 'https://laravel.com/docs/5.4/valet'
        this.dependencyDescription = 'Composer is the defacto package manager for PHP.'

        this.command = 'composer -V'
        this.expectedOutput = /Composer version/i

        this.installCommand = 'brew install composer'
        this.installRequiresSudo = false

        this.uninstallCommand = 'brew uninstall composer'
        this.uninstallRequiresSudo = false
    }

    windows() {

    }

    linux() {

    }

}

import Dependency from './Dependency'

export default class Composer extends Dependency {

    default()
    {
        this.dependencyName = 'PHP Composer'
        this.required = true
    }

    mac() {
        this.dependencyLink = 'https://getcomposer.org/'
        this.dependencyDocumentation = 'https://getcomposer.org/doc/'
        this.dependencyDescription = 'Composer is the defacto package manager for PHP.'

        this.command = 'composer -V'
        this.expectedOutput = /Composer version/i

        this.installCommand = 'brew install composer'
        this.installRequiresSudo = false

        this.uninstallCommand = 'brew uninstall composer'
        this.uninstallRequiresSudo = false
    }

    windows() {

    }

    linux() {

    }

}

Add proper composer link and docs


'use strict';

/* jasmine specs for controllers go here */

describe('RootCtrl', function(){
    var scope;

    beforeEach(module('swiftBrowser.controllers'));

    beforeEach(inject(function($controller) {
        scope = {};
        $controller('RootCtrl', {$scope: scope});
    }));

    it('should list containers', inject(function($httpBackend) {
        var containers = [
            {"count": 10, "bytes": 1234, "name": "foo"},
            {"count": 20, "bytes": 2345, "name": "bar"},
        ];
        $httpBackend.whenGET('/v1/AUTH_abc?format=json')
            .respond(200, containers);

        expect(scope.containers).toEqual([]);
        $httpBackend.flush();
        expect(scope.containers).toEqual(containers);
    }));

    it('should set sort order', function() {
        expect(scope.orderProp).toEqual('name');
    });

});

describe('ContainerCtrl', function(){
    var scope;

    beforeEach(module('swiftBrowser.controllers'));

    beforeEach(inject(function($controller) {
        var params = {container: 'cont'};
        scope = {};
        $controller('ContainerCtrl',
                    {$scope: scope, $routeParams: params});
    }));

    it('should set sort order', function() {
        expect(scope.orderProp).toEqual('name');
    });

    it('should set container', function() {
        expect(scope.container).toEqual('cont');
    });

});

Add unit test for ContainerCtrl


module.exports = {
  testURL: 'http://localhost/',
  moduleFileExtensions: ['js', 'jsx', 'json', 'styl'],
  setupFiles: ['<rootDir>/test/jestLib/setup.js'],
  moduleDirectories: ['src', 'node_modules'],
  moduleNameMapper: {
    '^redux-cozy-client$': '<rootDir>/src/lib/redux-cozy-client',
    '\\.(png|gif|jpe?g|svg)$': '<rootDir>/test/__mocks__/fileMock.js',
    // identity-obj-proxy module is installed by cozy-scripts
    '.styl$': 'identity-obj-proxy',
    '^cozy-client$': 'cozy-client/dist/index'
  },
  transformIgnorePatterns: ['node_modules/(?!cozy-ui|cozy-harvest-lib)'],
  globals: {
    __ALLOW_HTTP__: false,
    __TARGET__: 'browser',
    __SENTRY_TOKEN__: 'token',
    cozy: {}
  }
}

module.exports = {
  testURL: 'http://localhost/',
  moduleFileExtensions: ['js', 'jsx', 'json', 'styl'],
  setupFiles: ['<rootDir>/test/jestLib/setup.js'],
  moduleDirectories: ['src', 'node_modules'],
  moduleNameMapper: {
    '^redux-cozy-client$': '<rootDir>/src/lib/redux-cozy-client',
    '\\.(png|gif|jpe?g|svg)$': '<rootDir>/test/__mocks__/fileMock.js',
    // identity-obj-proxy module is installed by cozy-scripts
    '.styl$': 'identity-obj-proxy',
    '^cozy-client$': 'cozy-client/dist/index'
  },
  transformIgnorePatterns: [
    'node_modules/(?!cozy-ui|cozy-harvest-lib|cozy-keys-lib)'
  ],
  globals: {
    __ALLOW_HTTP__: false,
    __TARGET__: 'browser',
    __SENTRY_TOKEN__: 'token',
    cozy: {}
  }
}

Add cozy-keys-lib exception to transformIgnorePatterns


import EventEmitter from 'events';
import { RESIZE } from '../constants/AppConstants';

class RendererStore extends EventEmitter {

  constructor(...args) {
    super(...args);

    this.data = {
      width: 0,
      height: 0,
      stageWidth: 0,
      stageHeight: 0,
      stageCenter: {x: 0,y: 0},
      resolution: 1
    };
  }

  get(key) {
    return this.data[key];
  }

  set(key, value) {
    return this.data[key] = value;
  }

  emitChange() {
    this.emit(RESIZE, this.data);
  }

  addChangeListener(callback) {
    this.on(RESIZE, callback);
  }
}

export default new RendererStore();

import EventEmitter from 'events';
import { RESIZE } from '../constants/AppConstants';

class RendererStore extends EventEmitter {

  constructor(...args) {
    super(...args);

    this.data = {
      width: 0,
      height: 0,
      stageWidth: 0,
      stageHeight: 0,
      stageCenter: {x: 0,y: 0},
      resolution: 1
    };
  }

  get(key) {
    return this.data[key];
  }

  set(key, value) {
    return this.data[key] = value;
  }

  emitChange() {
    this.emit(RESIZE, this.data);
  }

  addChangeListener(callback) {
    this.on(RESIZE, callback, this.data);
  }
}

export default new RendererStore();

Add data to resize callback


'use strict';
var sdk = require('flowxo-sdk'),
  service = require('../');

var credentials = {};
try {
  credentials = require('../credentials');
} catch(e) {}

beforeEach(function() {
  this.service = service;
  this.credentials = credentials;
  this.runner = new sdk.ScriptRunner(service, {
    credentials: credentials
  });
});

'use strict';

var sdk = require('flowxo-sdk'),
    service = require('../');

var credentials = {};
try {
  credentials = require('../credentials');
} catch(e) {}

beforeEach(function() {
  this.service = service;

  // Clone the credentials so they can't be globally
  // overwritten by a test spec
  this.credentials = JSON.parse(JSON.stringify(credentials));

  this.runner = new sdk.ScriptRunner(service, {
    credentials: this.credentials
  });
});

Clone credentials on each test run


//
// See https://github.com/jenkinsci/js-builder
//
var builder = require('@jenkins-cd/js-builder');

// Disable js-builder based linting for now.
// Will get fixed with https://github.com/cloudbees/blueocean/pull/55
builder.lint('none');

// Explicitly setting the src paths in order to allow the rebundle task to
// watch for changes in the JDL (js, css, icons etc).
// See https://github.com/jenkinsci/js-builder#setting-src-and-test-spec-paths
builder.src(['src/main/js', 'src/main/less', 'node_modules/@jenkins-cd/design-language']);

//
// Create the main "App" bundle.
// generateNoImportsBundle makes it easier to test with zombie.
//
builder.bundle('src/main/js/blueocean.js')
    .withExternalModuleMapping('jquery-detached', 'jquery-detached:jquery2')
    .inDir('target/classes/io/jenkins/blueocean')
    .less('src/main/less/blueocean.less')
    .generateNoImportsBundle();

//
// See https://github.com/jenkinsci/js-builder
//
var builder = require('@jenkins-cd/js-builder');

// Disable js-builder based linting for now.
// Will get fixed with https://github.com/cloudbees/blueocean/pull/55
builder.lint('none');

// Explicitly setting the src paths in order to allow the rebundle task to
// watch for changes in the JDL (js, css, icons etc).
// See https://github.com/jenkinsci/js-builder#setting-src-and-test-spec-paths
builder.src(['src/main/js', 'src/main/less', 'node_modules/@jenkins-cd/design-language/dist']);

//
// Create the main "App" bundle.
// generateNoImportsBundle makes it easier to test with zombie.
//
builder.bundle('src/main/js/blueocean.js')
    .withExternalModuleMapping('jquery-detached', 'jquery-detached:jquery2')
    .inDir('target/classes/io/jenkins/blueocean')
    .less('src/main/less/blueocean.less')
    .generateNoImportsBundle();

Watch for changes in the JDL package (rebundle)


var ancestralBlueprint = require('../../lib/ancestral-blueprint');

module.exports = {
  description: 'Generates a route and registers it with the router',

  availableOptions: [
    {
      name: 'type',
      type: String,
      values: ['route', 'resource'],
      default: 'route',
      aliases:[
        {'route': 'route'},
        {'resource': 'resource'}
      ]
    },
    {
      name: 'path',
      type: String,
      default: ''
    }
  ],

  _fixBlueprint: function(options) {
    var blueprint = ancestralBlueprint('component', this.project);
    blueprint.ui = options.ui;
    return blueprint;
  },

  fileMapTokens: function() {
    return ancestralBlueprint('component', this.project).fileMapTokens();
  },

  beforeInstall: function(options) {
    return ancestralBlueprint('component', this.project).beforeInstall(options);
  },

  shouldTouchRouter: function(name) {
    return ancestralBlueprint('component', this.project).shouldTouchRouter(name);
  },

  afterInstall: function(options) {
    return this._fixBlueprint(options).afterInstall(options);
  },

  beforeUninstall: function(options) {
    return ancestralBlueprint('component', this.project).beforeUninstall(options);
  },

  afterUninstall: function(options) {
    return this._fixBlueprint(options).afterUninstall(options);
  }
};

var ancestralBlueprint = require('../../lib/ancestral-blueprint');

module.exports = {
  description: 'Generates a route and registers it with the router',

  availableOptions: [
    {
      name: 'type',
      type: String,
      values: ['route', 'resource'],
      default: 'route',
      aliases:[
        {'route': 'route'},
        {'resource': 'resource'}
      ]
    },
    {
      name: 'path',
      type: String,
      default: ''
    }
  ],

  _fixBlueprint: function(options) {
    var blueprint = ancestralBlueprint('route', this.project);
    blueprint.ui = options.ui;
    return blueprint;
  },

  fileMapTokens: function() {
    return ancestralBlueprint('route', this.project).fileMapTokens();
  },

  beforeInstall: function(options) {
    return ancestralBlueprint('route', this.project).beforeInstall(options);
  },

  shouldTouchRouter: function(name) {
    return ancestralBlueprint('route', this.project).shouldTouchRouter(name);
  },

  afterInstall: function(options) {
    return this._fixBlueprint(options).afterInstall(options);
  },

  beforeUninstall: function(options) {
    return ancestralBlueprint('route', this.project).beforeUninstall(options);
  },

  afterUninstall: function(options) {
    return this._fixBlueprint(options).afterUninstall(options);
  }
};

Correct route blueprint mistakenly looking up wrong blueprint


import { SET_SEARCH_TERM } from './actions'

const DEFAULT_STATE = {
  searchTerm: ''
}

const setSearchTerm = (state, action) => {
  const newState = {}
  Object.assign(newState, state, {searchTerm: action.searchTerm})
}

const rootReducer = (state = DEFAULT_STATE, action) => {
  switch (action.type) {
    case SET_SEARCH_TERM:
      return setSearchTerm(state, action)
    default:
      return state
  }
}

export default rootReducer

import { SET_SEARCH_TERM } from './actions'

const DEFAULT_STATE = {
  searchTerm: ''
}

const setSearchTerm = (state, action) => {
  const newState = {}
  Object.assign(newState, state, {searchTerm: action.searchTerm})
  return newState
}

const rootReducer = (state = DEFAULT_STATE, action) => {
  switch (action.type) {
    case SET_SEARCH_TERM:
      return setSearchTerm(state, action)
    default:
      return state
  }
}

export default rootReducer

Add missing return statement in setSearchTerm


/*global Ember */

// ensure we don't share routes between all Router instances
var Router = Ember.Router.extend();

Router.reopen({
    //location: 'history', // use HTML5 History API instead of hash-tag based URLs
    rootURL: '/ghost/ember/' // admin interface lives under sub-directory /ghost
});

Router.map(function () {
    this.resource('posts', { path: '/' }, function () {
        this.route('post', { path: ':post_id' });
    });
    this.resource('editor', { path: '/editor/:post_id' });
    this.route('new', { path: '/editor' });
});

export default Router;

/*global Ember */

// ensure we don't share routes between all Router instances
var Router = Ember.Router.extend();

Router.reopen({
    location: 'history', // use HTML5 History API instead of hash-tag based URLs
    rootURL: '/ghost/ember/' // admin interface lives under sub-directory /ghost
});

Router.map(function () {
    this.resource('posts', { path: '/' }, function () {
        this.route('post', { path: ':post_id' });
    });
    this.resource('editor', { path: '/editor/:post_id' });
    this.route('new', { path: '/editor' });
});

export default Router;

Add HTML5 pushState support for Ember


module.exports = {
  options: {
    dir: 'dist',
    commit: true,
    push: true,
    message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
  },
  pages: {
    options: {
      remote: 'https://github.com/lewisnyman/lewisnyman.github.io.git',
      branch: 'master'
    }
  },
  local: {
    options: {
      remote: '../',
      branch: 'app'
    }
  }
};

module.exports = {
  options: {
    dir: 'dist',
    commit: true,
    push: true,
    message: 'Built %sourceName% from commit %sourceCommit% on branch %sourceBranch%'
  },
  pages: {
    options: {
      remote: 'https://github.com/lewisnyman/lewisnyman.github.io.git',
      branch: 'master',
      config: {
        'user.name': 'lewisnyman'
      },
    }
  },
  local: {
    options: {
      remote: '../',
      branch: 'app'
    }
  }
};

Add username to deploy config


jest.mock('../../internal/ESIAgent');

const Api = require('../../Api');

let api = new Api();
let agent = api._esiAgent;

afterEach(() => {
  agent.__reset();
});

test('Killmail.get', () => {
  agent.__expectRoute('get_killmails_killmail_id_killmail_hash', {'killmail_id': 1, 'killmail_hash': 'hash'});
  return api.killmail(1, 'hash').then(result => {
    expect(result).toBeDefined();
  });
});

jest.mock('../../internal/ESIAgent');

const Api = require('../../Api');

let api = new Api();
let agent = api._esiAgent;

afterEach(() => {
  agent.__reset();
});

test('Killmail.get', () => {
  agent.__expectRoute('get_killmails_killmail_id_killmail_hash', {
    'killmail_id': 1,
    'killmail_hash': 'hash'
  });
  return api.killmail(1, 'hash').then(result => {
    expect(result).toBeDefined();
  });
});

Fix formatting in Killmail test


var ContribBox = React.createClass({
    render: function() {
        return <div />;
    }
});

var SearchBox = React.createClass({
    getInitialState: function () {
        console.log(this.props);
        return {
            user: this.props.user || ''
        };
    },

    handleSubmit: function() {

    },

    submit: function(e) {
        var uri = '/' + this.state.user;
        e.preventDefault();

        var ps = window.history.pushState ? 1 : 0;
        [function(){location.replace(uri)},function(){window.history.pushState(null,null,uri)}][ps]();

        this.handleSubmit();
    },

    updateUser: function(e) {
        this.setState({
            user: e.target.value
        });
    },

    render: function() {
        return (
            <form className="ui" onSubmit={this.submit}>
                <div className="ui action center aligned input">
                    <input type="text" placeholder="나무위키 아이디 입력" defaultValue={this.props.user} onChange={this.updateUser} />
                    <button className="ui teal button">조회</button>
                </div>
            </form>
        );
    }
});

var ContribBox = React.createClass({
    handleLoad: function(user) {
        alert(user);
    },

    render: function() {
        return
asdf
;
    }
});

var SearchBox = React.createClass({
    getInitialState: function() {
        return {
            user: this.props.user || ''
        };
    },

    submit: function(e) {
        var uri = '/' + this.state.user;
        e.preventDefault();

        var ps = window.history.pushState ? 1 : 0;
        [function(){location.replace(uri)},function(){window.history.pushState(null,null,uri)}][ps]();

        this.props.onSubmit(this.state.user);
    },

    updateUser: function(e) {
        this.setState({
            user: e.target.value
        });
    },

    componentDidMount: function() {
        this.props.onSubmit(this.state.user);
    },

    render: function() {
        return (
            <form className="ui" onSubmit={this.submit}>

                    <input type="text" placeholder="나무위키 아이디 입력" defaultValue={this.props.user} onChange={this.updateUser} />
                    <button className="ui teal button">조회</button>

            </form>
        );
    }
});

Make codes being close to React style


import React from 'react'
import { Text } from 'react-native'
import { withNavigation } from 'react-navigation'

import ShuttleOverview from './ShuttleOverview'
import ScrollCard from '../common/ScrollCard'
import Touchable from '../common/Touchable'
import css from '../../styles/css'

export const ShuttleCard = ({
	navigation,
	stopsData,
	savedStops,
	gotoRoutesList,
	gotoSavedList,
	updateScroll,
	lastScroll,
}) => {
	const extraActions = [
		{
			name: 'Manage Stops',
			action: gotoSavedList
		}
	]

	return (
		<ScrollCard
			id="shuttle"
			title="Shuttle"
			scrollData={savedStops}
			renderItem={
				({ item: rowData }) => (
					<ShuttleOverview
						onPress={() => navigation.navigate('ShuttleStop', { stopID: rowData.id })}
						stopData={stopsData[rowData.id]}
						closest={Object.prototype.hasOwnProperty.call(rowData, 'savedIndex')}
					/>
				)
			}
			actionButton={
				<Touchable
					style={css.shuttlecard_addButton}
					onPress={() => gotoRoutesList()}
				>
					<Text style={css.shuttlecard_addText}>Add a Stop</Text>
				</Touchable>
			}
			extraActions={extraActions}
			updateScroll={updateScroll}
			lastScroll={lastScroll}
		/>
	)
}

export default withNavigation(ShuttleCard)

import React from 'react'
import { Text } from 'react-native'
import { withNavigation } from 'react-navigation'

import ShuttleOverview from './ShuttleOverview'
import ScrollCard from '../common/ScrollCard'
import Touchable from '../common/Touchable'
import css from '../../styles/css'

export const ShuttleCard = ({
	navigation,
	stopsData,
	savedStops,
	gotoRoutesList,
	gotoSavedList,
	updateScroll,
	lastScroll,
}) => {
	const extraActions = [
		{
			name: 'Manage Stops',
			action: gotoSavedList
		}
	]
	console.log(savedStops)
	return (
		<ScrollCard
			id="shuttle"
			title="Shuttle"
			scrollData={savedStops}
			renderItem={
				({ item: rowData }) => (
					<ShuttleOverview
						onPress={() => navigation.navigate('ShuttleStop', { stopID: rowData.id })}
						stopData={stopsData[rowData.id]}
						closest={Object.prototype.hasOwnProperty.call(rowData, 'savedIndex')}
					/>
				)
			}
			actionButton={
				<Touchable
					style={css.shuttlecard_addButton}
					onPress={() => gotoRoutesList()}
				>
					<Text style={css.shuttlecard_addText}>Add a Stop</Text>
				</Touchable>
			}
			extraActions={extraActions}
			updateScroll={updateScroll}
			lastScroll={lastScroll}
		/>
	)
}

export default withNavigation(ShuttleCard)

Add extra check in keyExtractor to prevent dublicate keys


import React from 'react'

function Footer() {
  return (

All rigths reserved

  )
}

export default Footer

import React from 'react'

function Footer() {
  return (

© 2017 All rigths reserved

  )
}

export default Footer

Replace all rights reserved at the bottom of the screen


var spawn = require('child_process').spawn;
var path = require('path');

module.exports = function (options) {
    options = options || {};
    options.url = options.url || 'http://nodejs.org';
    options.name = options.name || 'nodejs';

    var client;
    switch (process.platform) {
    case 'win32':
        client = path.resolve(__dirname + '/cefclient/cefclient');
        break;
    case 'linux':
        client = path.resolve(__dirname + '/build/default/topcube');
        break;
    default:
        console.warn('');
        return null;
        break;
    }

    var args = [];
    for (var key in options) {
        // Omit keys besides name & url for now until options
        // parsing bugs are resolved.
        if (process.platform === 'win32' &&
            (key !== 'name' || key !== 'url')) continue;
        args.push('--' + key + '=' + options[key]);
    }

    var child = spawn(client, args);
    child.on('exit', function(code) {
        process.exit(code);
    });
    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stderr);
    return child;
};

var spawn = require('child_process').spawn;
var path = require('path');

module.exports = function (options) {
    options = options || {};
    options.url = options.url || 'http://nodejs.org';
    options.name = options.name || 'nodejs';

    var client;
    switch (process.platform) {
    case 'win32':
        client = path.resolve(__dirname + '/cefclient/cefclient');
        break;
    case 'linux':
        client = path.resolve(__dirname + '/build/default/topcube');
        break;
    default:
        console.warn('');
        return null;
        break;
    }

    var args = [];
    for (var key in options) args.push('--' + key + '=' + options[key]);

    var child = spawn(client, args);
    child.on('exit', function(code) {
        process.exit(code);
    });
    child.stdout.pipe(process.stdout);
    child.stderr.pipe(process.stderr);
    return child;
};

Revert "Allow only name, url keys for win32."


var AlexaAppServer = require('alexa-app-server');

var MpdInterface = require('./apps/alexa-mpd-control/mpd_interface');
var mpd = new MpdInterface();

AlexaAppServer.start({
//    server_root:__dirname,     // Path to root
//    public_html:"public_html", // Static content
//    app_dir:"apps",            // Where alexa-app modules are stored
//    app_root:"/alexa/",        // Service root
  preRequest: function(json,req,res) {
    console.log("preRequest fired", json.request.intent && json.request.intent.name);
    json.userDetails = { "name":"Bob Smith" };

    var retPromise = new Promise(function(resolve, reject){
      if(json.request.intent && json.request.intent.name === "randalbum"){
        mpd.getRandomAlbumName().then(function(albumInfo){
           json[json.request.intent.name] = albumInfo;
          resolve(json);
        });
      }else{
        resolve(json);
      }
    });
    return retPromise;
  },
  port:8092,                 // What port to use, duh
  httpsPort:443,
  httpsEnabled:true,
  privateKey:'private-key.pem',
  certificate:'certificate.pem'
});

var AlexaAppServer = require('alexa-app-server');

var MpdInterface = require('./apps/alexa-mpd-control/mpd_interface');
var mpd = new MpdInterface();

AlexaAppServer.start({
//    server_root:__dirname,     // Path to root
//    public_html:"public_html", // Static content
//    app_dir:"apps",            // Where alexa-app modules are stored
//    app_root:"/alexa/",        // Service root
  preRequest: function(json,req,res) {
    console.log("preRequest fired", json.request.intent && json.request.intent.name);
    json.userDetails = { "name":"Bob Smith" };

    var retPromise = new Promise(function(resolve, reject){
      if(json.request.intent && json.request.intent.name === "randalbum"){
        mpd.getRandomAlbum().then(function(albumInfo){
           json[json.request.intent.name] = albumInfo;
          resolve(json);
        });
      }else{
        resolve(json);
      }
    });
    return retPromise;
  },
  port:8092,                 // What port to use, duh
  httpsPort:443,
  httpsEnabled:true,
  privateKey:'private-key.pem',
  certificate:'certificate.pem'
});

Fix bad function name call


export Tuttolino404 from "./tuttolino-404.png"
export TuttolinoCompetitor from "./tuttolino-competitor.svg"
export TuttolinoErrorMobile from "./tuttolino-error-mobile.png"
export TuttolinoError from "./tuttolino-error.svg"
export TuttolinoFamilySofa from "./tuttolino-family-sofa.svg"
export TuttolinoFamily from "./tuttolino-family.svg"
export TuttolinoGay from "./tuttolino-gay.svg"
export TuttolinoGlasses from "./tuttolino-glasses.svg"
export TuttolinoHey from "./tuttolino-hey.svg"
export TuttolinoHolmesNoCircle from "./tuttolino-holmes-no_circle.svg"
export TuttolinoHolmes from "./tuttolino-holmes.svg"
export TuttolinoHolmes from "./tuttolino-holmes-no_circle.svg"
export TuttolinoIntroScreens from "./tuttolino-intro-screens.svg"
export TuttolinoSergi from "./tuttolino-sergi.svg"
export TuttolinoSuccess from "./tuttolino-success.svg"
export TuttolinoTablet from "./tuttolino-tablet.svg"
export TuttolinoTuttiFan from "./tuttolino-tutti_fan.svg"

export Tuttolino404 from "./tuttolino-404.png"
export TuttolinoCompetitor from "./tuttolino-competitor.svg"
export TuttolinoErrorMobile from "./tuttolino-error-mobile.png"
export TuttolinoError from "./tuttolino-error.svg"
export TuttolinoFamilySofa from "./tuttolino-family-sofa.svg"
export TuttolinoFamily from "./tuttolino-family.svg"
export TuttolinoGay from "./tuttolino-gay.svg"
export TuttolinoGlasses from "./tuttolino-glasses.svg"
export TuttolinoHey from "./tuttolino-hey.svg"
export TuttolinoHolmesNoCircle from "./tuttolino-holmes-no_circle.svg"
export TuttolinoHolmes from "./tuttolino-holmes.svg"
export TuttolinoIntroScreens from "./tuttolino-intro-screens.svg"
export TuttolinoSergi from "./tuttolino-sergi.svg"
export TuttolinoSuccess from "./tuttolino-success.svg"
export TuttolinoTablet from "./tuttolino-tablet.svg"
export TuttolinoTuttiFan from "./tuttolino-tutti_fan.svg"

Deploy to GitHub pages


var Reflux = require('reflux');
var objectAssign = require('object-assign');

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

var _stack = []; // Container for the each object of message
var _counter = 0;
/**
 * Registry of all messages, mixin to manage all drawers.
 * Contains add, flush, and remove to do the mentioned.
 */
var MessageStore = Reflux.createStore({
  listenables: MessageActions,

  /**
   * Removes the message with given key
   * @param {int} id ID/Key of message which would be removed
   */
  onRemove: function(id) {
    // Index of the message
    var index = _stack.map(function(message) { return message.id }).indexOf(id);

    // Throw an exception if there are no results of the given id
    if ( index == -1 )
      throw new Error('The message (id) does not exist in the stack');

    _stack.splice(index, 1);
    this.trigger(_stack);
  },

  /**
   * Adds a new message to the stack
   */
  onAdd: function(data) {
    // Message defaults
    var _defaults = {
      id: ++_counter,
      duration: 10000,
      template: ''
    };

    _stack.push( data
      ? objectAssign(_defaults, data)
      : _defaults
    );

    this.trigger(_stack);
  },

  /**
   * Removes everything in the stack
   */
  onFlush: function() { this.trigger(_stack = []); }
};

module.exports = MessageStore;

var Reflux = require('reflux');
var objectAssign = require('object-assign');

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

var _stack = []; // Container for the each object of message
var _counter = 0;
/**
 * Registry of all messages, mixin to manage all drawers.
 * Contains add, flush, and remove to do the mentioned.
 */
var MessageStore = Reflux.createStore({
  listenables: MessageActions,

  /**
   * Removes the message with given key
   * @param {int} id ID/Key of message which would be removed
   */
  onRemove: function(id) {
    // Index of the message
    var index = _stack.map(function(message) { return message.id }).indexOf(id);

    // Throw an exception if there are no results of the given id
    if ( index == -1 )
      throw new Error('The message (id) does not exist in the stack');

    _stack.splice(index, 1);
    this.trigger(_stack);
  },

  /**
   * Adds a new message to the stack
   */
  onAdd: function(data) {
    // Message defaults
    var _defaults = {
      id: ++_counter,
      duration: 10000,
      template: ''
    };

    _stack.push( data
      ? objectAssign(_defaults, data)
      : _defaults
    );

    this.trigger(_stack);
  },

  /**
   * Removes everything in the stack
   */
  onClear: function(filter) {
    this.trigger(_stack = !!filter
      ? _stack.filter(function(message) { return filter == message.type })
      : []
    );
  }
};

module.exports = MessageStore;

Clear instead of Flush. Clearing now allows for a certain type to be filtered out.


var http = require('http')
  , url = require('url')
  , express = require('express')
  , rest = express()
  , path = require('path')
  , server = http.createServer(rest)
  , ap = require('argparse').ArgumentParser
  , colors = require('colors')
  , appium = require('./app/appium')
  , parser = require('./app/parser');

rest.configure(function() {
  rest.use(express.favicon());
  rest.use(express.static(path.join(__dirname, '/app/static')));
  rest.use(express.logger('dev'));
  rest.use(express.bodyParser());
  rest.use(express.methodOverride());
  rest.use(rest.router);
});

// Parse the command line arguments
var args = parser().parseArgs();

// Instantiate the appium instance
var appium = appium(args.app, args.UDID, args.verbose);
// Hook up REST http interface
appium.attachTo(rest);

// Start the web server that receives all the commands
server.listen(args.port, args.address, function() {
  var logMessage = "Appium REST http interface listener started on "+args.address+":"+args.port;
  console.log(logMessage.cyan);
});

var http = require('http')
  , url = require('url')
  , express = require('express')
  , rest = express()
  , path = require('path')
  , server = http.createServer(rest)
  , ap = require('argparse').ArgumentParser
  , colors = require('colors')
  , appium = require('./app/appium')
  , parser = require('./app/parser');

rest.configure(function() {
  var bodyParser = express.bodyParser()
    , parserWrap = function(req, res, next) {
        // wd.js sends us http POSTs with empty body which will make bodyParser fail.
        if (parseInt(req.get('content-length'), 10) <= 0) {
          return next();
        }
        bodyParser(req, res, next);
      };

  rest.use(express.favicon());
  rest.use(express.static(path.join(__dirname, '/app/static')));
  rest.use(express.logger('dev'));
  rest.use(parserWrap);
  rest.use(express.methodOverride());
  rest.use(rest.router);
});

// Parse the command line arguments
var args = parser().parseArgs();

// Instantiate the appium instance
var appium = appium(args.app, args.UDID, args.verbose);
// Hook up REST http interface
appium.attachTo(rest);

// Start the web server that receives all the commands
server.listen(args.port, args.address, function() {
  var logMessage = "Appium REST http interface listener started on "+args.address+":"+args.port;
  console.log(logMessage.cyan);
});

Deal with invalid http POST more gracefully.


function runTest()
{
    FBTest.sysout("issue5525.START");
    FBTest.openNewTab(basePath + "script/breakpoints/5525/issue5525.html", function(win)
    {
        FBTest.openFirebug();
        FBTest.enableScriptPanel()
        FBTest.enableConsolePanel()
        FBTest.selectPanel("console");

        var config = {tagName: "div", classes: "logRow logRow-errorMessage"};
        FBTest.waitForDisplayedElement("console", config, function(row)
        {
            // Verify displayed text.
            var reTextContent = /ReferenceError\:\s*undefinedVariable is not defined\s*var test = undefinedVariable;\s*issue5525.html\s*\(line 10\)/;
            FBTest.compare(reTextContent, row.textContent, "Text content must match.");

            // Create error breakpoint
            var br = row.getElementsByClassName("errorBreak")[0];
            FBTest.click(br);

            // Switch to the Script and Breakpoints panels.
            FBTest.selectPanel("script");
            var panel = FBTest.selectSidePanel("breakpoints");

            // Check content of the Breakpoints panel
            var panelNode = panel.panelNode;
            var rows = panelNode.getElementsByClassName("breakpointRow");
            FBTest.compare(rows.length, 1, "There must be one breakpoint");

            // Finish test
            FBTest.testDone("console.error.DONE");
        });

        FBTest.reload();
    });
}

function runTest()
{
    FBTest.sysout("issue5525.START");
    FBTest.openNewTab(basePath + "script/breakpoints/5525/issue5525.html", function(win)
    {
        FBTest.openFirebug();
        FBTest.enableScriptPanel()
        FBTest.enableConsolePanel()
        FBTest.selectPanel("console");

        var config = {tagName: "div", classes: "logRow logRow-errorMessage"};
        FBTest.waitForDisplayedElement("console", config, function(row)
        {
            // Verify displayed text.
            var reTextContent = /\s*undefinedVariable is not defined\s*var test = undefinedVariable;\s*issue5525.html\s*\(line 10\)/;
            FBTest.compare(reTextContent, row.textContent, "Text content must match.");

            // Create error breakpoint
            var br = row.getElementsByClassName("errorBreak")[0];
            FBTest.click(br);

            // Switch to the Script and Breakpoints panels.
            FBTest.selectPanel("script");
            var panel = FBTest.selectSidePanel("breakpoints");

            // Check content of the Breakpoints panel
            var panelNode = panel.panelNode;
            var rows = panelNode.getElementsByClassName("breakpointRow");
            FBTest.compare(rows.length, 1, "There must be one breakpoint");

            // Finish test
            FBTest.testDone("console.error.DONE");
        });

        FBTest.reload();
    });
}

Fix test to pass also with Firefox 13


export * from './controls/FirstPersonControls';
export * from './controls/OrbitControlsModule';
export * from './VirtualMouse';

export * from './controls/FirstPersonControls';
export * from './controls/OrbitControlsModule';
export * from './pass/index';
export * from './shader/index';
export * from './VirtualMouse';

Fix exporting pass & shaders


String.prototype.replaceAll = function(search, replace)
{
    //if replace is not sent, return original string otherwise it will
    //replace search string with 'undefined'.
    if (replace === undefined) {
        return this.toString();
    }

    return this.replace(new RegExp('[' + search + ']', 'g'), replace);
};

var repoFromLink = window.location.pathname.split("/")[2];

listRepositories(function(repos){
    var repo = repos.find(repo => repo.scm == repoFromLink);
    if(repo){
      processRepo(repo);
    }
});

function processRepo(repo){
  var commentBody = $(".comment-body, .commit-title, .commit-desc");
  var splittedBody = commentBody.text().split(" ");
  for( var i in splittedBody){
    var text = splittedBody[i];
    if (splittedBody[i].indexOf(repo.keyword) > -1){
      //Clean the link from some symbols usually added to destinguish issue-id from commit message
      var cleanedText = text.replaceAll("[", "").replaceAll("\\]", "").replaceAll("#", "");
      commentBody.html(commentBody.html().replace(text, '' + text + ''));
    }
  }
}

String.prototype.replaceAll = function(search, replace)
{
    //if replace is not sent, return original string otherwise it will
    //replace search string with 'undefined'.
    if (replace === undefined) {
        return this.toString();
    }

    return this.replace(new RegExp('[' + search + ']', 'g'), replace);
};

var repoFromLink = window.location.pathname.split("/")[2];

listRepositories(function(repos){
    var repos = repos.filter(repo => repo.scm == repoFromLink);
    if(repos){
      processRepo(repos);
    }
});

function processRepo(repos){
  var commentBody = $(".comment-body, .commit-title, .commit-desc");
  var splittedBody = commentBody.text().split(" ");
  for( var i in splittedBody){
    var text = splittedBody[i];
    for(var j in repos){
      var repo = repos[j];
      if (splittedBody[i].indexOf(repo.keyword) > -1){
        console.log("here");
        //Clean the link from some symbols usually added to destinguish issue-id from commit message
        var cleanedText = text.replaceAll("[", "").replaceAll("\\]", "").replaceAll("#", "");
        commentBody.html(commentBody.html().replace(text, '' + text + ''));
      }
    }
  }
}

Add support for multiple issue keywords in the same repo


'use strict';

module.exports = key => ({
  [`${key}-day`]: {
    label: 'Day'
  },
  [`${key}-month`]: {
    label: 'Month'
  },
  [`${key}-year`]: {
    label: 'Year'
  }
});

'use strict';

module.exports = key => ({
  [`${key}-day`]: {
    label: 'Day',
    autocomplete: 'bday-day'
  },
  [`${key}-month`]: {
    label: 'Month',
    autocomplete: 'bday-month'
  },
  [`${key}-year`]: {
    label: 'Year',
    autocomplete: 'bday-year'
  }
});

Add autocomplete to date component to assist with accessibility


//     Zepto.js
//     (c) 2010-2013 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function(){
  // __proto__ doesn't exist on IE<11, so redefine
  // the Z function to use object extension instead
  if (!('__proto__' in {})) {
    $.extend($.zepto, {
      Z: function(dom, selector){
        dom = dom || []
        $.extend(dom, $.fn)
        dom.selector = selector || ''
        dom.__Z = true
        return dom
      },
      // this is a kludge but works
      isZ: function(object){
        return $.type(object) === 'array' && '__Z' in object
      }
    })
  }

  // getComputedStyle shouldn't freak out when called
  // without a valid element as argument
  try {
    getComputedStyle(undefined)
  } catch(e) {
    var nativeGetComputedStyle = getComputedStyle;
    window.getComputedStyle = function(element){
      try {
        return nativeGetComputedStyle(element)
      } catch(e) {
        return null
      }
    }
  }
})()

//     Zepto.js
//     (c) 2010-2013 Thomas Fuchs
//     Zepto.js may be freely distributed under the MIT license.

;(function($){
  // __proto__ doesn't exist on IE<11, so redefine
  // the Z function to use object extension instead
  if (!('__proto__' in {})) {
    $.extend($.zepto, {
      Z: function(dom, selector){
        dom = dom || []
        $.extend(dom, $.fn)
        dom.selector = selector || ''
        dom.__Z = true
        return dom
      },
      // this is a kludge but works
      isZ: function(object){
        return $.type(object) === 'array' && '__Z' in object
      }
    })
  }

  // getComputedStyle shouldn't freak out when called
  // without a valid element as argument
  try {
    getComputedStyle(undefined)
  } catch(e) {
    var nativeGetComputedStyle = getComputedStyle;
    window.getComputedStyle = function(element){
      try {
        return nativeGetComputedStyle(element)
      } catch(e) {
        return null
      }
    }
  }
})(Zepto)

Make sure to properly patch the Zepto object in IE, not any global $ object.