'use strict';

import React, { Component, PropTypes } from 'react';
import Button from './Button';
import TextInput from './TextInput';
import { destTextInputStyle, errorMessageStyle } from '../stylesheets/styles';

class CreateTripPage extends Component {
  componentDidMount() {
    const { onEnterDestination } = this.props;

    // API documentation: https://developers.google.com/maps/documentation/javascript/places-autocomplete#add_autocomplete
    const input = document.getElementById('destinationInput');
    const options = { types: ['(regions)'] };
    const ac = new window.google.maps.places.Autocomplete(input, options);
    ac.addListener('place_changed', destinationChanged);

    function destinationChanged() {
      onEnterDestination(ac.getPlace());
    }
  }

  render() {
    const {
      error,
      onCreateTripPress,
      onEnterTitle
    } = this.props;

    return (

New Trip

          <TextInput
            onChange={onEnterTitle}
            placeholder="Trip Title"
          />
          <TextInput
            id="destinationInput"
            placeholder="Where do you want to go?"
            style={destTextInputStyle}
          />

{error}

          <Button label="Create Trip" onClick={onCreateTripPress} />

    );
  }
}

CreateTripPage.propTypes = {
  error: PropTypes.string,
  onCreateTripPress: PropTypes.func.isRequired,
  onEnterTitle: PropTypes.func.isRequired,
  onEnterDestination: PropTypes.func.isRequired
};

export default CreateTripPage;

'use strict';

import React, { Component, PropTypes } from 'react';
import Button from './Button';
import TextInput from './TextInput';
import { destTextInputStyle, errorMessageStyle } from '../stylesheets/styles';

class CreateTripPage extends Component {
  componentDidMount() {
    this.loadGoogleAutocompleteAPI();
  }

  render() {
    const {
      error,
      onCreateTripPress,
      onEnterTitle
    } = this.props;

    return (

New Trip

          <TextInput
            onChange={onEnterTitle}
            placeholder="Trip Title"
          />
          <TextInput
            id="destinationInput"
            placeholder="Where do you want to go?"
            style={destTextInputStyle}
          />

{error}

          <Button label="Create Trip" onClick={onCreateTripPress} />

    );
  }

  loadGoogleAutocompleteAPI() {
    const { onEnterDestination } = this.props;

    // API documentation: https://developers.google.com/maps/documentation/javascript/places-autocomplete#add_autocomplete
    const input = document.getElementById('destinationInput');
    const options = { types: ['(regions)'] };
    const ac = new window.google.maps.places.Autocomplete(input, options);
    ac.addListener(
      'place_changed',
      () => { onEnterDestination(ac.getPlace()); }
    );
  }
}

CreateTripPage.propTypes = {
  error: PropTypes.string,
  onCreateTripPress: PropTypes.func.isRequired,
  onEnterTitle: PropTypes.func.isRequired,
  onEnterDestination: PropTypes.func.isRequired
};

export default CreateTripPage;

Clean up autocomplete API load code


/* global app:true */

'use strict';

app.controller('MusicCtrl', ['$scope', 'Music', 'PER_PAGE', function($scope, Music, PER_PAGE) {
  var artistNum = 0;
  var finished = false;
  var size = PER_PAGE;

  $scope.waiting = false;
  $scope.artists = [];

  $scope.nextPage = function() {
    if (finished) {
      return ;
    }
    $scope.waiting = true;
    Music.artists(artistNum, size).then(function(data) {
      for (var i = 0; i < data.artists.length; i++) {
        $scope.artists.push(data.artists[i]);
      }
      artistNum += size;
      if (artistNum + size > data.limits.total) {
        size = data.limits.total - artistNum;
        if (size === 0) {
          finished = true;
        }
      }
      $scope.waiting = false;
    });
  };
}]);

/* global app:true */

'use strict';

app.controller('MusicCtrl', ['$scope', 'Music', 'PER_PAGE', function($scope, Music, PER_PAGE) {
  var artistNum = 0;
  var finished = false;
  var size = PER_PAGE;

  $scope.waiting = false;
  $scope.artists = [];

  $scope.nextPage = function() {
    if (finished) {
      return ;
    }
    $scope.waiting = true;
    Music.artists(artistNum, size).then(function(data) {
      for (var i = 0; i < data.artists.length; i++) {
        $scope.artists.push(data.artists[i]);
      }
      artistNum += size;
      if (artistNum + size > data.limits.total) {
        size = data.limits.total - artistNum;
        if (size <= 0) {
          finished = true;
        }
      }
      $scope.waiting = false;
    });
  };
}]);

Fix bug when less artists than one page


// console.log('package-pre-init start')
import { Session } from 'meteor/session';

web3Obj = new Web3();
Session.set('web3ObjReady', false);
setTimeout(
  function() {
    if (window.web3) {
      web3Obj.setProvider(window.web3.currentProvider);
      console.log('Using current provider');
    } else {
      web3Obj.setProvider(new Web3.providers.HttpProvider('http://localhost:8545'));
      console.log('Using new provider');
    }
    window.web3 = web3Obj;
    Session.set('web3ObjReady', true);
  }, 300)
// console.log('package-pre-init done')

if (typeof module !== 'undefined' && module.exports) {
  module.exports = web3Obj;
}

// console.log('package-pre-init start')
import { Session } from 'meteor/session';

web3Obj = new Web3();
Session.set('web3ObjReady', false);
Session.set('web3Counter', 0);

const web3Interval = setInterval(
  function() {
    if (window.web3) {
      web3Obj.setProvider(window.web3.currentProvider);
      window.web3 = web3Obj;
      Session.set('web3ObjReady', true);
      console.log('Using current provider');
      clearInterval(Session.get('web3Interval'));
      Session.delete('web3Interval');
    } else {
      let counter = Session.get('web3Counter');
      counter++;
      Session.set('web3Counter', counter);
      if (counter >= 3) {
        clearInterval(Session.get('web3Interval'));
        Session.delete('web3Interval');
        web3Obj.setProvider(new Web3.providers.HttpProvider('http://localhost:8545'));
        console.log('Using new provider');
        window.web3 = web3Obj;
        Session.set('web3ObjReady', true);
      }
    }
  }, 300)

Session.set('web3Interval', web3Interval);
// console.log('package-pre-init done')

if (typeof module !== 'undefined' && module.exports) {
  module.exports = web3Obj;
}

Check 3 times for web3 before going localhost


var App = (function () { "use strict";
  var pub = {};
  var scores = {
    1: 0,
    2: 0,
  };

  function render() {
    React.unmountComponentAtNode(document.getElementById('scoreboard'));
    React.render(
        <ScoreBoard scores={scores} />,
        document.getElementById('scoreboard')
    );
  }

  pub.start = function () {
    socket.on('update scores', function (newScores) {
      scores = newScores;
      render();
    });

    render();
  };

  return pub;
})();

var ScoreBoard = React.createClass({
  render: function() {
    return (

            P1 Score: { this.state.scores[1] }

            P2 Score: { this.state.scores[2] }

      );
  },
  getInitialState: function () {
    return this.props;
  }
});

$(App.start);

var App = (function () { "use strict";
  var pub = {};
  var scores = {
    1: 0,
    2: 0,
  };

  function render() {
    React.unmountComponentAtNode(document.getElementById('scoreboard'));
    React.render(
        <ScoreBoard scores={scores} />,
        document.getElementById('scoreboard')
    );
  }

  pub.start = function () {
    socket.on('update scores', function (newScores) {
      scores = newScores;
      render();
    });

    render();
  };

  return pub;
})();

var ScoreBoard = React.createClass({
  render: function() {
    return (

            P1 Score: { this.props.scores[1] }

            P2 Score: { this.props.scores[2] }

      );
  }
});

$(App.start);

Remove unneeded usage of state


'use strict';

angular.module('publicApp')
  .controller('LoginCtrl', ['$scope', '$http', '$location', 'UserService', function ($scope, $http, $location, $user) {
    function checkAdminExists() {
      $http.get("/api/v1/gateway/settings").success(function(resp){
        if (resp.success) {
          $scope.adminExists = resp.settings.adminExists
        }
        $scope.loading = false
      })
    }

    checkAdminExists()

    $scope.loading = true
    $scope.adminExists = false

    $scope.user = {}
    $scope.userService = $user

    $scope.logout = function() {
      $user.logout()
    }

    $scope.login = function () {
			var name = $scope.user.name;
			var password = $scope.user.password;
      $user.login(name, password, function(err, session){
        if (!!session.username) {
					$location.path('/gateway/account');
				} else {
					$location.path('/admin/users/new');
				}
      })
		}
  }]);

'use strict';

angular.module('publicApp')
  .controller('LoginCtrl', ['$scope', '$http', '$location', 'UserService', function ($scope, $http, $location, $user) {
    function checkAdminExists() {
      $http.get("/api/v1/gateway/settings").success(function(resp){
        if (resp.success) {
          $scope.adminExists = resp.settings.adminExists
        }
        $scope.loading = false
      })
    }

    checkAdminExists()

    $scope.loading = true
    $scope.adminExists = false
    $scope.admin = { email: '' }

    $scope.user = {}
    $scope.userService = $user

    $scope.logout = function() {
      $user.logout()
    }

    $scope.registerAdmin = function() {
      if ($scope.admin.email) {
        $http.post('/api/v1/admin/users', { email: $scope.admin.email }).success(function(resp) {
          console.log(resp)
        })
      }
    }

    $scope.login = function () {
			var name = $scope.user.name;
			var password = $scope.user.password;
      $user.login(name, password, function(err, session){
        if (!!session.username) {
					$location.path('/gateway/account');
				} else {
					$location.path('/admin/users/new');
				}
      })
		}
  }]);

Add function in client to register admin user.


import Component from 'ember-forge-ui/components/ef-list';
import Ember from 'ember';

const {
  computed,
  get
} = Ember;

/**
 * @module
 * @augments ember-forge-ui/components/ef-list
 */
export default Component.extend({

  // -------------------------------------------------------------------------
  // Dependencies

  // -------------------------------------------------------------------------
  // Attributes

  // -------------------------------------------------------------------------
  // Actions

  // -------------------------------------------------------------------------
  // Events

  /**
   * init event hook
   *
   * Configure the list
   *
   * @function
   * @returns {undefined}
   */
  init() {
    this._super(...arguments);
  },

  /**
   * didInsertElement event hook
   *
   * Apply correct styling to list
   *
   * @returns {undefined}
   */
  didInsertElement() {
    this._super(...arguments);

    this.styleList();
  },

  // -------------------------------------------------------------------------
  // Properties

  // -------------------------------------------------------------------------
  // Observers

  // -------------------------------------------------------------------------
  // Methods

  /**
   * Apply/remove class names dependent on whether an ordered list
   *
   * @private
   * @override
   * @returns {undefined}
   */
  setListType() {
    this._super(...arguments);

    if(get(this, 'ordered')) {
      get(this, 'classNames').removeObject('list-group');
    } else {
      get(this, 'classNames').addObject('list-group');
    }
  },

  /**
   * Apply/remove class names dependent on whether an ordered list
   *
   * @private
   * @returns {undefined}
   */
  styleList() {
    if(get(this, 'ordered')) {
      this.$('.list-group-item').each(function() {
        $(this).removeClass('list-group-item');
      });
    }
  }

});

import Component from 'ember-forge-ui/components/ef-list';
import Ember from 'ember';

const {
  get
} = Ember;

/**
 * @module
 * @augments ember-forge-ui/components/ef-list
 */
export default Component.extend({

  // -------------------------------------------------------------------------
  // Dependencies

  // -------------------------------------------------------------------------
  // Attributes

  // -------------------------------------------------------------------------
  // Actions

  // -------------------------------------------------------------------------
  // Events

  /**
   * init event hook
   *
   * Configure the list
   *
   * @function
   * @returns {undefined}
   */
  init() {
    this._super(...arguments);
  },

  /**
   * didInsertElement event hook
   *
   * Apply correct styling to list
   *
   * @returns {undefined}
   */
  didInsertElement() {
    this._super(...arguments);

    this.styleList();
  },

  // -------------------------------------------------------------------------
  // Properties

  // -------------------------------------------------------------------------
  // Observers

  // -------------------------------------------------------------------------
  // Methods

  /**
   * Apply/remove class names dependent on whether an ordered list
   *
   * @private
   * @override
   * @returns {undefined}
   */
  setListType() {
    this._super(...arguments);

    if(get(this, 'ordered')) {
      get(this, 'classNames').removeObject('list-group');
    } else {
      get(this, 'classNames').addObject('list-group');
    }
  },

  /**
   * Apply/remove class names dependent on whether an ordered list
   *
   * @private
   * @returns {undefined}
   */
  styleList() {
    if(get(this, 'ordered')) {
      this.$('.list-group-item').removeClass('list-group-item');
    }
  }

});

Improve jQuery object iteration; remove unused deconstructed property


var LoadingBar = function(game, parent, color) {
    Phaser.Group.call(this, game, parent);

    // Images loaded by MyGame.Init
    this.background = game.add.sprite(game.world.centerX, game.world.centerY, 'loadingBarBg');
    this.background.anchor.setTo(0.5, 0.5);
    this.add(this.background);

    // Left to right loading bar
    this.bar = game.add.sprite(game.world.centerX - 175, game.world.centerY - 16, 'loadingBar');
    // Center to outsides loading bar.
    //this.bar = game.add.sprite(game.world.centerX, game.world.centerY, 'loadingBar');
    //this.bar.anchor.setTo(0.5, 0.5);
    this.add(this.bar);
};

LoadingBar.prototype = Object.create(Phaser.Group.prototype);
LoadingBar.prototype.constructor = LoadingBar;

var LoadingBar = function(game, parent) {
    Phaser.Group.call(this, game, parent);

    // Images loaded by MyGame.Init
    this.background = game.add.sprite(game.world.centerX, game.world.centerY, 'loadingBarBg');
    this.background.anchor.setTo(0.5, 0.5);
    this.add(this.background);

    // Left to right loading bar
    this.bar = game.add.sprite(game.world.centerX - 175, game.world.centerY - 16, 'loadingBar');
    // Center to outsides loading bar.
    //this.bar = game.add.sprite(game.world.centerX, game.world.centerY, 'loadingBar');
    //this.bar.anchor.setTo(0.5, 0.5);
    this.add(this.bar);
};

LoadingBar.prototype = Object.create(Phaser.Group.prototype);
LoadingBar.prototype.constructor = LoadingBar;

Remove unused parameter from object.


import React from 'react';

import FeaturedItems from '../FeaturedItems';
import ItemCard from '../ItemCard';

const Jobs = props => {
  return (
    <FeaturedItems>
      {props.data.map(job =>
        <ItemCard
          key={job._id}
          id={job._id}
          imgUrl={
            job.info.imgUrl &&
            job.info.imgUrl.replace(/upload\//, 'upload/thumbs/')
          }
          title={job.info.title}
          description={job.info.description}
          expDate={job.expDate}
          companyName={job.companyName}
          location={job.location}
        />
      )}
    </FeaturedItems>
  );
};

export default Jobs;

import React from 'react';

import FeaturedItems from '../FeaturedItems';
import ItemCard from '../ItemCard';

const parseImgUrl = url => url.replace(/upload\//, 'upload/thumbs/');

const Jobs = props => {
  return (
    <FeaturedItems>
      {props.data.map(job =>
        <ItemCard
          key={job._id}
          id={job._id}
          imgUrl={job.info.imgUrl && parseImgUrl(job.info.imgUrl)}
          title={job.info.title}
          description={job.info.description}
          expDate={job.expDate}
          companyName={job.companyName}
          location={job.location}
        />
      )}
    </FeaturedItems>
  );
};

export default Jobs;

Refactor url parsing into function


/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';

const { parent } = window;

if ( parent.pairedBrowsingApp ) {
	window.ampPairedBrowsingClient = true;
	const app = parent.pairedBrowsingApp;

	app.registerClientWindow( window );

	domReady( () => {
		if ( app.documentIsAmp( document ) ) {
			// Hide the paired browsing menu item.
			const pairedBrowsingMenuItem = document.getElementById( 'wp-admin-bar-amp-paired-browsing' );
			if ( pairedBrowsingMenuItem ) {
				pairedBrowsingMenuItem.remove();
			}

			// Hide menu item to view non-AMP version.
			const ampViewBrowsingItem = document.getElementById( 'wp-admin-bar-amp-view' );
			if ( ampViewBrowsingItem ) {
				ampViewBrowsingItem.remove();
			}
		} else {
			/**
			 * Override the entire AMP menu item with just "Non-AMP". There should be no link to
			 * the AMP version since it is already being shown.
			 */
			const ampMenuItem = document.getElementById( 'wp-admin-bar-amp' );
			if ( ampMenuItem ) {
				ampMenuItem.innerHTML = 'Non-AMP';
			}
		}
	} );
}

/**
 * WordPress dependencies
 */
import domReady from '@wordpress/dom-ready';

const { parent } = window;

if ( parent.pairedBrowsingApp ) {
	window.ampPairedBrowsingClient = true;
	const app = parent.pairedBrowsingApp;

	app.registerClientWindow( window );

	domReady( () => {
		if ( app.documentIsAmp( document ) ) {
			// Hide the paired browsing menu item.
			const pairedBrowsingMenuItem = document.getElementById( 'wp-admin-bar-amp-paired-browsing' );
			if ( pairedBrowsingMenuItem ) {
				pairedBrowsingMenuItem.remove();
			}

			// Hide menu item to view non-AMP version.
			const ampViewBrowsingItem = document.getElementById( 'wp-admin-bar-amp-view' );
			if ( ampViewBrowsingItem ) {
				ampViewBrowsingItem.remove();
			}
		} else {
			/**
			 * No need to show the AMP menu in the Non-AMP window.
			 */
			const ampMenuItem = document.getElementById( 'wp-admin-bar-amp' );
			ampMenuItem.remove();
		}
	} );
}

Remove AMP menu in non-AMP window


exports.nit = function(env) {
    var $ = env.$;
    // at least one author
    var authors = $(".section#authors address");
    if (authors.length < 1) {
        return env.error("No authors");
    }

    var hauth = $("#document .authors");
    hauth.empty();
    hauth.comment("Automatically generated from $('.section#authors address')");
    authors.each(function() {
        var author = $("<div>").addClass("author");
        // Only pull out the default (hopefully English-ified) name from the
        // author information into the header.

        // Note: "initial" is not a valid RFC 6350 property name.
        var initial = $(".initial[lang='']", this).text();
        if (initial.length === 0) {
            initial = $(".n .given-name[lang='']", this).text().slice(0,1) + ".";
        }
        $("<span>").addClass("initial").text(initial).appendTo(author);
        $("<span>").addClass("surname").text($(".n .family-name[lang='']", this).text()).appendTo(author);
        $("<span>").addClass("company").text($(".org[lang='']", this).text()).appendTo(author);
        author.appendTo(hauth);
    });
};

exports.nit = function(env) {
    var $ = env.$;
    // at least one author
    var authors = $(".section#authors address");
    if (authors.length < 1) {
        return env.error("No authors");
    }

    var hauth = $("#document .authors");
    if (hauth.length < 1) {
        hauth = $("<div class='authors'/>");
        hauth.appendTo($("#document"));
    }
    hauth.empty();
    hauth.comment("Automatically generated from $('.section#authors address')");
    authors.each(function() {
        var author = $("<div>").addClass("author");
        // Only pull out the default (hopefully English-ified) name from the
        // author information into the header.

        // Note: "initial" is not a valid RFC 6350 property name.
        var initial = $(".initial[lang='']", this).text();
        if (initial.length === 0) {
            initial = $(".n .given-name[lang='']", this).text().slice(0,1) + ".";
        }
        $("<span>").addClass("initial").text(initial).appendTo(author);
        $("<span>").addClass("surname").text($(".n .family-name[lang='']", this).text()).appendTo(author);
        $("<span>").addClass("company").text($(".org[lang='']", this).text()).appendTo(author);
        author.appendTo(hauth);
    });
};

Add author info in the document info if it doesn't exist.


/**
 * Validation
 *
 * @constructor
 * @param {object} options
 */
var Validation = function(options) {

  // Save a reference to the ‘this’
  var self = this;

  var defaultOptions = {
    singleError: true,
    errorMessages: errorMessages,
    cache: false
  };

  each(defaultOptions, function(key, value) {

    if (isObject(value) && options[key]) {
      self[key] = merge(options[key], defaultOptions[key]);

    } else if (isObject(value) && !options[key]) {
      self[key] = merge ({}, defaultOptions[key]);

    } else {
      self[key] = options[key] || defaultOptions[key];
    }

  });

  this.errors = new ValidationError();

};

/**
 * Validation
 *
 * @constructor
 * @param {object} options
 */
var Validation = function(options) {

  // Save a reference to the ‘this’
  var self = this;

  var defaultOptions = {
    singleError: true,
    errorMessages: errorMessages,
    cache: false
  };

  each(defaultOptions, function(key, value) {

    if (isObject(value) && options[key]) {
      self[key] = merge(options[key], defaultOptions[key]);

    } else if (isObject(value) && !options[key]) {
      self[key] = merge ({}, defaultOptions[key]);

    } else {
      self[key] = (isDefined(options[key])) ? options[key] : defaultOptions[key];
    }

  });

  this.errors = new ValidationError();

};

Fix merging of the ‘Options’ object


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

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

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

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

  encode.exit = {
    opacity: zero
  };

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

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

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

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

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

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

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

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

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

  encode.exit = {
    opacity: zero
  };

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

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

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

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

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

Fix legend gradient label text to use update set.


import { BrowserPolicy } from 'meteor/browser-policy-common';
BrowserPolicy.content.allowConnectOrigin("wss:");
BrowserPolicy.content.allowConnectOrigin("ws:");
BrowserPolicy.content.allowFontOrigin('data:');
BrowserPolicy.content.allowOriginForAll('*.bootstrapcdn.com');

import { BrowserPolicy } from 'meteor/browser-policy-common';

BrowserPolicy.content.allowConnectOrigin('wss:');
BrowserPolicy.content.allowConnectOrigin('ws:');
BrowserPolicy.content.allowFontOrigin('data:');
BrowserPolicy.content.allowOriginForAll('https://maxcdn.bootstrapcdn.com');

Clean code of browser policy file


var express = require('express');
var passport = require('passport');
var util = require('./lib/utility.js');

// Load environment variables
if (process.env.NODE_ENV !== 'integration') {
  require('dotenv').config({ path: './env/.env' });
}

var app = express();

// Initial Configuration, Static Assets, & View Engine Configuration
require('./config/initialize.js')(app, express);
// Authentication Middleware: Express Sessions, Passport Strategy
require('./config/auth.js')(app, express, passport);

// Pre-Authentication Routes & OAuth Requests
require('./routes/auth-routes.js')(app, passport);

//Authentication check currently commented out, uncomment line to re-activate
app.use(util.ensureAuthenticated);

// View Routes
require('./routes/view-routes.js')(app);
// API Routes
// require('./routes/api-routes.js')(app);

// Wildcard route
app.get('/*', function(req, res) {
  res.redirect('/');
})

app.listen(Number(process.env.PORT), process.env.HOST, function() {
  console.log(process.env.APP_NAME + ' is listening at ' + process.env.HOST + ' on port ' + process.env.PORT + '.')
});

// Load environment variables
if (process.env.NODE_ENV !== 'integration') {
  require('dotenv').config({ path: './env/.env' });
}

var express = require('express');
var passport = require('passport');
var util = require('./lib/utility.js');

var app = express();

// Initial Configuration, Static Assets, & View Engine Configuration
require('./config/initialize.js')(app, express);
// Authentication Middleware: Express Sessions, Passport Strategy
require('./config/auth.js')(app, express, passport);

// Pre-Authentication Routes & OAuth Requests
require('./routes/auth-routes.js')(app, passport);

//Authentication check currently commented out, uncomment line to re-activate
app.use(util.ensureAuthenticated);

// View Routes
require('./routes/view-routes.js')(app);
// API Routes
// require('./routes/api-routes.js')(app);

// Wildcard route
app.get('/*', function(req, res) {
  res.redirect('/');
})

app.listen(Number(process.env.PORT), process.env.HOST, function() {
  console.log(process.env.APP_NAME + ' is listening at ' + process.env.HOST + ' on port ' + process.env.PORT + '.')
});

Load environment variable first in express app


/**
 * All methods related to the search
 */
jsBackend.search =
{
    // init, something like a constructor
    init: function()
    {
        $synonymBox = $('input.synonymBox');

        // synonyms box
        if($synonymBox.length > 0)
        {
            $synonymBox.multipleTextbox(
            {
                emptyMessage: jsBackend.locale.msg('NoSynonymsBox'),
                addLabel: utils.string.ucfirst(jsBackend.locale.lbl('Add')),
                removeLabel: utils.string.ucfirst(jsBackend.locale.lbl('DeleteSynonym'))
            });
        }

        // settings enable/disable
        $('#searchModules input[type=checkbox]').on('change', function()
        {
            $this = $(this);

            if($this.is(':checked')) { $('#' + $this.attr('id') + 'Weight').removeAttr('disabled').removeClass('disabled'); }
            else { $('#' + $this.attr('id') + 'Weight').prop('disabled', true).addClass('disabled'); }
        });
    }
};

$(jsBackend.search.init);

/**
 * All methods related to the search
 */
jsBackend.search = {
  init: function() {
    var $synonymBox = $('input.synonymBox');

    // synonyms box
    if ($synonymBox.length > 0) {
      $synonymBox.multipleTextbox({
        emptyMessage: jsBackend.locale.msg('NoSynonymsBox'),
        addLabel: utils.string.ucfirst(jsBackend.locale.lbl('Add')),
        removeLabel: utils.string.ucfirst(jsBackend.locale.lbl('DeleteSynonym'))
      });
    }

    // settings enable/disable
    $('#searchModules').find('input[type=checkbox]').on('change', function() {
      var $this = $(this);
      var $weightElement = $('#' + $this.attr('id') + 'Weight');

      if ($this.is(':checked')) {
        $weightElement.removeAttr('disabled').removeClass('disabled');

        return;
      }

      $weightElement.prop('disabled', true).addClass('disabled');
    });
  }
};

$(jsBackend.search.init);

Clean up backen search js


const fs = require('fs-extra');
const path = require('path');
const yargs = require('yargs').argv;

const validEnvironments = ['beta', 'development'];
if (!validEnvironments.includes(yargs.env)) {
  console.log(`Invalid ENVIRONMENT provided. Must be one of: [${validEnvironments.join('|')}]`);
  process.exit(1);
}

const env = yargs.env;
const workspaceRoot = path.join(__dirname, '..');
const buildDirectory = path.join(workspaceRoot, 'dist', 'extension');
const manifestPath = path.join(buildDirectory, 'manifest.json');

const manifest = require(manifestPath);
const changes = require(path.join(workspaceRoot, 'src', `manifest.${env}.json`));

// Clobber any keys in the beta manifest across.
Object.assign(manifest, changes);

// If we're on Travis, we should append the build number to the version number.
if (process.env.TRAVIS_BUILD_NUMBER) {
  manifest.version += `.${process.env.TRAVIS_BUILD_NUMBER}`;
}

// Delete the old one.
fs.unlinkSync(manifestPath);

// And write our new one.
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));

console.log(`${env} manifest applied.`);

const fs = require('fs-extra');
const path = require('path');
const yargs = require('yargs').argv;

const validEnvironments = ['beta', 'development'];
if (!validEnvironments.includes(yargs.env)) {
  console.log(`Invalid ENVIRONMENT provided. Must be one of: [${validEnvironments.join('|')}]`);
  process.exit(1);
}

const env = yargs.env;
const workspaceRoot = path.join(__dirname, '..');
const buildDirectory = path.join(workspaceRoot, 'dist', 'extension');
const manifestPath = path.join(buildDirectory, 'manifest.json');

const manifest = require(manifestPath);
const changes = require(path.join(workspaceRoot, 'src', `manifest.${env}.json`));

// Clobber any keys in the beta manifest across.
Object.assign(manifest, changes);

// If we're on Travis, we should append the build number to the version number.
if (process.env.TRAVIS_BUILD_NUMBER) {
  // I goofed up and didn't realize Google complained about version numbers not
  // going up so we're going to add 1500 to the build number until we're on the
  // next minor version :P
  manifest.version += `.${parseInt(process.env.TRAVIS_BUILD_NUMBER) + 1500}`;
}

// Delete the old one.
fs.unlinkSync(manifestPath);

// And write our new one.
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));

console.log(`${env} manifest applied.`);

Add 1500 to build number until next minor bump


module.exports = {
    'swagger--collection-format': function (value) {
        return {
            'csv': 'comma separated (`foo,bar`)',
            'ssv': 'space separated (`foo bar`)',
            'tsv': 'tab separated (`foo\\tbar`)',
            'pipes': 'pipe separated )`foo|bar`)',
            'multi': 'multiple parameters (`foo=bar&foo=baz`)'
        }[value];
    }
}

module.exports = {
    'swagger--collection-format': function (value) {
        return {
            'csv': 'comma separated (`foo,bar`)',
            'ssv': 'space separated (`foo bar`)',
            'tsv': 'tab separated (`foo\\tbar`)',
            'pipes': 'pipe separated (`foo|bar`)',
            'multi': 'multiple parameters (`foo=bar&foo=baz`)'
        }[value];
    }
}

Correct type ("(" instead of ")")


module.exports = {
  siteMetadata: {
    title: 'keff',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sass',
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        name: 'keff.me',
        short_name: 'keff.me',
        start_url: '/',
        display: 'minimal-ui',
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/posts`,
        name: 'markdown-pages',
      },
    },
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          'gatsby-remark-katex',
          'gatsby-remark-prismjs',
          'gatsby-remark-external-links',
        ],
      },
    },
    'gatsby-plugin-offline',
  ],
};

module.exports = {
  siteMetadata: {
    title: 'keff',
  },
  plugins: [
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sass',
    {
      resolve: 'gatsby-plugin-manifest',
      options: {
        name: 'keff.dev',
        short_name: 'keff.dev',
        start_url: '/',
        display: 'minimal-ui',
      },
    },
    {
      resolve: 'gatsby-source-filesystem',
      options: {
        path: `${__dirname}/src/posts`,
        name: 'markdown-pages',
      },
    },
    {
      resolve: 'gatsby-transformer-remark',
      options: {
        plugins: [
          'gatsby-remark-katex',
          'gatsby-remark-prismjs',
          'gatsby-remark-external-links',
        ],
      },
    },
    'gatsby-plugin-offline',
  ],
};

Update config to point at keff.dev


'use strict';

import React, { Component } from 'react';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';

class Navigation extends Component {
  render() {
    return (
      <Navbar brand='Football Hackday'>
        <Nav>
          <NavItem href='http://footballhackday.github.io/london/'>Website</NavItem>
          <NavItem href='https://github.com/X8/hackday-example'>Source code</NavItem>
        </Nav>
      </Navbar>
    )
  }
}

export default Navigation;

'use strict';

import React, { Component } from 'react';
import Navbar from 'react-bootstrap/lib/Navbar';
import Nav from 'react-bootstrap/lib/Nav';
import NavItem from 'react-bootstrap/lib/NavItem';

class Navigation extends Component {
  render() {
    return (
      <Navbar brand='Football Hackday'>
        <Nav>
          <NavItem href='http://footballhackday.github.io/london/'>Website</NavItem>
          <NavItem href='https://github.com/X8/hackday-example'>Source code</NavItem>
          <NavItem href='https://hackday-api.herokuapp.com/'>API</NavItem>
        </Nav>
      </Navbar>
    )
  }
}

export default Navigation;

Add a link to the API


import Apps from 'steemscript/apps.json';

export function makeCanonicalLink(d) {
    var canonicalUrl = 'https://steemit.com' + d.link;
    if (
        d.json_metadata &&
        d.json_metadata.app &&
        typeof d.json_metadata.app !== 'string'
    ) {
        return canonicalUrl;
    }
    const hasAppTemplateData =
        d.json_metadata &&
        d.json_metadata.app &&
        d.category &&
        d.json_metadata.app.split('/').length === 2;
    if (hasAppTemplateData) {
        const app = d.json_metadata.app.split('/')[0];
        const hasAppData = Apps[app] && Apps[app].url_scheme;
        if (hasAppData) {
            canonicalUrl = Apps[app].url_scheme
                .split('{category}')
                .join(d.category)
                .split('{username}')
                .join(d.author)
                .split('{permlink}')
                .join(d.permlink);
        }
    }
    return canonicalUrl;
}

import Apps from 'steemscript/apps.json';

export function makeCanonicalLink(d) {
    let canonicalUrl = 'https://steemit.com' + d.link;

    if (d.json_metadata) {
        if (
            d.json_metadata.canonical_link &&
            typeof d.json_metadata.canonical_link === 'string'
        ) {
            const urlTester = new RegExp(
                /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/gm
            );
            if (urlTester.test(d.json_metadata.canonical_link)) {
                return d.json_metadata.canonical_link;
            }
        }

        if (d.json_metadata.app && typeof d.json_metadata.app === 'string') {
            const hasAppTemplateData =
                d.json_metadata &&
                d.json_metadata.app &&
                d.category &&
                d.json_metadata.app.split('/').length === 2;
            if (hasAppTemplateData) {
                const app = d.json_metadata.app.split('/')[0];
                const hasAppData = Apps[app] && Apps[app].url_scheme;
                if (hasAppData) {
                    canonicalUrl = Apps[app].url_scheme
                        .split('{category}')
                        .join(d.category)
                        .split('{username}')
                        .join(d.author)
                        .split('{permlink}')
                        .join(d.permlink);
                }
            }
        }
    }
    return canonicalUrl;
}

Allow the use of the json_metadata 'canonical_link' to set a canonical link on top of the app tag


const validKeys = ['key1','key2', 'key3', 'key4', 'key5']; //TODO replace API keys in request with JWT-token?
const validator = {
    validateKey: function(req, res, next){
        if(validKeys.indexOf(req.query.key)===-1){
            res.status(401);
            res.json({"status":"401", "message":"invalid credentials"});
            return;
        }
        next();
    },
    validateRate: function(req, res, next){
        next(); //TODO
    }
};

module.exports = validator;

const RateLimiter = require("rolling-rate-limiter");

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

const validKeys = ['key1','key2', 'key3', 'key4', 'key5']; //TODO replace API keys in request with JWT-token?
const limiter = RateLimiter({
    interval: 60*60*1000, //1 hour in miliseconds
    maxInInterval: config.max_requests_per_hour
});
const validator = {
    validateKey: function(req, res, next){
        if(validKeys.indexOf(req.query.key)===-1){
            res.status(401);
            res.json({"status":"401", "message":"invalid credentials"});
            return;
        }
        next();
    },
    validateRate: function(req, res, next){
        const timeLeft = limiter(req.query.key);
        if (timeLeft > 0) {
            // limit was exceeded, action should not be allowed
            // timeLeft is the number of ms until the next action will be allowed
            res.status(429);
            res.json({"status":"429", "message":"Request limit excceded- try after "+(timeLeft/1000)+"s"});
        } else {
            next();
            // limit was not exceeded, action should be allowed
        }
    }
};

module.exports = validator;

Add rolling-rate-limiter for limiting api request rate


import React, { Component } from 'react';
import PropTypes from 'prop-types';

import './OperationCard.css';

class OperationCard extends Component {
  render() {
    const { operator, onOptionsChange } = this.props;
    return (

{operator.type}

          {this.renderOptionsInput(operator, onOptionsChange)}

    );
  }

  renderOptionsInput(operator, onOptionsChange) {
    switch (operator.type) {
      case 'debounceTime': {
        return (
          <input
            value={operator.options.dueTime}
            onChange={e => onOptionsChange({ dueTime: Number(e.target.value) })}
          />
        );
      }
      default: {
        return null;
      }
    }
  }
}

const propTypes = {
  operator: PropTypes.object.isRequired,
  onOptionsChange: PropTypes.func,
};
const defaultProps = {
  onOptionsChange: () => {},
};
OperationCard.propTypes = propTypes;
OperationCard.defaultProps = defaultProps;

export default OperationCard;

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import './OperationCard.css';

class OperationCard extends Component {
  render() {
    const { operator, onOptionsChange } = this.props;
    return (

{operator.type}

          {this.renderOptionsInput(operator, onOptionsChange)}

    );
  }

  renderOptionsInput(operator, onOptionsChange) {
    switch (operator.type) {
      case 'debounceTime': {
        return (
          <input
            value={operator.options.dueTime}
            onChange={e => onOptionsChange({ dueTime: Number(e.target.value) })}
            onKeyDown={onKeyDownHandlerForNumber('dueTime')}
          />
        );
      }
      default: {
        return null;
      }
    }

    function onKeyDownHandlerForNumber(optionsKey) {
      return (e) => {
        let delta = 0;
        if (e.keyCode === 38) { delta = 1; }
        if (e.keyCode === 40) { delta = -1; }
        onOptionsChange({ [optionsKey]: Number(e.target.value) + delta });
      };
    }
  }
}

const propTypes = {
  operator: PropTypes.object.isRequired,
  onOptionsChange: PropTypes.func,
};
const defaultProps = {
  onOptionsChange: () => {},
};
OperationCard.propTypes = propTypes;
OperationCard.defaultProps = defaultProps;

export default OperationCard;

Add key down handler for debounceTime options


var express             = require('express');
var http                = require('http');
var path                = require('path');
var app                 = express();
var server              = require('http').createServer(app);
var io                  = require('socket.io').listen(server);
var spotify             = require('spotify-node-applescript');
var SpotifyRemoteServer = require('./lib/spotify_remote_server');

io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('log level', 1);

app.configure(function() {
  app.set('port', process.env.PORT || 3000);
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(app.router);
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function() {
  app.use(express.errorHandler());
});

app.get('/', function(req, res) {
  res.sendfile(__dirname + '/public/index.html');
});

server.listen(app.get('port'), function() {
  console.log('Your spotify remote is awaiting commands on: http://localhost:' + app.get('port'));
});

new SpotifyRemoteServer(io, spotify);

var express             = require('express');
var http                = require('http');
var path                = require('path');
var app                 = express();
var server              = require('http').createServer(app);
var io                  = require('socket.io').listen(server);
var spotify             = require('spotify-node-applescript');
var SpotifyRemoteServer = require('./lib/spotify_remote_server');

io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('log level', 1);

app.configure(function() {
  app.set('port', process.env.PORT || 3000);
  app.use(express.favicon());
  app.use(express.logger('dev'));
  app.use(express.static(path.join(__dirname, 'public')));
});

app.configure('development', function() {
  app.use(express.errorHandler());
});

app.get('/', function(req, res) {
  res.sendfile(__dirname + '/public/index.html');
});

server.listen(app.get('port'), function() {
  console.log('Your spotify remote is awaiting commands on: http://localhost:' + app.get('port'));
});

new SpotifyRemoteServer(io, spotify);

Remove router, we just have ONE GET, nothing more.


/// <reference path="typings/node/node.d.ts" />
/// <reference path="typings/express/express.d.ts" />

var express = require('express');
var app = express();

var colors = [ "red", "yellow", "green" ];

var data = {

	color: colors[0],
	delay: 200
};

var chooseColor = function() {

	// Don't show the same color twice to make it obvious that something
	// is changing
	var filteredColors = colors.filter(function(x) { return x !== data.color; });

	data.color = filteredColors[Math.floor(Math.random() * filteredColors.length)];
	data.delay = Math.floor(Math.random() * 1900 + 100);

	console.log(data);
};

setInterval(chooseColor, 10000);

app.get('/', function(req, res) {
	res.json(data);
});

var server = app.listen(3000, function() {
	console.log('Up and running at http://%s:%s',
		server.address().address,
		server.address().port);
});

Add references to node and express typings grabbed with grab-typings (thanks bengreenier!)


var http = require('http')
  , server = http.createServer().listen(8005)
  , io = require('socket.io')(server)
  , nsp = io.of('/socket.io')
  , peopleManager = require('./utils/peopleManager');

nsp.on('connection', function (socket) {
  socket.on('client', function (data) {
    socket.broadcast.emit('server', data);
  });

  socket.on('identify', function(username) {
    peopleManager.identify(nsp, socket, username);
  });

  socket.on('disconnect', function () {
    peopleManager.disconnect(nsp, socket);
  });

  socket.on('startViewingCase', function(caseref) {
    peopleManager.startViewingCase(nsp, socket, caseref);
  });

  socket.on('stopViewingCase', function(caseref) {
    peopleManager.stopViewingCase(nsp, socket, caseref);
  });
});

server.addListener('request', function (req, res) {
  res.writeHead(200, {'Content-Type': 'application/json'});
  res.end('{"status": "OK"}\n');
});

var http = require('http')
  , server = http.createServer().listen(8005)
  , io = require('socket.io')(server)
  , nsp = io.of('/socket.io')
  , peopleManager = require('./utils/peopleManager');

nsp.on('connection', function (socket) {
  socket.on('client', function (data) {
    socket.broadcast.emit('server', data);
  });

  socket.on('identify', function(username) {
    peopleManager.identify(nsp, socket, username);
  });

  socket.on('disconnect', function () {
    peopleManager.disconnect(nsp, socket);
  });

  socket.on('startViewingCase', function(caseref) {
    peopleManager.startViewingCase(nsp, socket, caseref);
  });

  socket.on('stopViewingCase', function(caseref) {
    peopleManager.stopViewingCase(nsp, socket, caseref);
  });
});

// server.addListener('request', function (req, res) {
//   res.writeHead(200, {'Content-Type': 'application/json'});
//   res.end('{"status": "OK"}\n');
// });

Disable socket server listener for now


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

const lexicon = [];
{
  const directory = path.join(__dirname, 'lexicon');
  fs.readdirSync(directory).forEach(function(file) {
    const entry = require(path.join(directory, file));
    lexicon.push(entry);
  });
}

const parse = function parse(message, reply) {
  if (!message || !message.text) return;

  const [ ,,input ] = message.text.match(/^lex(icon)?\s(.+)/) || [];
  if (input === undefined) return;

  lexicon.forEach(function(entry) {
    const match = input.match(new RegExp('^' + entry.pattern, 'i'));
    if (match) entry.reply(message, match, reply);
  });
};

module.exports = { parse };

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

const lexicon = [];
{
  const directory = path.join(__dirname, 'lexicon');
  fs.readdirSync(directory).forEach(function(file) {
    const entry = require(path.join(directory, file));
    lexicon.push(entry);
  });
}

const parse = function parse(message, reply) {
  if (!message || !message.text) return;

  let [ prefix,,,input ] = message.text.match(/^lex(icon)?(\s(.+)|\s$|$)/) || [];
  if (!prefix) return;
  if (!input) input = 'help';

  lexicon.forEach(function(entry) {
    if (!entry.pattern) return true;
    const match = input.match(new RegExp('^' + entry.pattern, 'i'));
    if (match) entry.reply(message, match, reply);
  });
};

module.exports = { parse };

Fix help message when command is empty


(function(window){
    window.ajax = function(url, options) {
        var method = options.method || 'GET',
            data = options.data || {},
            success = options.success || function(response){},
            error = options.error || function(response){},
            request = new XMLHttpRequest();

        request.open(method, url, true);
        request.setRequestHeader("X-Requested-With", "XMLHttpRequest");

        request.addEventListener("load", function(evt) {
            success(JSON.parse(request.responseText), request);
        });
        request.addEventListener("error", function(evt) {
            error(request);
        });

        if(method === 'POST') {
            request.send(data);
        }
        else {
            request.send();
        }
    };
})(window);

(function(window){
    window.ajax = function(route, options) {
        var data = options.data || {},
            success = options.success || function(response){},
            error = options.error || function(response){},
            request = new XMLHttpRequest();

        request.open(route.method, route.url, true);
        request.setRequestHeader("X-Requested-With", "XMLHttpRequest");

        request.addEventListener("load", function(evt) {
            success(JSON.parse(request.responseText), request);
        });
        request.addEventListener("error", function(evt) {
            error(request);
        });

        if(method === 'POST') {
            request.send(data);
        }
        else {
            request.send();
        }
    };
})(window);

Switch to route based request


#!/usr/bin/env node
const qr = require('qrcode-terminal')
const argv = require('minimist')(process.argv.slice(2), { string: '_' })
const generatePayload = require('./')
const target = argv._[0].replace(/-/g, '')

if (!/^(0|66)\d{9}|\d{13}$/.test(target)) {
  console.error('Invalid recipient given: expected tax id or phone number')
  process.exit(1)
}

const payload = generatePayload(target, { amount: +argv._[1] })
console.log(payload)

qr.generate(payload, { small: !!argv.small })

#!/usr/bin/env node
const qr = require('qrcode-terminal')
const argv = require('minimist')(process.argv.slice(2), { string: '_' })
const generatePayload = require('./')
const target = String(argv._[0]).replace(/-/g, '')

if (!/^(0|66)\d{9}|\d{13}$/.test(target)) {
  console.error('Invalid recipient given: expected tax id or phone number')
  process.exit(1)
}

const payload = generatePayload(target, { amount: +argv._[1] })
console.log(payload)

qr.generate(payload, { small: !!argv.small })

Fix CLI throw when less argument


module.exports = function (app, passport) {

  var authorization = require('../controllers/authorization'),
      pages = require('../controllers/pages'),
      users = require('../controllers/users'),
      auth = require('../lib/authorization');

  app.get('/', pages.index);
  app.get('/about', pages.about);
  app.get('/signup', authorization.signup);
  app.post('/signup', authorization.newLocalUser);
  app.get('/signin', authorization.signin);
  app.post('/signin', passport.authenticate('local', {
                                    successRedirect: '/',
                                    failureRedirect: '/signin',
                                    failureFlash: true })
  );
  app.get('/logout', authorization.logout);
  app.get('/activate/:string', authorization.activate);

  app.get('/auth/google', passport.authenticate('google'));
  app.get('/auth/google/return', passport.authenticate('google', { successRedirect: '/',
                                                                  failureRedirect: '/signin' }));
  app.get('/users', auth.requiresLogin, users.list);

};

module.exports = function (app, passport) {

  var authorization = require('../controllers/authorization'),
    pages = require('../controllers/pages'),
    users = require('../controllers/users'),
    auth = require('../lib/authorization');

  app.get('/', pages.index);
  app.get('/about', pages.about);
  app.get('/signup', authorization.signup);
  app.post('/signup', authorization.newLocalUser);
  app.get('/signin', authorization.signin);
  app.post('/signin', passport.authenticate('local', {
    successRedirect: '/',
    failureRedirect: '/signin',
    failureFlash: true})
    );
  app.get('/logout', authorization.logout);
  app.get('/activate/:string', authorization.activate);

  app.get('/auth/google', passport.authenticate('google'));
  app.get('/auth/google/return', passport.authenticate('google', {
    successRedirect: '/',
    failureRedirect: '/signin'}));
  app.get('/users', auth.requiresLogin, users.list);

};

Cut the over than 80 columns code


"use strict";
/* eslint new-cap: 0 */

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

var getFeatureFilePaths = require("../lib/specifications/getFeatureFilePaths");

/* GET home page. */
router.get('/', function(req, res) {
  getFeatureFilePaths('public/feature-files')
    .then(function(featureFilePaths) {
      res
        .status(200)
        .type("text/feature")
        .send(featureFilePaths.join("\n"));
    })
    .catch(function(err) {
      res
        .status(500)
        .send(err);
    })
});

module.exports = router;

"use strict";
/* eslint new-cap: 0 */

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

var getFeatureFilePaths = require("../lib/specifications/getFeatureFilePaths");

/* GET home page. */
router.get('/', function(req, res) {
  getFeatureFilePaths('public/feature-files')
    .then(function(featureFilePaths) {
      res
        .status(200)
        .send(featureFilePaths.reduce(function(previous, current) {
          // There's no school like old school.
          // Seriously, I will replace this with a templating engine once it matters.
          return previous + '
' + current + '
'
        }, ''));
    })
    .catch(function(err) {
      res
        .status(500)
        .send(err);
    })
});

module.exports = router;

Return a HTML doc for the list of feature files, include link to the feature file.


module.exports = function() {
    return {
        'translation.af': JSON.stringify({
            '' : {
                'domain' : 'messages',
                'lang'   : 'af',
                'plural_forms' : 'nplurals=2; plural=(n != 1);'
            },
            'yes' : [null, 'ja'],
            'no' : [null, 'nee'],
            'yes?' : [null, 'ja?'],
            'no!' : [null, 'nee!'],
            'hello': [null, 'hallo'],
            'hello?': [null, 'hallo?'],
            'goodbye': [null, 'totsiens']
        }),
        'translation.jp': JSON.stringify({
            '' : {
                'domain' : 'messages',
                'lang'   : 'af',
                'plural_forms' : 'nplurals=2; plural=(n != 1);'
            },
            'yes' : [null, 'hai'],
            'no' : [null, 'iie']
        }),
        config: JSON.stringify({
            lerp: 'larp',
            metric_store: 'luke_the_store'
        }),
        foo: JSON.stringify({bar: 'baz'})
    };
};

module.exports = function() {
    return {
        'translation.af': JSON.stringify({
            '' : {
                'domain' : 'messages',
                'lang'   : 'af',
                'plural_forms' : 'nplurals=2; plural=(n != 1);'
            },
            'yes' : [null, 'ja'],
            'no' : [null, 'nee'],
            'yes?' : [null, 'ja?'],
            'no!' : [null, 'nee!'],
            'hello': [null, 'hallo'],
            'hello?': [null, 'hallo?'],
            'goodbye': [null, 'totsiens']
        }),
        'translation.jp': JSON.stringify({
            '' : {
                'domain' : 'messages',
                'lang'   : 'af',
                'plural_forms' : 'nplurals=2; plural=(n != 1);'
            },
            'yes' : [null, 'hai'],
            'no' : [null, 'iie']
        }),
        config: JSON.stringify({
            name: 'anakin_the_app',
            lerp: 'larp',
            metric_store: 'luke_the_store'
        }),
        foo: JSON.stringify({bar: 'baz'})
    };
};

Add name config property to the simple config fixture


define([
    "src/schema"
], function(Schema) {
    var _ = codebox.require("hr/utils");
    var hr = codebox.require("hr/hr");
    var File = codebox.require("models/file");

    var Manager = hr.Class.extend({
        initialize: function() {
            Manager.__super__.initialize.apply(this, arguments);

            this.schemas = new (hr.Collection.extend({ model: Schema }));
        },

        // Add/Get a schema
        schema: function(id, infos) {
            var that = this;

            if (!infos) return this.schemas.get(id);

            this.schemas.add({
                'id': id,
                'schema': infos
            });

            return this.schema(id);
        },

        // Export
        exportJson: function() {
            var that = this;
            return _.object(
                this.schemas.map(function(schema) {
                    return [
                        schema.id,
                        schema.getData()
                    ];
                })
            );
        },

        // Import
        importJSON: function(data) {
            this.schemas.each(function(schema) {
                schama.data.set(data[schema.id] || {});
            });
        },

        // Get file
        getFile: function() {
            // Generate the string content
            var code = JSON.stringify(this.exportJson(), null, 4);

            // Build the file buffer
            var f = File.buffer("Codebox Settings.json", code, "codebox-settings.json");

            // Handle write operations
            this.listenTo(f, "write", function(data) {
                this.importJSON(JSON.parse(data));
            });

            return f;
        }
    });

    return Manager;
});

define([
    "src/schema"
], function(Schema) {
    var _ = codebox.require("hr/utils");
    var hr = codebox.require("hr/hr");
    var File = codebox.require("models/file");

    var Manager = hr.Class.extend({
        initialize: function() {
            Manager.__super__.initialize.apply(this, arguments);

            this.schemas = new (hr.Collection.extend({ model: Schema }));
        },

        // Add/Get a schema
        schema: function(id, infos) {
            var that = this;

            if (!infos) return this.schemas.get(id);

            this.schemas.add({
                'id': id,
                'schema': infos
            });

            return this.schema(id);
        },

        // Export
        exportJson: function() {
            var that = this;
            return _.object(
                this.schemas.map(function(schema) {
                    return [
                        schema.id,
                        schema.getData()
                    ];
                })
            );
        },

        // Import
        importJSON: function(data) {
            this.schemas.each(function(schema) {
                schema.data.set(data[schema.id] || {});
            });
        },

        // Get file
        getFile: function() {
            // Generate the string content
            var code = JSON.stringify(this.exportJson(), null, 4);

            // Build the file buffer
            var f = File.buffer("Codebox Settings.json", code, "codebox-settings.json");

            // Handle write operations
            this.listenTo(f, "write", function(data) {
                this.importJSON(JSON.parse(data));
            });

            return f;
        }
    });

    return Manager;
});

Fix import of json in settings


var app = app || {};

// Todo項目のビュー

// Todo項目を表すDOM要素
app.TodoView = Backbone.View.extend({

  tagName: 'li',

  template: _.template($('#item-template').html()),

  events: {
    'dblclick label': 'edit',
    'keypress .edit': 'updateOnEnter',
    'blur .edit': 'close'
  },

  // モデルに対する変化を監視して再描画。TodoとTodoViewは
  // 一対一対応しているため、ここではモデルを直接参照している
  initialize: function () {
    this.listenTo(this.model, 'change', this.render);
  },

  // 項目のタイトルを描画
  render: function () {
    this.$el.html(this.template(this.model.toJSON()));
    this.$input = this.$('.edit');
    return this;
  },

  // 編集モードに移行し、入力フィールドを表示
  edit: function () {
    this.$el.addClass('editing');
    this.$input.focus();
  },

  // 編集モードを終了し、Todo項目を保存
  close: function () {
    var value = this.$input.val().trim();

    if (value) {
      this.model.save({ title: value });
    }

    this.$el.removeClass('editing');
  },

  // Enterキーが押されると編集モードを終了
  updateOnEnter: function (event) {
    if (event.which === ENTER_KEY) {
      this.close();
    }
  }
});

Add a one-to-one corresponding view in model.


// js/directives/nw-category-select.directive

(function() {
  "use strict";

  angular.module("NoteWrangler")
    .directive("nwCategorySelect", nwCategorySelectDirective);

  function nwCategorySelectDirective() {
    return {
      replace: true,
      restrict: "E",
      templateUrl: "../templates/directives/nw-category-select.directive.html",
      scope: {
        notes: "="
      },
      link: (scope, element, attrs, nwCategorySelectCtrl) => {
        scope.categories = nwCategorySelectCtrl.query();
      },
      controller: "nwCategorySelectController",
      controllerAs: "nwCategorySelectCtrl"
    };
  }
})();

// js/directives/nw-category-select.directive

(function() {
  "use strict";

  angular.module("NoteWrangler")
    .directive("nwCategorySelect", nwCategorySelectDirective);

  function nwCategorySelectDirective() {
    return {
      replace: true,
      restrict: "E",
      templateUrl: "../templates/directives/nw-category-select.directive.html",
      scope: {
        notes: "=",
        activeCategory: "="
      },
      link: (scope, element, attrs, nwCategorySelectCtrl) => {
        scope.categories = nwCategorySelectCtrl.query();
      },
      controller: "nwCategorySelectController",
      controllerAs: "nwCategorySelectCtrl"
    };
  }
})();

Add to Directive scope activeCategory value


//Square It
"use strict";
//Declare and assign the arrow function to accept one argument
let SQ = (nbr) => {
  //Set the input variable locally within the function
  var nbr = prompt("Please enter an integer ...")
  /* where nbr = any whole integer */
  //Assign the calculation to a local variable
  var sq = nbr * nbr;
  /* where sq = square of the number */
  //Alert the result to the end-user
  window.alert("The square of the number " ➡
  + nbr + " given is " + sq);
  //Return and archive the result at the console
  return("The square of the input " + nbr + " = " + sq);
};

//The execution command for the SQ function
SQ();
/* Notice the open argument accepts the prompt nbr */

//Square It
"use strict";
//Declare and assign the arrow function to accept one argument
let SQ = (nbr) => {
  //Set the input variable locally within the function
  var nbr = prompt("Please enter an integer ...")
  /* where nbr = any whole integer */
  //Assign the calculation to a local variable
  var sq = nbr * nbr;
  /* where sq = square of the number */
  //Alert the result to the end-user
  window.alert("The square of the number " + nbr + " given is " + sq);
  //Return and archive the result at the console
  return("The square of the input " + nbr + " = " + sq);
};

//The execution command for the SQ function
SQ();
/* Notice the open argument accepts the prompt nbr */

Remove illegal character ( right arrow ) from (.js)


(function(){
  $.ajax({
    url: 'evanxd/sensors',
  })
  .done(function(sensors) {
    var sensorList = $('#sensor-list ul');
    var html = '';
    sensors.forEach(function(sensor) {
      var html = '
' +
                   '
' +
                     sensor.name + 'info' +
                   '
' +
                 '
';
      sensorList.append(html);
    });
  })
  .fail(function(error) {
    console.error(error);
  })
})();

(function(){
  $.ajax({
    url: 'users/evanxd/sensors',
  })
  .done(function(sensors) {
    var sensorList = $('#sensor-list ul');
    var html = '';
    sensors.forEach(function(sensor) {
      var html = '
' +
                   '
' +
                     sensor.name + 'info' +
                   '
' +
                 '
';
      sensorList.append(html);
    });
  })
  .fail(function(error) {
    console.error(error);
  })
})();

Update API path of geting sensors


// @flow

export const union = require('./shapely/interfaceFunctions/union').default;
export const any = require('./shapely/interfaceFunctions/any').default;
export const nil = require('./shapely/interfaceFunctions/nil').default;
export const mapOf = require('./shapely/interfaceFunctions/mapOf').default;
export const arrayOf = require('./shapely/interfaceFunctions/arrayOf').default;
export const record = require('./shapely/interfaceFunctions/record').default;
export const optional = require('./shapely/interfaceFunctions/optional').default;
export const validate = require('./shapely/interfaceFunctions/validate').default;
export const deferred = require('./shapely/interfaceFunctions/deferred').default;
export const createValidator = require('./shapely/createValidator').default;
export const isValid = require('./shapely/interfaceFunctions/isValid').default;

// @flow

export union from './shapely/interfaceFunctions/union';
export any from './shapely/interfaceFunctions/any';
export nil from './shapely/interfaceFunctions/nil';
export mapOf from './shapely/interfaceFunctions/mapOf';
export arrayOf from './shapely/interfaceFunctions/arrayOf';
export record from './shapely/interfaceFunctions/record';
export optional from './shapely/interfaceFunctions/optional';
export validate from './shapely/interfaceFunctions/validate';
export deferred from './shapely/interfaceFunctions/deferred';
export createValidator from './shapely/createValidator';
export isValid from './shapely/interfaceFunctions/isValid';

Use of export...from instead of


import initOpbeat from 'opbeat-react';
import 'opbeat-react/router';

let opbeat_app_id = process.env.REACT_APP_OPBEAT_APP_ID;
let opbeat_org_id = process.env.REACT_APP_OPBEAT_ORG_ID;

if(process.env.NODE_ENV === 'production' && opbeat_app_id && opbeat_org_id) {
    initOpbeat({
        appId: opbeat_app_id,
        orgId: opbeat_org_id,
    });
}

import React from 'react';
import ReactDOM from 'react-dom';
import { browserHistory } from 'react-router';
import { Provider } from 'react-redux';

import configureStore from './store/configureStore';
import Routes from './routes';

const store = configureStore();

import './index.css';
import './semantic-ui/semantic.min.css';

ReactDOM.render(
  <Provider store={store}>
    <Routes history={browserHistory} />
  </Provider>,
  document.getElementById('root')
);

import initOpbeat from 'opbeat-react';
import 'opbeat-react/router';

let opbeat_app_id = process.env.REACT_APP_OPBEAT_APP_ID;
let opbeat_org_id = process.env.REACT_APP_OPBEAT_ORG_ID;

if(process.env.NODE_ENV === 'production' && opbeat_app_id && opbeat_org_id) {
    initOpbeat({
        appId: opbeat_app_id,
        orgId: opbeat_org_id,
        performance: {
            'initial-page-load': true
        },
    });
}

import React from 'react';
import ReactDOM from 'react-dom';
import { browserHistory } from 'react-router';
import { Provider } from 'react-redux';

import configureStore from './store/configureStore';
import Routes from './routes';

const store = configureStore();

import './index.css';
import './semantic-ui/semantic.min.css';

ReactDOM.render(
  <Provider store={store}>
    <Routes history={browserHistory} />
  </Provider>,
  document.getElementById('root')
);

Add Opbeat performance flag for client


/* eslint-env node, jest */
const { partition, range } = require('iter-tools')

describe('partition', function () {
  describe('evens and odds', function () {
    const isEven = n => n % 2 === 0

    it('empty iterable', function () {
      const [evens, odds] = partition(isEven, [])

      expect([
        Array.from(evens),
        Array.from(odds)
      ]).toEqual([[], []])
    })

    it('range(10)', function () {
      const [evens, odds] = partition(isEven, range(10))

      expect([
        Array.from(evens),
        Array.from(odds)
      ]).toEqual([
        [0, 2, 4, 6, 8],
        [1, 3, 5, 7, 9]
      ])
    })

    it('calls func once for each item', function () {
      const func = jest.fn(isEven)
      const [evens, odds] = partition(func, range(10))
      Array.from(evens)
      Array.from(odds)
      expect(func.mock.calls).toEqual(
        Array.from(range(10)).map(x => [x])
      )
    })
  })
})

/* eslint-env node, jest */
const { partition, range, zip } = require('iter-tools')

describe('partition', function () {
  describe('evens and odds', function () {
    const isEven = n => n % 2 === 0

    it('empty iterable', function () {
      const [evens, odds] = partition(isEven, [])

      expect([
        Array.from(evens),
        Array.from(odds)
      ]).toEqual([[], []])
    })

    it('range(10)', function () {
      const [evens, odds] = partition(isEven, range(10))

      expect([
        Array.from(evens),
        Array.from(odds)
      ]).toEqual([
        [0, 2, 4, 6, 8],
        [1, 3, 5, 7, 9]
      ])
    })

    it('calls func once for each item', function () {
      const func = jest.fn(isEven)
      const [evens, odds] = partition(func, range(10))
      Array.from(evens)
      Array.from(odds)
      expect(func.mock.calls).toEqual(
        Array.from(range(10)).map(x => [x])
      )
    })

    it('iterate both evens and odds at the same time', function () {
      const [evens, odds] = partition(isEven, range(10))
      const zipped = Array.from(zip(evens, odds))
      expect(zipped).toEqual([
        [0, 1],
        [2, 3],
        [4, 5],
        [6, 7],
        [8, 9]
      ])
    })
  })
})

Test if it works with zip


global._noQUnitBridge = true;

import "./main";
import { start } from "QUnit";
import nwGui from "nw.gui";

const nwWindow = nwGui.Window.get();

nwWindow.show();
nwWindow.showDevTools();

start();

global._noQUnitBridge = true;

import "./main";
import { start } from "qunit";
import nwGui from "nw.gui";

const nwWindow = nwGui.Window.get();

nwWindow.show();
nwWindow.showDevTools();

start();

Fix old qunit import name in test-dev


/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */

require('dotenv').config();

const testUrl = 'http://localhost:3000/tests.html';

module.exports = (grunt) => {
  const browsers = [
    {
      browserName: 'googlechrome',
      platform: 'WIN10'
    },
    {
      browserName: 'firefox',
      platform: 'linux'
    }
  ];

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    connect: {
      server: {
        options: {
          base: '',
          port: 9999
        }
      }
    },

    'saucelabs-mocha': {
      all: {
        options: {
          urls: [
            testUrl
          ],
          browsers,
          build: process.env.TRAVIS_JOB_ID,
          testname: 'mocha tests',
          throttled: 1,
          sauceConfig: {
            'video-upload-on-pass': false
          }
        }
      }
    },
    watch: {}
  });

  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-saucelabs');

  grunt.registerTask('sauce', ['connect', 'saucelabs-mocha']);
};

/* eslint import/no-extraneous-dependencies: ["error", {"devDependencies": true}] */

require('dotenv').config();

const testUrl = 'http://localhost:3000/tests.html';

module.exports = (grunt) => {
  const browsers = [
    {
      browserName: 'safari',
      platform: 'macOS 10.12',
    },
    {
      browserName: 'safari',
      platform: 'OS X 10.8',
      version: '6.0'
    },
    {
      browserName: 'internet explorer',
      platform: 'Windows 7',
      version: '9.0'
    },
    {
      browserName: 'internet explorer',
      platform: 'Windows 7',
      version: '11.0'
    },
    {
      browserName: 'microsoftedge',
      platform: 'Windows 10'
    },
    {
      browserName: 'googlechrome',
      platform: 'Windows 10'
    },
    {
      browserName: 'firefox',
      platform: 'linux'
    },
  ];

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    connect: {
      server: {
        options: {
          base: '',
          port: 9999
        }
      }
    },

    'saucelabs-mocha': {
      all: {
        options: {
          urls: [
            testUrl
          ],
          browsers,
          build: process.env.TRAVIS_JOB_ID,
          testname: 'js-set-functions mocha tests',
          throttled: 5,
          sauceConfig: {
            'video-upload-on-pass': false
          }
        }
      }
    },
    watch: {}
  });

  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-saucelabs');

  grunt.registerTask('sauce', ['connect', 'saucelabs-mocha']);
};

Add more desktop browsers to list of browsers to test


'use strict';

module.exports = function (grunt) {
  grunt.initConfig({

    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        '.jshintrc',
        'package.json',
        '**/*.js',
        '!node_modules/**/*',
        '!test/**/*',
        '!static/**/*'
      ]
    },

    mochacov: {
      unit: {
        options: {
          reporter: 'spec'
        }
      },
      coverage: {
        options: {
          reporter: 'mocha-term-cov-reporter',
          coverage: true
        }
      },
      coveralls: {
        options: {
          coveralls: true
        }
      },
      options: {
        files: 'test/**/*.js',
        ui: 'bdd',
        colors: true
      }
    }

  });

  grunt.loadNpmTasks('grunt-mocha-cov');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('test', ['jshint', 'mochacov:unit', 'mochacov:coverage']);
  grunt.registerTask('travis', ['jshint', 'mochacov:unit', 'mochacov:coverage', 'mochacov:coveralls']);
  grunt.registerTask('default', 'test');

};

'use strict';

module.exports = function (grunt) {
  grunt.initConfig({

    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        '.jshintrc',
        'package.json',
        '**/*.js',
        '!node_modules/**/*',
        '!test/**/*',
        '!static/**/*'
      ]
    },

    mochacov: {
      unit: {
        options: {
          reporter: 'spec'
        }
      },
      coverage: {
        options: {
          reporter: 'mocha-term-cov-reporter',
          coverage: true
        }
      },
      coveralls: {
        options: {
          coveralls: true
        }
      },
      options: {
        files: 'test/**/*.js',
        ui: 'bdd',
        colors: true
      }
    }

  });

  grunt.loadNpmTasks('grunt-mocha-cov');
  grunt.loadNpmTasks('grunt-contrib-jshint');

  grunt.registerTask('test', ['jshint', 'mochacov:unit']);
  grunt.registerTask('travis', ['jshint', 'mochacov:unit', 'mochacov:coveralls']);
  grunt.registerTask('default', 'test');

};

Remove coverage for now (its getting stuck)


module.exports = function (grunt) {

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		clean: {
			build: {
				src: "build"
			}
		},

		copy: {
			build: {
				files: [
					{
						expand: true,
						cwd: 'source/',
						src: ['pixadee.js'],
						dest: 'build/'
					}
				]
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');

	grunt.registerTask('build', ['clean', 'copy']);

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

module.exports = function (grunt) {

	grunt.initConfig({

		pkg: grunt.file.readJSON('package.json'),

		clean: {
			build: {
				src: "build"
			}
		},

		copy: {
			build: {
				files: [
					{
						expand: true,
						cwd: 'source/',
						src: ['pixadee.js'],
						dest: 'build/'
					}
				]
			}
		},

		uglify: {
			build: {
				files: {
					'build/pixadee.min.js': ['source/pixadee.js']
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-uglify');

	grunt.registerTask('build', ['clean', 'copy']);

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

Add a Grunt task to produce a minified version of pixadee.js.


import * as most from 'most';
import { curryN } from 'ramda';

export const curry2 = r.curryN(2);

export const mfilterc = r.curry2(most.filter);
export const mmapc = r.curry2(most.map);

import * as most from 'most';
import { curryN } from 'ramda';

export const curry2 = r.curryN(2);

export const mfilterc = curry2(most.filter);
export const mmapc = curry2(most.map);

Correct function used to curry.


var SetOperatorNode = require("../SetOperatorNode.js");

module.exports = (function () {

	var o = function (graph) {
		SetOperatorNode.apply(this, arguments);

		var that = this;

		this.styleClass("intersectionof")
			.type("owl:intersectionOf");

		this.drawNode = function (element) {
			that.nodeElement(element);

			element.append("circle")
				.attr("class", that.type())
				.classed("class", true)
				.classed("special", true)
				.attr("r", that.actualRadius());

			var symbol = element.append("g").classed("embedded", true);

			symbol.append("circle")
				.attr("class", "symbol")
				.classed("fineline", true)
				.attr("r", (that.radius() - 15));
			symbol.append("path")
				.attr("class", "nofill")
				.attr("d", "m -7,-1.5 12,0 0,6");

			symbol.attr("transform", "translate(-" + (that.radius() - 15) / 100 + ",-" + (that.radius() - 15) / 100 + ")");

			that.postDrawActions();
		};
	};
	o.prototype = Object.create(SetOperatorNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

var SetOperatorNode = require("../SetOperatorNode.js");

module.exports = (function () {

	var o = function (graph) {
		SetOperatorNode.apply(this, arguments);

		var that = this;

		this.styleClass("complementof")
			.type("owl:complementOf");

		this.drawNode = function (element) {
			that.nodeElement(element);

			element.append("circle")
				.attr("class", that.type())
				.classed("class", true)
				.classed("special", true)
				.attr("r", that.actualRadius());

			var symbol = element.append("g").classed("embedded", true);

			symbol.append("circle")
				.attr("class", "symbol")
				.classed("fineline", true)
				.attr("r", (that.radius() - 15));
			symbol.append("path")
				.attr("class", "nofill")
				.attr("d", "m -7,-1.5 12,0 0,6");

			symbol.attr("transform", "translate(-" + (that.radius() - 15) / 100 + ",-" + (that.radius() - 15) / 100 + ")");

			that.postDrawActions();
		};
	};
	o.prototype = Object.create(SetOperatorNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

Fix type of complement of


import React, {PropTypes} from 'react'

export default function FallbackPreviewComponent(props) {
  return (

{JSON.stringify(props.value, null, 2)}

  )
}

FallbackPreviewComponent.propTypes = {
  value: PropTypes.any.isRequired,
  field: PropTypes.object.isRequired,
  type: PropTypes.object.isRequired
}

import React, {PropTypes} from 'react'
import {resolveJSType} from "../../types/utils";

function renderPrimitive(value) {
  return value
}

const GUESS_PROPERTIES = 'title,name,label'.split(',')
function renderObject(value) {
  const objectProperties = Object.keys(value)
  const displayProperty = objectProperties.find(key => GUESS_PROPERTIES.includes(key))
  if (displayProperty) {
    return value[displayProperty]
  }
  return objectProperties
    .filter(key => !key.startsWith('$'))
    .slice(2)
    .map(key => {
      return `${key}: ${render(value[key])}`
    })
}

function renderArray(array) {
  return array.map(render).join(', ')
}

function render(value) {
  if (resolveJSType(value.serialize) === 'function') {
    return render(value.serialize())
  }
  const type = resolveJSType(value)
  if (type === 'object') {
    return renderObject(value)
  }
  if (type === 'array') {
    return renderArray(value)
  }
  return renderPrimitive(value)
}

export default function FallbackPreviewComponent(props) {
  return (
    <div>
      {render(props.value)}
    </div>
  )
}

FallbackPreviewComponent.propTypes = {
  value: PropTypes.any.isRequired,
  field: PropTypes.object.isRequired,
  type: PropTypes.object.isRequired
}

Add heuristics to fallback preview component


var _ = require('lodash');

module.exports = function($templateRequest, $compile, $interpolate) {

    typeCounts = {};

    return {
        restrict: 'E',
        link: function($scope, $element, $attrs) {
            var type = $scope.type,
                newScope = $scope.$new();

            var templates = [
                '/templates/' + $attrs.type + '.html',
                '/templates/' + $attrs.type + '-' + $attrs.id + '.html'
            ];

            newScope.$watch($attrs.data, function(data) {
                _.merge(newScope, data);
            });

            typeCounts[type] = typeCounts[type] || 0

            function tryToLoadNextTemplate() {
                $templateRequest(templates.pop(), true).then(function(template) {
                    $element.append($compile(template)(newScope));
                }, function(response) {
                    if (templates.length === 0) {
                        throw new Error('No template could be loaded for widget ' + $attrs.type);
                    }
                    tryToLoadNextTemplate();
                });
            };

            tryToLoadNextTemplate();
        }
    }
}

var _ = require('lodash');

module.exports = function($templateRequest, $compile, $interpolate) {

    typeCounts = {};

    return {
        restrict: 'E',
        link: function($scope, $element, $attrs) {
            var type = $scope.type,
                newScope = $scope.$new();

            var templates = [
                '/templates/' + $attrs.type + '.html',
                '/templates/' + $attrs.type + '-' + $attrs.id + '.html'
            ];

            newScope.$watch($attrs.data, function(data) {
                _.extend(newScope, data);
            });

            typeCounts[type] = typeCounts[type] || 0

            function tryToLoadNextTemplate() {
                $templateRequest(templates.pop(), true).then(function(template) {
                    $element.append($compile(template)(newScope));
                }, function(response) {
                    if (templates.length === 0) {
                        throw new Error('No template could be loaded for widget ' + $attrs.type);
                    }
                    tryToLoadNextTemplate();
                });
            };

            tryToLoadNextTemplate();
        }
    }
}

Fix bug where list rows are not cleaned up


/*
  Control.Zoom.debug.js
  This is wrapping the L.Control.Zoom class with .debug

	(c) 2013, Aaron Racicot, Z-Pulley Inc.
*/
'use strict';

var ControlZoomDebug = L.Class.extend({
    // The name of the class being wrapped with a debug
    _className: "L.Control.Zoom",
    _controlZoom: null,
    _map: null,
    initialize: function(controlZoom) {
        this._map = controlZoom._map;
        this._controlZoom = controlZoom;
    },
    dumpOptions: function() {
        for (var key in this.options) {
            console.log(key + " - " + this.options[key]);
        }
        return Object.keys(this.options).length;
    }
});

// This is the generic hook into the testing system for this
// object type.
module.exports = function() {
    L.Control.Zoom.addInitHook(function () {
        L.debug.add(this);
        this.debug = new ControlZoomDebug(this);
    });
    return [{className:"L.Control.Zoom",classRef:L.Control.Zoom}];
};

/*
  Control.Zoom.debug.js
  This is wrapping the L.Control.Zoom class with .debug

	(c) 2013, Aaron Racicot, Z-Pulley Inc.
*/
'use strict';

var ControlZoomDebug = L.Class.extend({
    // The name of the class being wrapped with a debug
    _className: "L.Control.Zoom",
    _controlZoom: null,
    _map: null,
    initialize: function(controlZoom) {
        this._map = controlZoom._map;
        this._controlZoom = controlZoom;
    },
    dumpOptions: function() {
        for (var key in this._controlZoom.options) {
            console.log(key + " - " + this._controlZoom.options[key]);
        }
        return Object.keys(this._controlZoom.options).length;
    }
});

// This is the generic hook into the testing system for this
// object type.
module.exports = function() {
    L.Control.Zoom.addInitHook(function () {
        L.debug.add(this);
        this.debug = new ControlZoomDebug(this);
    });
    return [{className:"L.Control.Zoom",classRef:L.Control.Zoom}];
};

Fix up the dump options for Control.Zoom


/*
 * Author: CM
 */

(function(global) {

  /**
   * @callback PromiseThrottled
   * @param {...Object|String|Number} any number of optional params
   * @return {Promise}
   */

  /**
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running.
   * @returns {PromiseThrottled}
   */
  function promiseThrottler(fn, options) {
    options = _.defaults(options || {}, {cancel: false});
    var promise;

    return function() {
      if (options.cancel && promise && promise.isPending() && promise.isCancellable()) {
        promise.cancel();
        promise = null;
      }
      if (!promise || !promise.isPending()) {
        promise = fn.apply(null, arguments);
      }
      return promise;
    };
  }

  var throttlersStorage = {};

  /**
   * @param {String} namespace
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running
   * @returns {Promise}
   */
  function throttle(namespace, fn, options) {
    if (!throttlersStorage[namespace]) {
      throttlersStorage[namespace] = throttleFunction(fn, options);

    }
    return throttlersStorage[namespace]();
  }

  global.throttleFunction = throttleFunction;
  global.throttle = throttle;

  // temporary backward compatibility
  global.promiseThrottler = throttleFunction;

})(window);

/*
 * Author: CM
 */

(function(global) {

  /**
   * @param {PromiseThrottled} fn
   * @param {Object|null} [options]
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running.
   * @returns {PromiseThrottled}
   */
  function promiseThrottler(fn, options) {
    options = _.defaults(options || {}, {cancel: false});
    if (options.key) {
      return namespaceThrottler(options.key, fn, options);
    } else {
      return nonameThrottler(fn, options);
    }
  }

  /**
   * @see promiseThrottler
   */
  function nonameThrottler(fn, options) {
    var promise;

    return function() {
      if (options.cancel && promise && promise.isPending() && promise.isCancellable()) {
        promise.cancel();
        promise = null;
      }
      if (!promise || !promise.isPending()) {
        promise = fn.apply(null, arguments);
      }
      return promise;
    };
  }

  var storage = {};

  /**
   * @param {String} namespace
   * @param {PromiseThrottled} fn
   * @param {Object|null} options
   * @param {Boolean} options.cancel Whether to cancel the previous promise if it is still running
   * @returns {Promise}
   */
  function namespaceThrottler(namespace, fn, options) {
    if (!storage[namespace]) {
      storage[namespace] = nonameThrottler(fn, options);
    }
    return storage[namespace];
  }

  global.promiseThrottler = promiseThrottler;

})(window);

Unify promiseThrottler. Add 'key' to options.


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

function insertLinksIntoHead({html, links=[]}) {
  if (links.length === 0) {
    return html;
  }

  if (html.includes('')) {
    // If a valid closing  is found, insert the new <link>s right before it.
    return html.replace('', links.join('\n') + '\n');
  }

  if (html.includes('')) {
    // If there's a  but no , create a  containing the .
    return html.replace('', `<head>\n${links.join('\n')}\n</head>\n<body>`);
  }

  throw new Error(`The HTML provided did not contain a </head> or a <body>:\n\n${html}`);
}

module.exports = insertLinksIntoHead;

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

function insertLinksIntoHead({html, links=[]}) {
  if (links.length === 0) {
    return html;
  }

  if (html.includes('')) {
    // If a valid closing  is found, insert the new <link>s right before it.
    return html.replace('', links.join('') + '');
  }

  if (html.includes('')) {
    // If there's a  but no , create a  containing the .
    return html.replace('', `<head>${links.join('')}\n</head><body>`);
  }

  throw new Error(`The HTML provided did not contain a </head> or a <body>:\n\n${html}`);
}

module.exports = insertLinksIntoHead;

Remove whitespace around inserted links


import React from 'react';
import Button from '../Button';
import styles from './styles.css';

const Header = () => (

Bayes Editor

    <Button
      title="Menu"
      className={styles.menuButton}
      onClick={() => alert('menu')}
    >

    </Button>

);

export default Header;

import React from 'react';
import Button from '../Button';
import styles from './styles.css';

const Header = () => (

Bayes Editor

    <Button
      title="Menu"
      className={styles.menuButton}
      onClick={() => alert('¯\\_(ツ)_/¯')}
    >

    </Button>

);

export default Header;

Change menu 'not implemented' alert ¯\_(ツ)_/¯


var path = require("path");
var rootDir = path.join(__dirname, "../..");
var exec = require(path.join(rootDir, "./utils/execPromise"));

module.exports = function getStatus() {
  return exec("git submodule status", { cwd: rootDir})
    .then(function(stdout) {
      function getStatusPromiseFromLine(line) {
        var lineSections = line.trim().split(" ");
        var onNewCommit = !!~lineSections[0].indexOf("+");
        var needsInitialization = !!~lineSections[0].indexOf("-");
        var commitOid = lineSections[0].replace("+", "").replace("-", "");
        var name = lineSections[1];

        return exec("git status", { cwd: path.join(rootDir, name)})
          .then(function(workDirStatus) {
            return {
              commitOid: commitOid,
              onNewCommit: onNewCommit,
              name: name,
              needsInitialization: needsInitialization,
              workDirDirty: !~workDirStatus
                .trim()
                .split("\n")
                .pop()
                .indexOf("nothing to commit")
            };
          });
      }

      return Promise.all(stdout
        .trim()
        .split("\n")
        .map(getStatusPromiseFromLine)
      );
    });
};

var path = require("path");
var rootDir = path.join(__dirname, "../..");
var exec = require(path.join(rootDir, "./utils/execPromise"));

module.exports = function getStatus() {
  return exec("git submodule status", { cwd: rootDir})
    .then(function(stdout) {
      if (!stdout) {
        // In the case where we pull from npm they pre-init the submoduels for
        // us and `git submodule status` returns empty-string. In that case
        // we'll just assume that we're good.
        return Promise.resolve([]);
      }

      function getStatusPromiseFromLine(line) {
        var lineSections = line.trim().split(" ");
        var onNewCommit = !!~lineSections[0].indexOf("+");
        var needsInitialization = !!~lineSections[0].indexOf("-");
        var commitOid = lineSections[0].replace("+", "").replace("-", "");
        var name = lineSections[1];

        return exec("git status", { cwd: path.join(rootDir, name)})
          .then(function(workDirStatus) {
            return {
              commitOid: commitOid,
              onNewCommit: onNewCommit,
              name: name,
              needsInitialization: needsInitialization,
              workDirDirty: !~workDirStatus
                .trim()
                .split("\n")
                .pop()
                .indexOf("nothing to commit")
            };
          });
      }

      return Promise.all(stdout
        .trim()
        .split("\n")
        .map(getStatusPromiseFromLine)
      );
    });
};

Fix submodules for the "no-prebuilt install from npm" case


'use strict'

const createAddFactory = require('../create-add')
const { sails } = require('../../directory')
const category = require('../../category')
const carbon = require('./carbon')
const size = require('./size')
const type = require('./type')

function factory (log) {
  const createAdd = createAddFactory('mast', log)

  const addCategory = createAdd('category', (acc) => {
    return {
      data: category('masts'),
      output: acc.input
    }
  })

  const addBrand = createAdd('brand', (acc) => {
    return {
      data: acc.dir.data.brand,
      output: acc.dir.output
    }
  })

  const addType = createAdd('type', (acc) => type(acc.input))
  const addCarbon = createAdd('carbon', (acc) => carbon(acc.input))
  const addSize = createAdd('size', (acc) => size(acc.input))

  function mast (input) {
    const dir = sails(input)
    const acc = { dir, input, data: {} }

    addCategory(acc)
    addBrand(acc)
    addType(acc)
    addCarbon(acc)
    addSize(acc)

    return {data: acc.data, output: acc.input}
  }

  return mast
}

module.exports = factory

'use strict'

const createDirectoryFlow = require('../../directory/create-flow')
const { accesories, sails } = require('../../directory')
const createAddFactory = require('../create-add')
const category = require('../../category')
const carbon = require('./carbon')
const size = require('./size')
const type = require('./type')

const directory = createDirectoryFlow([sails, accesories])

function factory (log) {
  const createAdd = createAddFactory('mast', log)

  const addCategory = createAdd('category', (acc) => {
    return {
      data: category('masts'),
      output: acc.input
    }
  })

  const addBrand = createAdd('brand', (acc) => {
    return {
      data: acc.dir.data.brand,
      output: acc.dir.output
    }
  })

  const addType = createAdd('type', (acc) => type(acc.input))
  const addCarbon = createAdd('carbon', (acc) => carbon(acc.input))
  const addSize = createAdd('size', (acc) => size(acc.input))

  function mast (input) {
    const dir = directory(input)
    const acc = { dir, input, data: {} }

    addCategory(acc)
    addBrand(acc)
    addType(acc)
    addCarbon(acc)
    addSize(acc)

    return {data: acc.data, output: acc.input}
  }

  return mast
}

module.exports = factory

Enable resolve find brand from multiple directories


var locationGraph = require('../assets/data/demo-picker-data-1.json')

function isCanonicalNode (node) {
  return node.meta.canonical
}

function presentableName (node, locale) {
  var requestedName = node['names'][locale]
  var fallback = Object.values(node['names'])[0]
  return requestedName || fallback
}

var locationReverseMap = (preferredLocale) => Object.keys(locationGraph)
  .reduce((revMap, curie) => {
    var node = locationGraph[curie]
    Object.keys(node.names).forEach(locale => {
      var name = node.names[locale]
      // HACK to prevent overriding for example Antarctica,
      // where the en-GB and cy names are identical, and we want
      // en-GB to stay on top.
      var isntDefinedOrLocaleIsEnGb = !revMap[name] || locale === preferredLocale
      if (isntDefinedOrLocaleIsEnGb) {
        revMap[name] = { node, locale }
      }
    })
    return revMap
  }, {})

var canonicalLocationList = (preferredLocale) => Object.keys(locationGraph)
  .reduce((list, curie) => {
    var node = locationGraph[curie]
    return isCanonicalNode(node)
      ? list.concat([presentableName(node, preferredLocale)])
      : list
  }, [])
  .sort()

module.exports = {
  canonicalLocationList: canonicalLocationList,
  locationGraph: locationGraph,
  locationReverseMap: locationReverseMap
}

var locationGraph = require('../assets/data/demo-picker-data-1.json')

function isCanonicalNode (node) {
  return node.meta.canonical
}

function presentableName (node, locale) {
  var requestedName = node['names'][locale]
  var fallback = Object.keys(node['names']).map(k => node['names'][k])[0]
  return requestedName || fallback
}

var locationReverseMap = (preferredLocale) => Object.keys(locationGraph)
  .reduce((revMap, curie) => {
    var node = locationGraph[curie]
    Object.keys(node.names).forEach(locale => {
      var name = node.names[locale]
      // HACK to prevent overriding for example Antarctica,
      // where the en-GB and cy names are identical, and we want
      // en-GB to stay on top.
      var isntDefinedOrLocaleIsEnGb = !revMap[name] || locale === preferredLocale
      if (isntDefinedOrLocaleIsEnGb) {
        revMap[name] = { node, locale }
      }
    })
    return revMap
  }, {})

var canonicalLocationList = (preferredLocale) => Object.keys(locationGraph)
  .reduce((list, curie) => {
    var node = locationGraph[curie]
    return isCanonicalNode(node)
      ? list.concat([presentableName(node, preferredLocale)])
      : list
  }, [])
  .sort()

module.exports = {
  canonicalLocationList: canonicalLocationList,
  locationGraph: locationGraph,
  locationReverseMap: locationReverseMap
}

Fix cloudfoundry using wrong node version