// Game Controller
// A checkers board has 64 squares like a chess board but it only uses 32 squares all the same color
// Each player has 12 pieces and pieces that make until the last squares on the enemy side is promoted
// Promoted piece also moves on diagonals with no limit of squares if it is free
// The moves are on diagonal one square at a time
// To capture, the piece capturing jumps the enemy piece advancing two squares on diagonal
// The game end when one of the player lost all pieces or doesn't have moves to make
function Game() {
  /* Board.initial generate all elements used to be pieces and empty squares on the
  board and return an array of the board initial position*/
  this.board = Board.initial();
  this.playingNow = "blue";
}

Game.prototype.test = function(param){
  console.log(this.board);
}

Game.prototype.whoseTurn = function(){

}

// Game Controller
// A checkers board has 64 squares like a chess board but it only uses 32 squares all the same color
// Each player has 12 pieces and pieces that make until the last squares on the enemy side is promoted
// Promoted piece also moves on diagonals with no limit of squares if it is free
// The moves are on diagonal one square at a time
// To capture, the piece capturing jumps the enemy piece advancing two squares on diagonal
// The game end when one of the player lost all pieces or doesn't have moves to make
function Game() {
  /* Board.initial generate all elements used to be pieces and empty squares on the
  board and return an array of the board initial position*/
  this.board = Board.initial();
}

Game.prototype.flattenBoard = function(param){
  var flatBoard = this.board.reduce(
    function(a,b) {
      return a.concat(b);
    },[]
  );
  return flatBoard;
}

Game.prototype.whoseTurn = function(){

}

Create prototype to flatten board


import React, {Component, PropTypes} from 'react';

export default class Span extends Component {
  render() {
    const {children, span} = this.props;

    const style = {
      boxSizing: 'border-box',
      display: 'flex',
      flexBasis: span && window.innerWidth > 640 ?
        `calc(${span / 6 * 100}% - 10px)` :
        'calc(100% - 10px)',
      flexWrap: 'wrap',
      margin: '24px 10px 0 0',
      padding: 0,
      position: 'relative'
    };

    return (
      <div {...this.props} style={{...style, ...this.props.style}}>
        {children}
      </div>
    );
  }
}

Span.propTypes = {
  span: PropTypes.number,
  children: PropTypes.node.isRequired,
  style: PropTypes.object
};

import React, {Component, PropTypes} from 'react';

export default class Span extends Component {
  render() {
    const {children, span} = this.props;

    const style = {
      boxSizing: 'border-box',
      display: 'flex',
      flexBasis: span && window.innerWidth > 640 ?
        `calc(${span / 6 * 100}% - 10px)` :
        'calc(100% - 10px)',
      // Bug fix for Firefox; width and flexBasis don't work on horizontally scrolling code blocks
      maxWidth: span && window.innerWidth > 640 ?
        `calc(${span / 6 * 100}% - 10px)` :
        'calc(100% - 10px)',
      flexWrap: 'wrap',
      margin: '24px 10px 0 0',
      padding: 0,
      position: 'relative'
    };

    return (
      <div {...this.props} style={{...style, ...this.props.style}}>
        {children}
      </div>
    );
  }
}

Span.propTypes = {
  span: PropTypes.number,
  children: PropTypes.node.isRequired,
  style: PropTypes.object
};

Fix max width of overflowing specimens on Firefox


import { getCurrentTitle, getCurrentURL } from "./page.js";

let __sharedTracker = null;

export default class LoginTracker {
    username = "";
    password = "";
    _url = getCurrentTitle();
    _title = getCurrentTitle();

    get title() {
        return this._title;
    }

    get url() {
        return this._url;
    }
}

export function getSharedTracker() {
    if (!__sharedTracker) {
        __sharedTracker = new LoginTracker();
    }
    return __sharedTracker;
}

import { getCurrentTitle, getCurrentURL } from "./page.js";

let __sharedTracker = null;

export default class LoginTracker {
    username = "";
    password = "";
    _url = getCurrentURL();
    _title = getCurrentTitle();

    get title() {
        return this._title;
    }

    get url() {
        return this._url;
    }
}

export function getSharedTracker() {
    if (!__sharedTracker) {
        __sharedTracker = new LoginTracker();
    }
    return __sharedTracker;
}

Fix URL in login tracking


import Firebase from 'firebase'
import Vue from 'vue'
import VueRouter from 'vue-router'

import App from './App.vue'

Vue.use(VueRouter)

let router = new VueRouter({
  hashboang: false,
  history: true,
})

let MEGAKanban = Vue.extend({})

let Redirect = Vue.extend({

  ready() {
    let boardName = localStorage.getItem('MEGAKanban_board')
    if (!boardName) {
      boardName = this.randomName()
      localStorage.setItem('MEGAKanban_board', boardName)
    }
    router.go(boardName)
  },

  methods: {
    // generate board name using timestamp
    // @todo: generate memorable names
    randomName() {
      let now = new Date()
      return btoa(now)
    }
  }
})

router.map({
  '/': {
    name: 'root',
    component: Redirect
  },
  '/:board': {
    name: 'board',
    component: App
  }
})

router.start(MEGAKanban, '#main')

import Firebase from 'firebase'
import Vue from 'vue'
import VueRouter from 'vue-router'

import nonsense from './nonsense'
import App from './App.vue'

window.randomSet = nonsense.randomSet
window.randomNumber = nonsense.randomNumber

Vue.use(VueRouter)

let router = new VueRouter({
  hashboang: false,
  history: true,
})

let MEGAKanban = Vue.extend({})

let Redirect = Vue.extend({

  ready() {
    let boardName = this.randomName()
    router.go(boardName)
  },

  methods: {
    randomName() {
      return nonsense.randomSet()
        .concat(nonsense.randomNumber())
        .join('-')
    }
  }
})

router.map({
  '/': {
    name: 'root',
    component: Redirect
  },
  '/:board': {
    name: 'board',
    component: App
  }
})

router.start(MEGAKanban, '#main')

Use nonsense board name, no localStorage


'use strict';

var Mailgun = require('mailgun-js');
var packageData = require('../package.json');

module.exports = function(options) {
  return new MailgunTransport(options);
};

function MailgunTransport(options) {
  this.options = options || {};
  this.name = 'Mailgun';
  this.version = packageData.version;
}

MailgunTransport.prototype.send = function (mail, callback) {

  var mailgun = Mailgun({
    apiKey: this.options.auth.api_key,
    domain: this.options.auth.domain || ''
  });

  var data = {
    from: mail.data.from,
    to: mail.data.to,
    subject: mail.data.subject,
    text: mail.data.text
  }

  mailgun.messages().send(data,
    function (err, body) {
      if (err) {
        console.log(err);
        return callback(err);
      }
      return callback();
    }
  );

};

'use strict';

var Mailgun = require('mailgun-js');
var packageData = require('../package.json');

module.exports = function(options) {
  return new MailgunTransport(options);
};

function MailgunTransport(options) {
  this.options = options || {};
  this.name = 'Mailgun';
  this.version = packageData.version;
}

MailgunTransport.prototype.send = function (mail, callback) {

  var mailgun = Mailgun({
    apiKey: this.options.auth.api_key,
    domain: this.options.auth.domain || ''
  });

  var data = {
    from: mail.data.from,
    to: mail.data.to,
    subject: mail.data.subject,
    text: mail.data.text,
    html: mail.data.html
  }

  mailgun.messages().send(data,
    function (err, body) {
      if (err) {
        console.log(err);
        return callback(err);
      }
      return callback();
    }
  );

};

Add in support for passing through the html param


(function() {
    'use strict';

    // This is my local Docker IRC server
    var defaultHost = '192.168.99.100:6667';

    angular.module('app.factories.chat', []).
        factory('chat', Chat);

    Chat.$inject = ['$websocket', '$rootScope'];
    function Chat($websocket, $rootScope) {
        var ws = $websocket('ws://localhost:6060?server=' + defaultHost);

        $rootScope.logs = [];

        ws.onMessage(function(message) {
            console.log(message);

            var d = JSON.parse(message.data);
            $rootScope.logs.push(d);
        });

        ws.onOpen(function() {
            console.log('WebSocket opened!');
            ws.send({
                name: 'SET',
                message: defaultHost + '/#roomtest'
            });

            methods.setNick('paked');
        });

        var methods = {
            sendMessage: function(message) {
                ws.send({
                    name: 'SEND',
                    message: message,
                    channel: defaultHost + '/#roomtest'
                });
            },
            setNick: function(nick) {
                ws.send({
                    name: 'NICK',
                    message: nick
                });
            }
        };

        return methods;
    }
})();

(function() {
    'use strict';

    // This is my local Docker IRC server
    var defaultHost = '192.168.99.100:6667';

    angular.module('app.factories.chat', []).
        factory('chat', Chat);

    Chat.$inject = ['$websocket', '$rootScope'];
    function Chat($websocket, $rootScope) {
        var ws = $websocket('ws://localhost:6060?server=' + defaultHost);

        $rootScope.logs = [];

        ws.onMessage(function(message) {
            console.log(message);

            var d = JSON.parse(message.data);
            $rootScope.logs.push(d);
        });

        ws.onOpen(function() {
            console.log('WebSocket opened!');
            ws.send({
                name: 'SET',
                message: defaultHost + '/#roomtest'
            });

            methods.setNick('paked');
        });

        var methods = {
            sendMessage: function(message) {
                ws.send({
                    name: 'SEND',
                    message: message,
                    channel: defaultHost + '/#roomtest'
                });
            },
            setNick: function(nick) {
                ws.send({
                    name: 'NICK',
                    message: nick
                });
            },
            _send: function(obj) {
                ws.send(obj);
            }
        };

        return methods;
    }
})();

Add _send function for hacky-ness


'use strict';
/*eslint no-underscore-dangle: 0*/
var ElementFactory = require('./ElementFactory.js');
var elem = new ElementFactory({});
var stream = require('stream');

var ToHTML = function(options) {
  this.options = options;
  this.elem = new ElementFactory(options);
  stream.Transform.call(this, {
    objectMode: true
  });
};

var convertTokenToHTML = function(token) {
  var html = '';
  switch (token.type) {
    case 'open':
      html = elem.open(token.name, token.attr, token.selfClose);
      break;
    case 'close':
      html = elem.close(token.name);
      break;
    case 'text':
      html = token.content;
      break;
    case 'processinginstruction':
      html = elem.open(token.content);
      break;
    case 'comment':
      html = '<!--' + token.content + '-->';
      break;
    default:
      console.log('Unrecognised token type: ', token);
      break;
  }
  return html;
};

require('util').inherits(ToHTML, stream.Transform);

ToHTML.prototype._transform = function(token, enc, cb) {
  // Ignore invalid tokens
  if (typeof token !== 'object' || !token.type) {
    cb(null);
  }

  this.push(convertTokenToHTML(token));

  cb(null);
};

module.exports = function(options) {
  return new ToHTML(options);
};

module.exports.convertTokenToHTML = convertTokenToHTML;

'use strict';
/*eslint no-underscore-dangle: 0*/
var ElementFactory = require('./ElementFactory.js');
var elem = new ElementFactory({});
var stream = require('stream');

var ToHTML = function(options) {
  this.options = options;
  this.elem = new ElementFactory(options);
  stream.Transform.call(this, {
    objectMode: true
  });
};

var convertTokenToHTML = function(token) {
  var html = '';
  switch (token.type) {
    case 'open':
      html = elem.open(token.name, token.attr, token.selfClose);
      break;
    case 'close':
      html = elem.close(token.name);
      break;
    case 'text':
      html = token.content;
      break;
    case 'processinginstruction':
      html = elem.open(token.content);
      break;
    case 'comment':
      html = '<!--' + token.content + '-->';
      break;
    default:
      console.log('Unrecognised token type: ', token);
      break;
  }
  return html;
};

require('util').inherits(ToHTML, stream.Transform);

ToHTML.prototype._transform = function(token, enc, cb) {
  // Ignore invalid tokens
  if (typeof token !== 'object' || !token.type) {
    if (typeof token === 'string') {
      this.push(token);
    }
    return cb(null);
  }

  this.push(convertTokenToHTML(token));

  cb(null);
};

module.exports = function(options) {
  return new ToHTML(options);
};

module.exports.convertTokenToHTML = convertTokenToHTML;

Allow strings to pass through the stream


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

var page = new PluginPage('BarcodeScanner', 'cordova-plugin-barcodescanner', function(parent) {

  new tabris.Button({
    layoutData: {left: 10, top: 10, right: 10},
    text: 'Scan Barcode'
  }).on('select', scanBarcode).appendTo(parent);

  var resultView = new tabris.TextView({
    layoutData: {top: 'prev() 20', left: 20, right: 20},
    markupEnabled: true
  }).appendTo(parent);

  function scanBarcode() {
    cordova.plugins.barcodeScanner.scan(function(result) {
      resultView.set('text', result.cancelled ?
                             'Scan cancelled' :
                             'Scan result: ' + result.text + ' (' + result.format + ')');
    }, function(error) {
      resultView.set('text', 'Error: ' + error);
    });
  }
});

module.exports = page;

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

var page = new PluginPage('BarcodeScanner', 'phonegap-plugin-barcodescanner', function(parent) {

  new tabris.Button({
    layoutData: {left: 10, top: 10, right: 10},
    text: 'Scan Barcode'
  }).on('select', scanBarcode).appendTo(parent);

  var resultView = new tabris.TextView({
    layoutData: {top: 'prev() 20', left: 20, right: 20},
    markupEnabled: true
  }).appendTo(parent);

  function scanBarcode() {
    cordova.plugins.barcodeScanner.scan(function(result) {
      resultView.set('text', result.cancelled ?
                             'Scan cancelled' :
                             'Scan result: ' + result.text + ' (' + result.format + ')');
    }, function(error) {
      resultView.set('text', 'Error: ' + error);
    });
  }
});

module.exports = page;

Update barcode scanner example to reference plugin "phonegap-plugin-barcodescanner"


var Settings = {
  setUrls: function(urls) {
    localStorage.setItem('urls', JSON.stringify(urls));
  },
  getUrls: function() {
    var urls = localStorage.getItem('urls') || '';
    return JSON.parse(urls);
  }
};

var Settings = {
  setUrls: function(urls) {
    localStorage.setItem('urls', JSON.stringify(urls));
  },
  getUrls: function() {
    var urls = localStorage.getItem('urls');
    return urls ? JSON.parse(urls) : '';
  }
};

Fix bug when no urls have been set up yet


angular.module('anol.mouseposition', [])

.directive('anolMousePosition', ['MapService', function(MapService) {
    return {
        restrict: 'A',
        require: '?^anolMap',
        scope: {},
        link: {
            pre: function(scope, element, attrs, AnolMapController) {
                scope.map = MapService.getMap();

                var controlOptions = {};
                if(angular.isUndefined(AnolMapController)) {
                    controlOptions = {
                        target: element[0]
                    };
                }

                scope.map.addControl(
                    new ol.control.MousePosition(controlOptions)
                );
            }
        }
    };
}]);

angular.module('anol.mouseposition', [])

.directive('anolMousePosition', ['MapService', function(MapService) {
    return {
        restrict: 'A',
        require: '?^anolMap',
        scope: {},
        link: {
            pre: function(scope, element, attrs) {
                scope.map = MapService.getMap();
            },
            post: function(scope, element, attrs, AnolMapController) {
                var controlOptions = {};

                if(angular.isFunction(scope.coordinateFormat)) {
                    controlOptions.coordinateFormat = scope.coordinateFormat;
                }

                if(angular.isUndefined(AnolMapController)) {
                    controlOptions = {
                        target: element[0]
                    };
                }

                scope.map.addControl(
                    new ol.control.MousePosition(controlOptions)
                );
            }
        }
    };
}]);

Add coordinateFormat function to controlOptions if present


const path = require("path");
const ROOT = require("./config/path-helper").ROOT;
const WebpackIsomorphicTools = require("webpack-isomorphic-tools");

function hotReloadTemplate(templatesDir) {
  require("marko/hot-reload").enable();
  require("chokidar")
    .watch(templatesDir)
    .on("change", filename => {
      require("marko/hot-reload").handleFileModified(path.join(ROOT, filename));
    });
}

global.webpackIsomorphicTools = new WebpackIsomorphicTools(
  require("./config/webpack/webpack-isomorphic-tools")
);

// to get the node require instead of dynamic require by webpack
global.nodeRequire = require;

global.webpackIsomorphicTools
  .server(ROOT, () => {
    require("source-map-support").install();

    if (process.env.NODE_DEBUGGER) {
      require("babel-core/register");
      require("./app/server");
    } else {
      require("./build/server");
    }

    if (process.env.NODE_ENV === "development") {
      hotReloadTemplate("./app/server/application/templates/**/*.marko");
    }
  });

const path = require("path");
const ROOT = require("./config/path-helper").ROOT;
const WebpackIsomorphicTools = require("webpack-isomorphic-tools");

require("source-map-support").install({
  environment: "node"
});

function hotReloadTemplate(templatesDir) {
  require("marko/hot-reload").enable();
  require("chokidar")
    .watch(templatesDir)
    .on("change", filename => {
      require("marko/hot-reload").handleFileModified(path.join(ROOT, filename));
    });
}

global.webpackIsomorphicTools = new WebpackIsomorphicTools(
  require("./config/webpack/webpack-isomorphic-tools")
);

// to get the node require instead of dynamic require by webpack
global.nodeRequire = require;

global.webpackIsomorphicTools
  .server(ROOT, () => {
    if (process.env.NODE_DEBUGGER) {
      require("babel-core/register");
      require("./app/server");
    } else {
      require("./build/server");
    }

    if (process.env.NODE_ENV === "development") {
      hotReloadTemplate("./app/server/application/templates/**/*.marko");
    }
  });

Add source-map-support only for node env


import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
    layout,

    store: Ember.inject.service(),
    internalState: Ember.inject.service(),

    leftTitle: null,
    leftView: null,
    leftPanelColor: null,
    leftModel: null,

    rightTitle: null,
    rightView: null,
    rightPanelColor: null,

    init() {
      this._super(...arguments);
      console.log("Left View = " + this.get("leftView"));
      console.log("Right View = " + this.get("rightView"));
    },
    didRender() {
    },

    actions: {
      onLeftModelChange: function (model) {
        this.set("leftModel", model);
      },
      taleLaunched: function() {
        // TODO convert this interaction to use the wholetale events service instead
        // Update model and test if the interface updates automatically
        let self = this;
        this.get('store').unloadAll('instance');
        this.get('store').findAll('instance', { reload: true, adapterOptions: { queryParams:{sort: "created", sortdir: "-1", limit: "0"}} })
          .then(models => {
            self.set('rightModelTop', models);
          });
      },
    }
});

import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
    layout,

    store: Ember.inject.service(),
    internalState: Ember.inject.service(),

    leftTitle: null,
    leftView: null,
    leftPanelColor: null,
    leftModel: null,

    rightTitle: null,
    rightView: null,
    rightPanelColor: null,

    init() {
      this._super(...arguments);
      console.log("Left View = " + this.get("leftView"));
      console.log("Right View = " + this.get("rightView"));
    },
    didRender() {
    },

    actions: {
      onLeftModelChange: function (model) {
        this.set("leftModel", model);
      },
      taleLaunched: function() {
        // TODO convert this interaction to use the wt-events service instead
        // Update right panel models
        let self = this;
        // NOTE: using store.query here as a work around to disable store.findAll caching
        this.get('store').query('instance', {})
          .then(models => {
            self.set('rightModelTop', models);
          });
      },
    }
});

Update work around for disabling store caching


/**
 * Terminal client for the Ma3Route REST API
 */

"use strict";

// npm-installed modules
var decamelize = require("decamelize");
var parser = require("simple-argparse");

// own modules
var lib = require(".");
var pkg = require("../package.json");

parser
    .version(pkg.version)
    .description("ma3route", "terminal client for the Ma3Route REST API v2")
    .epilog("See https://github.com/GochoMugo/ma3route-cli for source code and license")
    .option("c", "config", "run configuration setup", lib.config.run)
    .prerun(function() {
      if (this.debug) {
        process.env.DEBUG = process.env.DEBUG || 1;
        delete this.debug;
      }
    });

// add options
for (var name in lib.options) {
    var option = lib.options[name];
    parser.option(option.descriptor.short, decamelize(name, "-"), option.description, option.run);
}

parser.parse();

/**
 * Terminal client for the Ma3Route REST API
 */

"use strict";

// npm-installed modules
var decamelize = require("decamelize");
var parser = require("simple-argparse");

// own modules
var lib = require("../lib");
var pkg = require("../package.json");

parser
    .version(pkg.version)
    .description("ma3route", "terminal client for the Ma3Route REST API v2")
    .epilog("See https://github.com/GochoMugo/ma3route-cli for source code and license")
    .option("c", "config", "run configuration setup", lib.config.run)
    .prerun(function() {
      if (this.debug) {
        process.env.DEBUG = process.env.DEBUG || 1;
        delete this.debug;
      }
    });

// add options
for (var name in lib.options) {
    var option = lib.options[name];
    parser.option(option.descriptor.short, decamelize(name, "-"), option.description, option.run);
}

parser.parse();

Add backwards compatibility for Node 0.x series


udefine(function() {
  return function(Factory, groupInstance) {

    return function() {
      var child = arguments[0];
      var args = 2 <= arguments.length ? [].slice.call(arguments, 1) : [];

      if (!( child instanceof Factory)) {
        if ( typeof child === 'string') {
          if (Object.hasOwnProperty.call(store, child)) {
            child = new Factory(Factory.store[child], args);
          }
        } else {
          child = new Factory(child, args);
        }
      }
      groupInstance.push(child);
      child.parent = this;
      child.trigger('add', child, args);
    };
  };
});

udefine(function() {
  return function(Factory, groupInstance) {

    return function() {
      var child = arguments[0];
      var args = 2 <= arguments.length ? [].slice.call(arguments, 1) : [];

      if (!( child instanceof Factory)) {
        if ( typeof child === 'string') {
          if (Object.hasOwnProperty.call(store, child)) {
            child = new Factory(Factory.store[child]);
          }
        } else {
          child = new Factory(child);
        }
      }
      groupInstance.push(child);
      child.parent = this;

      child.apply(args);
      child.trigger('add', child, args);
    };
  };
});

Call descriptor when a child is added


/* global angular */

angular.module('app')
.directive('extHref', function (platformInfo) {
	'use strict';

	return {
		restrict: 'A',
		link: link
	};

	function link(scope, element, attributes) {
		const url = attributes.extHref;
		if (platformInfo.isCordova) {
			element[0].onclick = onclick;
		} else {
			element[0].href = url;
		}

		function onclick() {
			window.open(url, '_system');
			return false;
		}
	}
});

/* global angular, require */

angular.module('app')
.directive('extHref', function (platformInfo) {
	'use strict';

	return {
		restrict: 'A',
		link: link
	};

	function link(scope, element, attributes) {

		const url = attributes.extHref;
		element[0].onclick = () => {
			if (platformInfo.isCordova) {
				window.open(url, '_system');
			} else {
				require('electron').shell.openExternal(url);
			}
			return false;
		};
	}
});

Clean up, and use electron functions to open urls


import Controller from '@ember/controller';
import {inject as service} from '@ember/service';

export default class UploadThemeController extends Controller {
    @service config;

    get isAllowed() {
        return !this.config.get('hostSettings')?.limits?.customThemes;
    }
}

import Controller from '@ember/controller';
import {inject as service} from '@ember/service';

export default class UploadThemeController extends Controller {
    @service config;

    get isAllowed() {
        return (!this.config.get('hostSettings')?.limits?.customThemes) || this.config.get('hostSettings').limits.customThemes.disabled;
    }
}

Fix UploadThemeController to support disable:true customThemes flag


Template.registrantDetails.helpers({
    'registrationTypeOptions': function () {
        // registration types used on the registration form
        return [
            {label: "Commuter", value: "commuter"},
            {label: "Daily", value: "daily"},
            {label: "Full Week", value: "weekly"}
        ];
    }
});

Template.registrantDetails.events({
    'change #registration_type': function () {
        // clean up form values for accommodations and days
        // to make sure no erroneous values remain

        resetReactiveVars();

        // Clear the accommodations selection
        $("#accommodations").val("");

        // Clear all day checkboxes
        $('input[name="days"]').each(function() {
            // make sure day is not checked
            this.checked = false;
        });
    },
    'change #age': function () {
        // Get the value of the age field
        var ageValue = $('#age').val();

        // Calculate the age group based on the age value
        var ageGroup = calculateAgeGroup(ageValue);

        // Reset the accommodations selection
        // as accommodations depend on age group
        $("#accommodations").val("");

        // Set the age group reactive variable
        // for price calculations
        ageGroupVar.set(ageGroup);
    }
});

Template.registrantDetails.helpers({
    'registrationTypeOptions': function () {
        // registration types used on the registration form
        return [
            {label: "Commuter", value: "commuter"},
            {label: "Daily", value: "daily"},
            {label: "Full Week", value: "weekly"}
        ];
    },
    /*
    Determine if registrant is school aged
    by checking age group
    return true if age group is child, youth, or teen
    */
    'schoolAgeGroup': function () {
        var ageGroup = ageGroupVar.get();

        // look at the value of age group
        switch (ageGroup) {
                // if child, youth or teen
                // return true
            case 'child':
                return true;
                break;
            case 'youth':
                return true;
                break;
            case 'teen':
                return true;
                break;
            default:
                return false;
                break;
        };
    }
});

Template.registrantDetails.events({
    'change #registration_type': function () {
        // clean up form values for accommodations and days
        // to make sure no erroneous values remain

        resetReactiveVars();

        // Clear the accommodations selection
        $("#accommodations").val("");

        // Clear all day checkboxes
        $('input[name="days"]').each(function() {
            // make sure day is not checked
            this.checked = false;
        });
    },
    'change #age': function () {
        // Get the value of the age field
        var ageValue = $('#age').val();

        // Calculate the age group based on the age value
        var ageGroup = calculateAgeGroup(ageValue);

        // Reset the accommodations selection
        // as accommodations depend on age group
        $("#accommodations").val("");

        // Set the age group reactive variable
        // for price calculations
        ageGroupVar.set(ageGroup);
    }
});

Add school age group template helper.


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

module.exports = {
    verbose: true,
    testRegex: 'test/.*\\.(js|jsx)$',
};

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

module.exports = {
    verbose: true,
    testRegex: 'test/(.+)(.test.)(js|jsx)$',
    moduleDirectories: ['node_modules', '<rootDir>'],
};

Set test regex to select only *.test.js/jsx files in the test directory.


forge['contact'] = {
	'select': function (success, error) {
		forge.internal.call("contact.select", {}, success, error);
	},
	'selectById': function (id, success, error) {
		forge.internal.call("contact.selectById", {id: id}, success, error);
	},
	'selectAll': function (fields, success, error) {
		if (typeof fields === "function") {
			error = success;
			success = fields;
			fields = [];
		}
		forge.internal.call("contact.selectAll", {fields: fields}, success, error);
	},
	'add': function (contact, success, error) {
		if (typeof contact === "function") {
			error = success;
			success = contact;
			contact = {};
		}
		forge.internal.call("contact.add", {contact: contact}, success, error);
	},

	'insert': function (contact, success, error) {
	    forge.internal.call("contact.insert", {contact: contact},
				success, error);
	}
};

/* global forge */

forge['contact'] = {
    'select': function (success, error) {
        forge.internal.call("contact.select", {}, success, error);
    },
    'selectById': function (id, success, error) {
        forge.internal.call("contact.selectById", {id: id}, success, error);
    },
    'selectAll': function (fields, success, error) {
        if (typeof fields === "function") {
            error = success;
            success = fields;
            fields = [];
        }
        forge.internal.call("contact.selectAll", {fields: fields}, success, error);
    },
    'add': function (contact, success, error) {
        if (typeof contact === "function") {
            error = success;
            success = contact;
            contact = {};
        }
        contact = JSON.parse(JSON.stringify(contact, function (k, v) { return v ==null ? undefined : v; }));
        forge.internal.call("contact.add", {contact: contact}, success, error);
    },

    'insert': function (contact, success, error) {
        contact = JSON.parse(JSON.stringify(contact, function (k, v) { return v ==null ? undefined : v; }));
        forge.internal.call("contact.insert", {contact: contact},
                success, error);
    }
};

Test failure on iOS13 when adding contacts with null property fields.


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

export default Service.extend(Evented, {

  showWindow: false,
  shownComponents: null,
  popupContent: null,

  addComponent(path) {
    if (this.get('shownComponents') == null) {
      this.set('shownComponents', []);
    }
    if (!this.get('shownComponents').includes(path)) {
      this.get('shownComponents').push(path);
      this.notifyPropertyChange('shownComponents');
    }
  },

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

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

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

  emptyAndClose() {
    this.close();
    if (this.get('shownComponents')) {
      this.set('shownComponents.length', 0);
    }
  },

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

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

  setPopupContent(content) {
    this.set('popupContent', content);
  },

  removePopup() {
    this.set('popupContent', null);
  }

});

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

export default Service.extend(Evented, {

  showWindow: false,
  shownComponents: null,
  popupContent: null,

  addComponent(path) {
    if (this.get('shownComponents') == null) {
      this.set('shownComponents', []);
    }
    if (!this.get('shownComponents').includes(path)) {
      this.get('shownComponents').unshift(path);
      this.notifyPropertyChange('shownComponents');
    }
  },

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

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

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

  emptyAndClose() {
    this.close();
    if (this.get('shownComponents')) {
      this.set('shownComponents.length', 0);
    }
  },

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

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

  setPopupContent(content) {
    this.set('popupContent', content);
  },

  removePopup() {
    this.set('popupContent', null);
  }

});

Add new components to top of sidebar


// import node packages
import React from 'react';

function Flashcard(props) {
  return (

      Question: {this.props.question}

      Answer: {this.props.answer}

  );
}

export default Flashcard;

// import node packages
import React from 'react';

function Flashcard(props) {
  return (

      Question: {props.question}

      Answer: {props.answer}

  );
}

export default Flashcard;

Fix props usage for function vs class


"use strict";

// considered using the node url library, but couldn't resolve dependencies
// without serious modifications, leading to maintenance nightmares

module.exports = {
    parse: function(url) {
        // rudimentary URL regex, could use some improvement
        // but should suffice for now. capturing parentheses are:
        //   1: protocol
        //   2: host
        //   3: path
        //   4: query
        var re = /^(?:([^:]+)?:?\/\/\/?)?([^\/]+)(?:(\/[^\?]*)(?:\??(.*))?)?$/,
            match = re.exec(url) || [];

        return {
            protocol: match[1],
            host: match[2],
            path: match[3] || '/',
            query: match[4]
        };
    },
    format: function(obj) {
        // based off the object returned from the parse url
        return [
            obj.protocol
                ? obj.protocol + '://'
                : '//',
            obj.host,
            obj.path,
            obj.query
                ? '?' + obj.query
                : ''
        ].join('');
    }
};

"use strict";

// considered using the node url library, but couldn't resolve dependencies
// without serious modifications, leading to maintenance nightmares

module.exports = {
    parse: function(url) {
        // rudimentary URL regex, could use some improvement
        // but should suffice for now. capturing parentheses are:
        //   1: protocol
        //   2: host
        //   3: path
        //   4: query
        var re = /^(?:([^:]+)?:?\/\/\/?)?([^\/]+)?(?:(\/[^\?]*)(?:\??(.*))?)?$/,
            match = re.exec(url) || [];

        return {
            protocol: match[1],
            host: match[2],
            path: match[3] || '/',
            query: match[4]
        };
    },
    format: function(obj) {
        // based off the object returned from the parse url
        return [
            obj.protocol
                ? obj.protocol + '://'
                : '//',
            obj.host,
            obj.path,
            obj.query
                ? '?' + obj.query
                : ''
        ].join('');
    }
};

Allow capture of relative URLs by making regex host segment optional


'use strict';

(function(exports) {
  exports.API_URL = '/';
}(window));

'use strict';

(function(exports) {
  exports.API_URL = 'http://api.sensorweb.io/';
}(window));

Switch to use real APIs on SensorWeb platform


"use strict";

const Constants = require("../../../Constants");
const Events = Constants.Events;
const Endpoints = Constants.Endpoints;
const apiRequest = require("../../../core/ApiRequest");

module.exports = function(channelId, messages) {
  console.log("deletes", messages)
  return new Promise((rs, rj) => {
    apiRequest
    .post(this, {
      url: `${Endpoints.MESSAGES(channelId)}/bulk_delete`,
      body: {messages: messages}
    })
    .send((err, res) => {
      return (!err && res.ok) ? rs() : rj(err);
    });
  });
};

"use strict";

const Constants = require("../../../Constants");
const Events = Constants.Events;
const Endpoints = Constants.Endpoints;
const apiRequest = require("../../../core/ApiRequest");

module.exports = function(channelId, messages) {
  return new Promise((rs, rj) => {
    apiRequest
    .post(this, {
      url: `${Endpoints.MESSAGES(channelId)}/bulk_delete`,
      body: {messages: messages}
    })
    .send((err, res) => {
      return (!err && res.ok) ? rs() : rj(err);
    });
  });
};

Remove log message on bulk delete


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

function mainController($scope, $http) {
  $scope.formData = {};

  $http.get('/api/todos')
    .success(function(data) {
      $scope.todos = data;
      console.log(data);
    })
    .error(function(data){
      console.log(Error(data));
    });

  $scope.createTodo = function() {
    $http.post('/api/todos', $scope.formData)
      .success(function(data){
        $scope.formData = {};
        $scope.todos = data;
        console.log(data);
      })
      .errror(function(data){
        console.log("Error: " + data);
      });
  };

  $scope.deleteTodo = function(id){
    $http.delete('/api/todos'+ id)
      .success(function(data){
        $scope.todos = data;
        console.log(data);
      })
      .error(function(data){
        console.log("Error: "+ data);
      });
  };

}

Write CRD todo module for angular.


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

/* fake api server */
var server = require('./server');

var api = server.createServer();

var clubs = [
  {
    id: '205',
    name: 'SURTEX',
    logo: 'http://121.199.38.39/hphoto/logoclub/NewClub.jpgw76_h76.jpg'
  }
];

var responses = {
  'clubs/': server.createGetResponse(JSON.stringify(clubs), 'application/json')
};

var bot = require('..')({url: api.url});

before(function (done) {
  api.listen(api.port, function () {
    for (var route in responses) {
      api.on('/' + route, responses[route]);
    }
    done();
  });
});

/* test cases */

describe('letsface api', function (done) {
  var req = {
    weixin: {
      MsgType: 'text',
      Content: 'clubs'
    }
  };
  var res = {
    reply: function (result) {
      expect(result).to.equal('1 clubs');
      done();
    }
  };
  it('should reply club list', function () {
    bot(req, res);
  });
});

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

/* fake api server */
var server = require('./server');

var api = server.createServer();

var clubs = [
  {
    id: '205',
    name: 'SURTEX',
    logo: 'http://121.199.38.39/hphoto/logoclub/NewClub.jpgw76_h76.jpg'
  }
];

var responses = {
  'clubs/': server.createGetResponse(JSON.stringify(clubs), 'application/json')
};

var bot = require('..')({url: api.url});

before(function (done) {
  api.listen(api.port, function () {
    for (var route in responses) {
      api.on('/' + route, responses[route]);
    }
    done();
  });
});

/* test cases */

describe('letsface api', function () {
  it('should reply club list', function (done) {
    var req = {
      weixin: {
        MsgType: 'text',
        Content: 'clubs'
      }
    };
    var res = {
      reply: function (result) {
        expect(result).to.equal('1 clubs');
        done();
      }
    };
    bot(req, res);
  });
});

Fix test error (still failing)


import 'babel-polyfill';

import sinon from 'sinon';
import chai from 'chai';
import chaiEnzyme from 'chai-enzyme';
import factory from 'fixture-factory';

chai.use(chaiEnzyme());

global.chai = chai;
global.sinon = sinon;
global.expect = chai.expect;
global.should = chai.should();

/**
 * Register the story as factory model.
 */
factory.register('story', {
	id: 'random.number',
	title: 'random.words',
	body: 'random.words',
	liked: false,
	author: {
		name: 'random.words',
	},
});

const __karmaWebpackManifest__ = [];

// Include all .js files under `app`, except app.js, reducers.js, routes.js and
// store.js. This is for isparta code coverage
const context = require.context(
	'../../src/app',
	true,
	/^^((?!(client|server)).)*\.js$/
);

function inManifest(path) {
	return __karmaWebpackManifest__.indexOf(path) >= 0;
}

let runnable = context.keys().filter(inManifest);

// Run all tests if we didn't find any changes
if (!runnable.length) {
	runnable = context.keys();
}

runnable.forEach(context);

import 'babel-polyfill';

import sinon from 'sinon';
import chai from 'chai';
import chaiEnzyme from 'chai-enzyme';
import factory from 'fixture-factory';

chai.use(chaiEnzyme());

global.chai = chai;
global.sinon = sinon;
global.expect = chai.expect;
global.should = chai.should();

/**
 * Register the story as factory model.
 */
factory.register('story', {
	id: 'random.number',
	title: 'random.words',
	excerpt: 'random.words',
	body: 'random.words',
	liked: false,
	author: {
		name: 'random.words',
	},
	created_at: 'date.recent.value',
});

factory.register('category', {
	id: 'random.number',
	name: 'random.word',
});

const __karmaWebpackManifest__ = [];

// Include all .js files under `app`, except app.js, reducers.js, routes.js and
// store.js. This is for isparta code coverage
const context = require.context(
	'../../src/app',
	true,
	/^^((?!(client|server)).)*\.js$/
);

function inManifest(path) {
	return __karmaWebpackManifest__.indexOf(path) >= 0;
}

let runnable = context.keys().filter(inManifest);

// Run all tests if we didn't find any changes
if (!runnable.length) {
	runnable = context.keys();
}

runnable.forEach(context);

Add excerpt to the story factor & add category factory


/**
 * As Recast is not preserving original quoting, we try to detect it.
 * See https://github.com/benjamn/recast/issues/171
 * and https://github.com/facebook/jscodeshift/issues/143
 * @return 'double', 'single' or null
 */
export default function detectQuoteStyle(j, ast) {
    let detectedQuoting = null;

    ast
        .find(j.Literal, {
            value: v => typeof v === 'string',
            raw: v => typeof v === 'string',
        })
        .forEach(p => {
            // The raw value is from the original babel source
            if (p.value.raw[0] === "'") {
                detectedQuoting = 'single';
            }

            if (p.value.raw[0] === '"') {
                detectedQuoting = 'double';
            }
        });

    return detectedQuoting;
}

/**
 * As Recast is not preserving original quoting, we try to detect it.
 * See https://github.com/benjamn/recast/issues/171
 * and https://github.com/facebook/jscodeshift/issues/143
 * @return 'double', 'single' or null
 */
export default function detectQuoteStyle(j, ast) {
    let doubles = 0;
    let singles = 0;

    ast
        .find(j.Literal, {
            value: v => typeof v === 'string',
            raw: v => typeof v === 'string',
        })
        .forEach(p => {
            // The raw value is from the original babel source
            const quote = p.value.raw[0];
            if (quote === '"') {
                doubles += 1;
            }
            if (quote === "'") {
                singles += 1;
            }
        });

    if (doubles === singles) {
        return null;
    }
    return doubles > singles ? 'double' : 'single';
}

Improve detectQuoteStyle (needed when adding imports and requires)


/* eslint-disable import/first */
import router from 'girder/router';
import events from 'girder/events';
import { exposePluginConfig } from 'girder/utilities/PluginUtils';

exposePluginConfig('treeview', 'plugins/treeview/config');

import ConfigView from './views/ConfigView';
router.route('plugins/treeview/config', 'treeviewConfig', function () {
    events.trigger('g:navigateTo', ConfigView);
});

Fix style for compatibility with eslint rule changes


import React, { PropTypes } from 'react'
import styled from 'styled-components'
import AceEditor from 'react-ace'

const PreviewContainer = styled.div`
  align-self: center;
  padding: 28px;
  width: 100%;
  height: 400px;
  background-color: white;
  border: 1px solid rgba(0, 0, 0, 0.35);
  box-shadow: 0 2px 16px 2px rgba(0, 0, 0, 0.25);
  box-sizing: border-box;
  overflow: scroll;
`

function DynamicPreview({ value, fontface, language, theme }) {
  require(`brace/mode/${language}`) // eslint-disable-line
  require(`brace/theme/${theme}`) // eslint-disable-line
  return (
    <PreviewContainer>
      <AceEditor mode={language} theme={theme} value={value} style={{ fontFamily: fontface }} />
    </PreviewContainer>
  )
}

DynamicPreview.propTypes = {
  value: PropTypes.string.isRequired,
  fontface: PropTypes.string,
  language: PropTypes.string.isRequired,
  theme: PropTypes.string.isRequired
}

export default DynamicPreview

import React, { PropTypes } from 'react'
import styled from 'styled-components'
import AceEditor from 'react-ace'

const PreviewContainer = styled.div`
  align-self: center;
  padding: 28px;
  width: 100%;
  height: 400px;
  background-color: white;
  border: 1px solid rgba(0, 0, 0, 0.35);
  box-shadow: 0 2px 16px 2px rgba(0, 0, 0, 0.25);
  box-sizing: border-box;
  overflow: scroll;
`

function DynamicPreview({ value, fontface, language, theme }) {
  require(`brace/mode/${language}`) // eslint-disable-line
  require(`brace/theme/${theme}`) // eslint-disable-line
  return (
    <PreviewContainer>
      <AceEditor
        mode={language}
        theme={theme}
        value={value}
        showGutter={false}
        style={{ fontFamily: fontface }}
      />
    </PreviewContainer>
  )
}

DynamicPreview.propTypes = {
  value: PropTypes.string.isRequired,
  fontface: PropTypes.string,
  language: PropTypes.string.isRequired,
  theme: PropTypes.string.isRequired
}

export default DynamicPreview

Remove gutter to match the output


/**
 * Created by austin on 9/24/14.
 */

var streams = function (client) {
  this.client = client;
};

var _qsAllowedProps = [
        'resolution'
        , 'series_type'
    ];

//===== streams endpoint =====
streams.prototype.activity = function(args,done) {

    var endpoint = 'activities';
    this._typeHelper(endpoint,args,done);
};

streams.prototype.effort = function(args,done) {

    var endpoint = 'segment_efforts';
    this._typeHelper(endpoint,args,done);
};

streams.prototype.segment = function(args,done) {

    var endpoint = 'segments';
    this._typeHelper(endpoint,args,done);
};

streams.prototype.route = function(args,done) {

    var endpoint = 'routes';
    this._typeHelper(endpoint,args,done);
};
//===== streams endpoint =====

//===== helpers =====
streams.prototype._typeHelper = function(endpoint,args,done) {

    var err = null
        , qs = this.client.getQS(_qsAllowedProps,args);

    //require id
    if(typeof args.id === 'undefined') {
        throw new Error('args must include an id');
    }
    //require types
    if(typeof args.types === 'undefined') {
        throw new Error('args must include types');
    }

    endpoint += '/' + args.id + '/streams/' + args.types + '?' + qs;
    return this.client.getEndpoint(endpoint,args,done);
};
//===== helpers =====

module.exports = streams;

/**
 * Created by austin on 9/24/14.
 */

var streams = function (client) {
  this.client = client;
};

var _qsAllowedProps = [
        'resolution'
        , 'series_type'
    ];

//===== streams endpoint =====
streams.prototype.activity = function(args,done) {

    var endpoint = 'activities';
    return this._typeHelper(endpoint,args,done);
};

streams.prototype.effort = function(args,done) {

    var endpoint = 'segment_efforts';
    return this._typeHelper(endpoint,args,done);
};

streams.prototype.segment = function(args,done) {

    var endpoint = 'segments';
    return this._typeHelper(endpoint,args,done);
};

streams.prototype.route = function(args,done) {

    var endpoint = 'routes';
    return this._typeHelper(endpoint,args,done);
};
//===== streams endpoint =====

//===== helpers =====
streams.prototype._typeHelper = function(endpoint,args,done) {

    var err = null
        , qs = this.client.getQS(_qsAllowedProps,args);

    //require id
    if(typeof args.id === 'undefined') {
        throw new Error('args must include an id');
    }
    //require types
    if(typeof args.types === 'undefined') {
        throw new Error('args must include types');
    }

    endpoint += '/' + args.id + '/streams/' + args.types + '?' + qs;
    return this.client.getEndpoint(endpoint,args,done);
};
//===== helpers =====

module.exports = streams;

Return value for client.stream.* calls


/* global console, Calendar, vis */

(function() {
    "use strict";

    var calendar = new Calendar();
    calendar.init(document.getElementById('visualization'),
    {
      height: "100vh",
      orientation: "top",
      zoomKey: 'shiftKey',
      zoomMax: 315360000000,
      zoomMin: 600000,
      editable: {
        add: false,
        updateTime: true,
        updateGroup: false,
        remove: true
      },
      groupOrder: function (a, b) {
          if (a.id === "Demos") {
            return -1;
          }
          if (b.id === "Demos") {
            return 1;
          }

          var groups = [a.id, b.id];
          groups.sort();
          if (a.id === groups[0]) {
            return -1;
          } else {
            return 1;
          }
        }

    });

    $(document).ready(function(){
      $('.vis-center>.vis-content').on('scroll', function () {
          $('.vis-left>.vis-content').scrollTop($(this).scrollTop());
      });
      $('.vis-left>.vis-content').on('scroll', function () {
          $('.vis-center>.vis-content').scrollTop($(this).scrollTop());
      });
    });

})();

/* global console, Calendar, vis */

(function() {
    "use strict";

    var calendar = new Calendar();
    calendar.init(document.getElementById('visualization'),
    {
      height: "100vh",
      orientation: "top",
      zoomKey: 'shiftKey',
      zoomMax: 315360000000,
      zoomMin: 86400000,
      editable: {
        add: false,
        updateTime: true,
        updateGroup: false,
        remove: true
      },
      groupOrder: function (a, b) {
          if (a.id === "Demos") {
            return -1;
          }
          if (b.id === "Demos") {
            return 1;
          }

          var groups = [a.id, b.id];
          groups.sort();
          if (a.id === groups[0]) {
            return -1;
          } else {
            return 1;
          }
        }

    });

    $(document).ready(function(){
      $('.vis-center>.vis-content').on('scroll', function () {
          $('.vis-left>.vis-content').scrollTop($(this).scrollTop());
      });
      $('.vis-left>.vis-content').on('scroll', function () {
          $('.vis-center>.vis-content').scrollTop($(this).scrollTop());
      });
    });

})();

Update minimun zoom to 24 hours


'use strict';

var EventEmitter = require('events'),
    util = require('util');

/**
 * The emitter returned by methods that load data from an external source.
 * @constructor
 * @fires Loading#error
 * @fires Loading#loaded
 */
function Loading(config) {
    EventEmitter.call(this);
}
util.inherits(Loading, EventEmitter);
Loading.prototype.loaded = function(data) {
    this.emit('loaded', data);
};
Loading.prototype.error = function(error) {
    if (typeof error === 'string') {
        this.emit('error', new Error(error));
        return;
    }
    else if (typeof error === 'object') {
        if (error instanceof String) {
            this.emit('error', new Error(error));
            return;
        }
        else if (error instanceof Error) {
            this.emit('error', error);
            return;
        }
    }
    this.emit('error', '' + error);
};
Loading.prototype.onLoaded = function(handler) {
    this.on('loaded', handler);
};
Loading.prototype.onError = function(handler) {
    this.on('error', handler);
};

/**
 * Emitted when there is an error loading the data.
 * @event Loading#error
 */

/**
 * Emitted when the data has been loaded successfuly.
 * @event Loading#loaded
 */

module.exports = Loading;

'use strict';

var EventEmitter = require('events'),
    util = require('util');

/**
 * The emitter returned by methods that load data from an external source.
 * @constructor
 * @fires Loading#error
 * @fires Loading#loaded
 */
function Loading(config) {
    EventEmitter.call(this);
}
util.inherits(Loading, EventEmitter);
Loading.prototype.loaded = function(data) {
    this.emit('loaded', data);
    return this;
};
Loading.prototype.error = function(error) {
    if (typeof error === 'string') {
        this.emit('error', new Error(error));
        return this;
    }
    else if (typeof error === 'object') {
        if (error instanceof String) {
            this.emit('error', new Error(error));
            return this;
        }
        else if (error instanceof Error) {
            this.emit('error', error);
            return this;
        }
    }
    this.emit('error', '' + error);
    return this;
};
Loading.prototype.onLoaded = function(handler) {
    this.on('loaded', handler);
    return this;
};
Loading.prototype.onError = function(handler) {
    this.on('error', handler);
    return this;
};

/**
 * Emitted when there is an error loading the data.
 * @event Loading#error
 */

/**
 * Emitted when the data has been loaded successfuly.
 * @event Loading#loaded
 */

module.exports = Loading;

Return Loading from Loading methods.


"use strict";
// Angular is refusing to recognize the HawtioNav stuff
// when testing even though its being loaded
 beforeEach(module(function ($provide) {
  $provide.provider("HawtioNavBuilder", function() {
    function Mocked() {}
    this.create = function() {return this;};
    this.id = function() {return this;};
    this.title = function() {return this;};
    this.template = function() {return this;};
    this.isSelected = function() {return this;};
    this.href = function() {return this;};
    this.page = function() {return this;};
    this.subPath = function() {return this;};
    this.build = function() {return this;};
    this.join = function() {return "";};
    this.$get = function() {return new Mocked();};
  });

  $provide.factory("HawtioNav", function(){
    return {add: function() {}};
  });

  $provide.factory("HawtioExtension", function() {
    return {
      add: function() {}
    };
  });

}));

// Make sure a base location exists in the generated test html
 if (!$('head base').length) {
   $('head').append($('<base href="/">'));
 }

 angular.module('openshiftConsole').config(function(AuthServiceProvider) {
   AuthServiceProvider.UserStore('MemoryUserStore');
 });

 //load the module
beforeEach(module('openshiftConsole'));

"use strict";
 beforeEach(module(function ($provide) {
  $provide.factory("HawtioExtension", function() {
    return {
      add: function() {}
    };
  });

}));

// Make sure a base location exists in the generated test html
 if (!$('head base').length) {
   $('head').append($('<base href="/">'));
 }

 angular.module('openshiftConsole').config(function(AuthServiceProvider) {
   AuthServiceProvider.UserStore('MemoryUserStore');
 });

 //load the module
beforeEach(module('openshiftConsole'));

Remove HawtioNav* mocks (no longer used)


import connection from '../../config/database';

module.exports.register = (server, options, next) => {
  async function getAvatar(userid, next) {
    try {
      const employee = await connection
        .table('avatars')
        .filter({ userid: userid.toUpperCase() })
        .nth(0)
        .run();

      next(null, employee);
    } catch (error) {
      next(error);
    }
  }

  server.method('db.getAvatar', getAvatar, {});

  next();
};

module.exports.register.attributes = {
  name: 'method.db.getAvatar',
};

import connection from '../../config/database';

module.exports.register = (server, options, next) => {
  async function getAvatar(userid, next) {
    try {
      const employee = await connection
        .table('avatars')
        .filter({ userid: userid.toUpperCase() })
        .orderBy(connection.desc('taken'))
        .nth(0)
        .run();

      next(null, employee);
    } catch (error) {
      next(error);
    }
  }

  server.method('db.getAvatar', getAvatar, {});

  next();
};

module.exports.register.attributes = {
  name: 'method.db.getAvatar',
};

Add sort by "taken" date to avatar query, so the most recent image is returned for the person.


var join = require("path").join;
var console = require("./utils").console;
var fs = require("fs-promise");
var zip = require("./zip");
var all = require("when").all;
var tmp = require('./tmp');
var bootstrapSrc = join(__dirname, "../data/bootstrap.js");

/**
 * Takes a manifest object (from package.json) and build options
 * object and zipz up the current directory into a XPI, copying
 * over default `install.rdf` and `bootstrap.js` if needed
 * and not yet defined. Returns a promise that resolves
 * upon completion.
 *
 * @param {Object} manifest
 * @param {Object} options
 * @return {Promise}
 */

function xpi (manifest, options) {
  var cwd = process.cwd();
  var xpiName = (manifest.name || "jetpack") + ".xpi";
  var xpiPath = join(cwd, xpiName);
  var buildOptions = createBuildOptions(options);

  return doFinalZip(cwd, xpiPath);
}
module.exports = xpi;

function doFinalZip(cwd, xpiPath) {
  return zip(cwd, xpiPath).then(function () {
    return xpiPath;
  });
}

var join = require("path").join;
var console = require("./utils").console;
var fs = require("fs-promise");
var zip = require("./zip");
var all = require("when").all;
var tmp = require('./tmp');
var bootstrapSrc = join(__dirname, "../data/bootstrap.js");

/**
 * Takes a manifest object (from package.json) and build options
 * object and zipz up the current directory into a XPI, copying
 * over default `install.rdf` and `bootstrap.js` if needed
 * and not yet defined. Returns a promise that resolves
 * upon completion.
 *
 * @param {Object} manifest
 * @param {Object} options
 * @return {Promise}
 */

function xpi (manifest, options) {
  var cwd = process.cwd();
  var xpiName = (manifest.name || "jetpack") + ".xpi";
  var xpiPath = join(cwd, xpiName);

  return doFinalZip(cwd, xpiPath);
}
module.exports = xpi;

function doFinalZip(cwd, xpiPath) {
  return zip(cwd, xpiPath).then(function () {
    return xpiPath;
  });
}

Remove extra createBuildOptions for now


(function () {
    "use strict";

    var Frame = function (elem) {
        if (typeof elem === 'string') {
            elem = document.getElementById(elem);
        }

        var height = elem.scrollHeight;
        var width = elem.scrollWidth;

        var viewAngle = 45;
        var aspect = width / (1.0 * height);
        var near = 0.1;
        var far = 10000;

        this.scene = new THREE.Scene();

        this.camera = new THREE.PerspectiveCamera(viewAngle, aspect, near, far);
        this.camera.position.z = 10;
        this.scene.add(this.camera);

        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(width, height);

        elem.appendChild(this.renderer.domElement);
    };
    window.Frame = Frame;

    Frame.prototype.addNode = function (node) {
        this.scene.add(node.mesh);
    };

    Frame.prototype.render = function () {
        this.renderer.render(this.scene, this.camera);
    };

    var Node = function (x, y, z) {
        var geometry = new THREE.SphereGeometry(1, 4, 4);
        var material = new THREE.MeshBasicMaterial({color: 0x00ff00, wireframe: true});
        this.mesh = new THREE.Mesh(geometry, material);
        this.mesh.position = {x: x, y: y, z: z};
    };
    window.Node = Node;
}());

(function () {
    "use strict";

    var Frame = function (elem) {
        if (typeof elem === 'string') {
            elem = document.getElementById(elem);
        }

        var height = elem.scrollHeight;
        var width = elem.scrollWidth;

        var viewAngle = 45;
        var aspect = width / (1.0 * height);
        var near = 0.1;
        var far = 10000;

        this.scene = new THREE.Scene();

        this.camera = new THREE.PerspectiveCamera(viewAngle, aspect, near, far);
        this.camera.position.z = 10;
        this.scene.add(this.camera);

        this.renderer = new THREE.WebGLRenderer();
        this.renderer.setSize(width, height);

        elem.appendChild(this.renderer.domElement);
    };
    window.Frame = Frame;

    Frame.prototype.addNode = function (node) {
        this.scene.add(node.mesh);
    };

    Frame.prototype.render = function () {
        this.renderer.render(this.scene, this.camera);
    };

    var Node = function (x, y, z) {
        var geometry = new THREE.SphereGeometry(1, 4, 4);
        var material = new THREE.MeshBasicMaterial({color: 0x00ff00, wireframe: true});
        this.mesh = new THREE.Mesh(geometry, material);
        this.mesh.position = {x: x, y: y, z: z};
    };
    window.Node = Node;

    Node.prototype.addTo = function (frame) {
        frame.addNode(this);
    };
}());

Add a shortcut method on node to add to frame


#! /usr/bin/env node

var program = require('commander'),
    fs      = require('fs'),
    path    = require('path'),
    polish  = require('./polish');

program
  .version('1.0.0')
  .option('-s, --stylesheet <path>',        'Path to a stylesheet (in CSS, SCSS, Sass, or Less).')
  .option('-P, --plugins-directory <path>', 'Path to a directory of linting plugins')
  .option('-p, --plugins <modules>',          'Comma-separated list of linting plugins', function(modules) { return modules.split(','); })
  .parse(process.argv);

/*
 * Read the provided file and call PolishCSS
 */
fs.readFile(program.stylesheet, 'utf8', function(err, stylesheet) {
  if (err) {
    throw err;
  }

  polish(stylesheet, program.stylesheet, { plugins: program.plugins, pluginsDirectory: program.pluginsDirectory });
});

#! /usr/bin/env node

var program = require('commander'),
    fs      = require('fs'),
    path    = require('path'),
    polish  = require('./polish');

program
  .version('1.0.0')
  .option('-s, --stylesheet <path>',        'Path to a stylesheet (in CSS, SCSS, Sass, or Less).')
  .option('-P, --plugins-directory <path>', 'Path to a directory of linting plugins.')
  .option('-p, --plugins <modules>',        'Comma-separated list of linting plugins.', function(modules) { return modules.split(','); })
  .option('-q, --quiet',                    'Prevent logging errors to the console.')
  .parse(process.argv);

/*
 * Read the provided file and call PolishCSS
 */
fs.readFile(program.stylesheet, 'utf8', function(err, stylesheet) {
  var results;

  if (err) {
    throw err;
  }

  results = polish(stylesheet, program.stylesheet, { plugins: program.plugins, pluginsDirectory: program.pluginsDirectory });

  if (!program.quiet) {
    polish.reporter(program.stylesheet, results);
  }
});

Print results when using the CLI. Can be turned off with `-q` or `--quiet`.


const fs = require('fs');
const process = require('process');
const jwt = require('jsonwebtoken');

// sign with RSA SHA256
// FIXME: move to env var
const cert = fs.readFileSync('private-key.pem');  // get private key

module.exports = generate;

function generate() {
  const payload = {
    // issued at time
    iat: Math.floor(new Date() / 1000),
    // JWT expiration time
    exp: (Math.floor(new Date() / 1000) + 60) * 5,
    // Integration's GitHub identifier
    iss: process.env.INTEGRATION_ID
  };

  return jwt.sign(payload, cert, {algorithm: 'RS256'});
}

const fs = require('fs');
const process = require('process');
const jwt = require('jsonwebtoken');

const cert = process.env.PRIVATE_KEY || fs.readFileSync('private-key.pem');

module.exports = generate;

function generate() {
  const payload = {
    // issued at time
    iat: Math.floor(new Date() / 1000),
    // JWT expiration time
    exp: (Math.floor(new Date() / 1000) + 60) * 5,
    // Integration's GitHub identifier
    iss: process.env.INTEGRATION_ID
  };

  // sign with RSA SHA256
  return jwt.sign(payload, cert, {algorithm: 'RS256'});
}

Load private key from env if possible


import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, Redirect } from 'react-router';
import { syncReduxAndRouter } from 'redux-simple-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';
import createStore from './store';
import App from './app';
import Build from './build';
import Json from './json';
import Html from './html';
import forms from './forms';

const history = createBrowserHistory();
const store = createStore({});

syncReduxAndRouter(history, store);

function mapFormsToRoutes({section, component}) {
  return <Route path={section} component={component} />;
}

ReactDOM.render((
  <Provider store={store} >
    <Router history={history}>
      <Route path="/" component={App}>
        <Redirect from="" to="build" />
        <Route path="build" component={Build}>
          {
            forms.map(mapFormsToRoutes)
          }
        </Route>
        <Route path="output" component={Html}/>
        <Route path="json" component={Json}/>
      </Route>
    </Router>
  </Provider>
  ), document.getElementById('app'));

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, Redirect } from 'react-router';
import { syncReduxAndRouter } from 'redux-simple-router';
import createHashHistory from 'history/lib/createHashHistory';
import createStore from './store';
import App from './app';
import Build from './build';
import Json from './json';
import Html from './html';
import forms from './forms';

const history = createHashHistory();
const store = createStore({});

syncReduxAndRouter(history, store);

function mapFormsToRoutes({section, component}) {
  return <Route path={section} component={component} />;
}

ReactDOM.render((
  <Provider store={store} >
    <Router history={history}>
      <Redirect from="/" to="/build" />
      <Route path="/" component={App}>
        <Route path="build" component={Build}>
          {
            forms.map(mapFormsToRoutes)
          }
        </Route>
        <Route path="output" component={Html}/>
        <Route path="json" component={Json}/>

      </Route>
    </Router>
  </Provider>
  ), document.getElementById('app'));

Switch to hash-based history, fix redirect to /build on boot


exports.initialize = require('./Bootstrapper')
exports.dep        = require('./DependencySpec')
exports.events     = require('../sdk/Events')
exports.iterable   = require('../sdk/Iterable')
exports.decorators = require('./DecoratorManager')
exports.testable   = require('./Testable')

exports.bootstrap  = require('./Bootstrapper')
exports.dep        = require('./DependencySpec')
exports.events     = require('../sdk/Events')
exports.iterable   = require('../sdk/Iterable')
exports.decorators = require('./DecoratorManager')
exports.testable   = require('./Testable')

Update exports to match bootstrap naming convention


var Sequelize = require('sequelize'),
    _ = require('lodash');

module.exports = function(target) {
  if (target instanceof Sequelize.Model) {
    // Model
    createHook(target);
  } else {
    // Sequelize instance
    target.afterDefine(createHook);
  }
}

function createHook(model) {
   model.addHook('beforeFindAfterOptions', function(options) {
    if (options.role) {
      var role = options.role,
          attributes = options.attributes,
          includes = options.include;

      options.attributes = attrAccessible(model, role, attributes);
      cleanIncludesRecursive(includes, role);
    }
  });
}

function attrAccessible(model, role, attributes) {
  var attrsToReject = attrProtected(model, role);
  return rejectAttributes(attributes, attrsToReject);
}

function attrProtected(model, role) {
  return _.keys(_.pickBy(model.attributes, function(attr, name) {
    return !_.isUndefined(attr.access) && ( attr.access === false || attr.access[role] === false );
  }));
}

function rejectAttributes(attributes, attrsToRemove) {
  return _.reject(attributes, function(attr) {
    if (_.isArray(attr)) {
      attr = attr[1];
    }

    return _.includes(attrsToRemove, attr);
  });
}

function cleanIncludesRecursive(includes, role) {
  _.each(includes, function(include) {
    var model = include.model,
        attributes = include.attributes;

    include.attributes = attrAccessible(model, role, attributes);

    if (include.include) {
      cleanIncludesRecursive(include.include, role);
    }
  });
}

var Sequelize = require('sequelize'),
    _ = require('lodash');

module.exports = function(target) {
  if (target instanceof Sequelize.Model) {
    // Model
    createHook(target);
  } else {
    // Sequelize instance
    target.afterDefine(createHook);
  }
}

function createHook(model) {
   model.addHook('beforeFindAfterOptions', function(options) {
    if (options.role) {
      var role = options.role,
          attributes = options.attributes,
          includes = options.include;

      options.attributes = attrAccessible(model, role, attributes);
      cleanIncludesRecursive(includes, role);
    }
  });
}

function attrAccessible(model, role, attributes) {
  var attrsToReject = attrProtected(model, role);
  return rejectAttributes(attributes, attrsToReject);
}

function attrProtected(model, role) {
  return _.keys(_.pickBy(model.rawAttributes, function(attr, name) {
    return !_.isUndefined(attr.access) && ( attr.access === false || attr.access[role] === false );
  }));
}

function rejectAttributes(attributes, attrsToRemove) {
  return _.reject(attributes, function(attr) {
    if (_.isArray(attr)) {
      attr = attr[1];
    }

    return _.includes(attrsToRemove, attr);
  });
}

function cleanIncludesRecursive(includes, role) {
  _.each(includes, function(include) {
    var model = include.model,
        attributes = include.attributes;

    include.attributes = attrAccessible(model, role, attributes);

    if (include.include) {
      cleanIncludesRecursive(include.include, role);
    }
  });
}

Replace usage of deprecated model.attributes


$(function() {
    // When we're using HTTPS, use WSS too.
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    chatsock.onmessage = function(message) {
        var data = JSON.parse(message.data);
        $("#chat").append('
'
            + '' + data.timestamp + '	'
            + '' + data.handle + '	'
            + '' + data.message + ' 	'
        + '
');
    };

    $("#chatform").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
});

$(function() {
    // When we're using HTTPS, use WSS too.
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    var chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    chatsock.onmessage = function(message) {
        var data = JSON.parse(message.data);
        var chat = $("#chat")
        var ele = $('

')

        ele.append(
            $("	").text(data.timestamp)
        )
        ele.append(
            $("	").text(data.handle)
        )
        ele.append(
            $("	").text(data.message)
        )

        chat.append(ele)
    };

    $("#chatform").on("submit", function(event) {
        var message = {
            handle: $('#handle').val(),
            message: $('#message').val(),
        }
        chatsock.send(JSON.stringify(message));
        $("#message").val('').focus();
        return false;
    });
});

Fix XSS issue in demo


Template.roomView.helpers({
    room: function () {
        return Rooms.findOne({_id: Session.get('currentRoom')});
    },
    roomUsers: function () {
        var room = Rooms.findOne({_id: Session.get('currentRoom')});
        return Meteor.users.find({_id: {$in: room.users}});
    },
    currentRooms: function () {
        return Rooms.find({users: Meteor.userId()});
    },
    currentRoom: function () {
        return Session.get('currentRoom');
    },
    availableRooms: function () {
        return Rooms.find();
    }
});
Template.roomView.events({
    'click #loadMore': function (e) {
        Session.set('messageLimit', Session.get('messageLimit') + 20);
        e.preventDefault();
    }
});

Template.roomView.rendered = function () {
    Meteor.call('setSeen', Session.get('currentRoom'));
    Meteor.setTimeout(scrollChatToBottom, 100);
};
Template.roomView.created = function () {
    Deps.autorun(function () {
        Meteor.subscribe('messages', Session.get('currentRoom'), Session.get('messageLimit'));
        Meteor.subscribe('feedbackMessages', Session.get('currentRoom'));
    });
};

Template.roomView.helpers({
    room: function () {
        return Rooms.findOne({_id: Session.get('currentRoom')});
    },
    roomUsers: function () {
        var room = Rooms.findOne({_id: Session.get('currentRoom')});
        if(room) {
            return Meteor.users.find({_id: {$in: room.users}});
        }
        else{
            return [];
        }
    },
    currentRooms: function () {
        return Rooms.find({users: Meteor.userId()});
    },
    currentRoom: function () {
        return Session.get('currentRoom');
    },
    availableRooms: function () {
        return Rooms.find();
    }
});
Template.roomView.events({
    'click #loadMore': function (e) {
        Session.set('messageLimit', Session.get('messageLimit') + 20);
        e.preventDefault();
    }
});

Template.roomView.rendered = function () {
    Meteor.call('setSeen', Session.get('currentRoom'));
    Meteor.setTimeout(scrollChatToBottom, 100);
};
Template.roomView.created = function () {
    Deps.autorun(function () {
        Meteor.subscribe('messages', Session.get('currentRoom'), Session.get('messageLimit'));
        Meteor.subscribe('feedbackMessages', Session.get('currentRoom'));
    });
};

Handle room users case when not in room


var express = require('express');
var http = require('http');
var socketIO = require('socket.io');
var path = require('path');
var game = require('./game.js');

var app = express();
var server = http.Server(app);
var io = socketIO(server);

app.set('views', path.join(__dirname, 'templates'));
app.set('view engine', 'jade');

app.use(express.static('public'));

app.get('/', function(req, res) {
  var state0 = game.getInitialState()
  res.render('index', state0);
})

io.on('connection', function(socket){
  console.log('CONNECT', socket.id);
  socket.on('log on', function(name){
    console.log('LOG ON', name);
    socket.broadcast.emit('log on', name);
  })
  socket.on('log off', function(name) {
    console.log('LOG OFF', name);
    socket.broadcast.emit('log off', name);
  })
  socket.on('disconnect', function(){
    console.log('DISCONNECT', socket.id);
  });
});

server.listen(3000, function() {
  console.log("listening on port 3000");
});

var express = require('express');
var http = require('http');
var socketIO = require('socket.io');
var path = require('path');
var game = require('./game.js');

var app = express();
var server = http.Server(app);
var io = socketIO(server);

app.set('views', path.join(__dirname, 'templates'));
app.set('view engine', 'jade');

app.use(express.static('public'));

app.get('/', function(req, res) {
  var state0 = game.getInitialState()
  res.render('index', state0);
})

io.on('connection', function(socket){
  console.log('CONNECT', socket.id);
  socket.on('log on', function(name){
    console.log('LOG ON', name);
    socket.broadcast.emit('log on', name);
  })
  socket.on('log off', function(name) {
    console.log('LOG OFF', name);
    socket.broadcast.emit('log off', name);
  })
  socket.on('disconnect', function(){
    console.log('DISCONNECT', socket.id);
  });
  socket.on('card click', function(click){
    console.log('CARD CLICK', click.user, click.card);
  });
});

server.listen(3000, function() {
  console.log("listening on port 3000");
});

Handle incoming card click event with simple logger


"use strict";

const generate = require("./generate");
const log = require("./log");
const init = require("./init");
const program = require("commander");

module.exports = function() {
    program.version("0.0.1");

    program.command("generate")
        .description("Generate site.")
        .option("-v, --verbose", "Enable verbose logging.", log.increaseVerbosity)
        .action(generate.generate);

    program.command("init")
        .description("Initialize a new project.")
        .option("-v, --verbose", "Enable verbose logging.", log.increaseVerbosity)
        .action(init.init);

    program.parse(process.argv);
};

"use strict";

const generate = require("./generate");
const log = require("./log");
const init = require("./init");
const program = require("commander");
const version = require("../package.json").version;

module.exports = function() {
    program.version(version);

    program.command("generate")
        .description("Generate site.")
        .option("-v, --verbose", "Enable verbose logging.", log.increaseVerbosity)
        .action(generate.generate);

    program.command("init")
        .description("Initialize a new project.")
        .option("-v, --verbose", "Enable verbose logging.", log.increaseVerbosity)
        .action(init.init);

    program.parse(process.argv);
};

Make lerret -V return the actual version number.


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);

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.static(path.join(__dirname, 'public')));
});

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 dev logging, don't need it. Console.log like in the old days!


var http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World from iojs ' + process.version + '!\n');
}).listen(process.env.port);

const http = require('http');

http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end(`Hello World from iojs ${process.version}!\n`);
}).listen(process.env.port);

Use const and string template


const ifElse = require('1-liners/ifElse');
const isFunction = require('1-liners/isFunction');
const filter = require('1-liners/filter');
const compose = require('1-liners/compose');

const castBool = (val) => val === true;
const throwError = (msg) => () => { throw new Error(msg); };

const filterCurried = (filterFn) => ifElse(
  Array.isArray,
  (arr) => filter(compose(castBool, filterFn), arr),
  throwError('Filter expected an array')
);

export default ifElse(
  isFunction,
  filterCurried,
  throwError('Filter expected a function')
);

const ifElse = require('1-liners/ifElse');
const isFunction = require('1-liners/isFunction');
const filter = require('1-liners/filter');

const throwError = (msg) => () => { throw new Error(msg); };

const filterCurried = (filterFn) => ifElse(
  Array.isArray,
  (arr) => filter(filterFn, arr),
  throwError('Filter expected an array')
);

export default ifElse(
  isFunction,
  filterCurried,
  throwError('Filter expected a function')
);

Update logic to fixed test


/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

function createModuleDescription(name, exclude) {
	var result= {};
	result.name= name;
	var excludes = ['vs/css', 'vs/nls', 'vs/text'];
	if (Array.isArray(exclude) && exclude.length > 0) {
		excludes = excludes.concat(exclude);
	}
	result.exclude= excludes;
	return result;
}

function addInclude(config, include) {
	if (!config.include) {
		config.include = [];
	}
	config.include.push(include);
	return config;
}

exports.collectModules= function() {
	return [
		// Include the severity module into the base worker code since it is used by many languages
		// It can cause waterfall loading if one language excludes another language it depends on and
		// both use vs/base/common/severity
		addInclude(
			createModuleDescription('vs/editor/common/worker/editorWorkerServer', ['vs/base/common/worker/workerServer']),
			'vs/base/common/severity'
		),
		createModuleDescription('vs/editor/common/services/editorSimpleWorker'),
	];
};

/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

function createModuleDescription(name, exclude) {
	var result= {};
	result.name= name;
	var excludes = ['vs/css', 'vs/nls', 'vs/text'];
	if (Array.isArray(exclude) && exclude.length > 0) {
		excludes = excludes.concat(exclude);
	}
	result.exclude= excludes;
	return result;
}

function addInclude(config, include) {
	if (!config.include) {
		config.include = [];
	}
	config.include.push(include);
	return config;
}

exports.collectModules= function() {
	return [
		// Include the severity module into the base worker code since it is used by many languages
		// It can cause waterfall loading if one language excludes another language it depends on and
		// both use vs/base/common/severity
		addInclude(
			createModuleDescription('vs/editor/common/worker/editorWorkerServer', ['vs/base/common/worker/workerServer']),
			'vs/base/common/severity'
		),
		createModuleDescription('vs/editor/common/services/editorSimpleWorker', ['vs/base/common/worker/simpleWorker']),
	];
};

Exclude `simpleWorker` from `editorSimpleWorker` in bundling


import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { withKnobs, text, boolean, number, object } from '@kadira/storybook-addon-knobs';
import { setComposerStub } from 'react-komposer';
import PollButtons from '../poll_buttons.jsx';
import palette from '../../libs/palette';

storiesOf('core.PollButtons', module)
  .addDecorator(withKnobs)
  .add('default view', () => {
    const poll = object('poll', {
      _id: 'abc123',
      question: 'Ice Cream Flavors',
      options: [
        {
          name: 'Chocolate',
          votes: 10
        },
        {
          name: 'Vanilla',
          votes: 5
        },
        {
          name: 'Rocky Road',
          votes: 20
        }
      ]
    });
    const colorScale = palette([ 'tol', 'tol-rainbow' ], poll.options.length);
    return (
      <PollButtons
        poll={poll}
        colorScale={colorScale}
        vote={action('pollButtons-vote-clicked')}
      />
    );
  });

import React from 'react';
import { storiesOf, action } from '@kadira/storybook';
import { withKnobs, text, boolean, number, object } from '@kadira/storybook-addon-knobs';
import { setComposerStub } from 'react-komposer';
import PollButtons from '../poll_buttons.jsx';
import palette from '../../libs/palette';

storiesOf('core.PollButtons', module)
  .addDecorator(withKnobs)
  .add('default view', () => {
    const poll = object('poll', {
      _id: 'abc123',
      question: 'Ice Cream Flavors',
      options: [
        {
          name: 'Chocolate',
          votes: 10
        },
        {
          name: 'Vanilla',
          votes: 5
        },
        {
          name: 'Rocky Road',
          votes: 20
        }
      ]
    });
    const isLoggedIn = boolean('isLoggedIn', true);
    const colorScale = palette([ 'tol', 'tol-rainbow' ], poll.options.length);
    return (
      <PollButtons
        poll={poll}
        colorScale={colorScale}
        isLoggedIn={isLoggedIn}
        vote={action('pollButtons-vote-clicked')}
      />
    );
  });

Add isLoggedIn knob to story for pollButtons


/**
 * Copyright 2013-2020 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * 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.
 */
const chalk = require('chalk');

const packageJson = require('../package.json');
const { logger, toString, getCommandOptions, doneFactory } = require('./utils');
const EnvironmentBuilder = require('./environment-builder');

const env = EnvironmentBuilder.createDefaultBuilder().getEnvironment();

const command = process.argv[2];
const options = getCommandOptions(packageJson, process.argv.slice(3));
logger.info(chalk.yellow(`Executing ${command} on ${process.cwd()}`));
logger.info(chalk.yellow(`Options: ${toString(options)}`));
try {
    env.run(command, options, doneFactory());
} catch (e) {
    logger.error(e.message, e);
    process.exitCode = 1;
}

/**
 * Copyright 2013-2020 the original author or authors from the JHipster project.
 *
 * This file is part of the JHipster project, see https://www.jhipster.tech/
 * for more information.
 *
 * 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.
 */
const chalk = require('chalk');

const packageJson = require('../package.json');
const { logger, toString, getCommandOptions, doneFactory } = require('./utils');
const EnvironmentBuilder = require('./environment-builder');

const env = EnvironmentBuilder.createDefaultBuilder().getEnvironment();

const command = process.argv[2];
const options = getCommandOptions(packageJson, process.argv.slice(3));
logger.info(chalk.yellow(`Executing ${command} on ${process.cwd()}`));
logger.debug(chalk.yellow(`Options: ${toString(options)}`));
try {
    env.run(command, options, doneFactory());
} catch (e) {
    logger.error(e.message, e);
    process.exitCode = 1;
}

Change another options log from info to debug


module.exports = {
  "stories": [
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials"
  ],
  "core": {
    "builder": "webpack5"
  }
}

module.exports = {
  "stories": [
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials"
  ],
  "core": {
    "builder": "webpack5"
  },
  "webpackFinal": (config) => {
    config.resolve.fallback.crypto = false;
    return config;
  },
}

Add crypto to storybook fallbacks


'use strict';

angular.module('app').service('stdout', ['$window', function($window) {
	var callback = undefined;
	var websocket = undefined;

	this.subscribe = function(path, _callback) {
		callback = _callback;

		var proto = ($window.location.protocol == 'https:' ? 'wss' : 'ws');
		var route = [proto, "://", $window.location.host, '/api/feed/stdout/', path].join('');

		websocket = new WebSocket(route);
		websocket.onmessage = function(event) {
			if (callback != undefined) {
				callback(event.data);
			}
		};
		websocket.onclose = function(event) {
			console.log('websocket closed at '+path);
		};
	};

	this.unsubscribe = function() {
		callback = undefined;
		if (websocket != undefined) {
			console.log('unsubscribing websocket at '+websocket.url);
			websocket.close();
		}
	};
}]);

'use strict';

angular.module('app').service('stdout', ['$window', function($window) {
	var callback = undefined;
	var websocket = undefined;

	this.subscribe = function(path, _callback) {
		callback = _callback;

		var proto = ($window.location.protocol == 'https:' ? 'wss' : 'ws');
		var route = [proto, "://", $window.location.host, '/api/stream/stdout/', path].join('');

		websocket = new WebSocket(route);
		websocket.onmessage = function(event) {
			if (callback != undefined) {
				callback(event.data);
			}
		};
		websocket.onclose = function(event) {
			console.log('websocket closed at '+path);
		};
	};

	this.unsubscribe = function() {
		callback = undefined;
		if (websocket != undefined) {
			console.log('unsubscribing websocket at '+websocket.url);
			websocket.close();
		}
	};
}]);

Update API endpoint for websockets


const RasterAggregation = require('./raster-aggregation');
const VectorAggregation = require('./vector-aggregation');
const RASTER_AGGREGATION = 'RasterAggregation';
const VECTOR_AGGREGATION = 'VectorAggregation';

module.exports = class AggregationProxy {
    constructor (mapconfig, resolution = 256, threshold = 10e5, placement = 'centroid') {
        this.mapconfig = mapconfig;
        this.resolution = resolution;
        this.threshold = threshold;
        this.placement = placement;
        this.implementation = this._getAggregationImplementation();
    }

    _getAggregationImplementation () {
        let implementation = null;

        switch (this._getAggregationType()) {
            case VECTOR_AGGREGATION:
                implementation = new VectorAggregation(this.resolution, this.threshold, this.placement);
                break;
            case RASTER_AGGREGATION:
                implementation = new RasterAggregation(this.resolution, this.threshold, this.placement);
                break;
            default:
                throw new Error('Unsupported aggregation type');
        }

        return implementation;
    }

    _getAggregationType () {
        if (this.mapconfig.isVetorLayergroup()) {
            return VECTOR_AGGREGATION;
        }

        return RASTER_AGGREGATION;
    }

    sql () {
        return this.implementation.sql();
    }
};

const RasterAggregation = require('./raster-aggregation');
const VectorAggregation = require('./vector-aggregation');
const RASTER_AGGREGATION = 'RasterAggregation';
const VECTOR_AGGREGATION = 'VectorAggregation';

module.exports = class AggregationProxy {
    constructor (mapconfig, { resolution = 256, threshold = 10e5, placement = 'centroid', columns = {}} = {}) {
        this.mapconfig = mapconfig;
        this.resolution = resolution;
        this.threshold = threshold;
        this.placement = placement;
        this.columns = columns;
        this.implementation = this._getAggregationImplementation();
    }

    _getAggregationImplementation () {
        let implementation = null;

        switch (this._getAggregationType()) {
            case VECTOR_AGGREGATION:
                implementation = new VectorAggregation(this.resolution, this.threshold, this.placement, this.columns);
                break;
            case RASTER_AGGREGATION:
                implementation = new RasterAggregation(this.resolution, this.threshold, this.placement, this.columns);
                break;
            default:
                throw new Error('Unsupported aggregation type');
        }

        return implementation;
    }

    _getAggregationType () {
        if (this.mapconfig.isVetorLayergroup()) {
            return VECTOR_AGGREGATION;
        }

        return RASTER_AGGREGATION;
    }

    sql () {
        return this.implementation.sql();
    }
};

Add params to instantiate aggregation


import Buttons from './Buttons.react';
import Component from 'react-pure-render/component';
import DocumentTitle from 'react-document-title';
import List from './List.react';
import NewTodo from './NewTodo.react';
import React, {PropTypes} from 'react';
import fetch from '../../common/components/fetch';
import {fetchUserTodos} from '../../common/todos/actions';

// This decorator (higher order component) fetches todos both on client and
// server side. It's true isomorphic data fetching and rendering.
@fetch(fetchUserTodos)
export default class Page extends Component {

  static propTypes = {
    actions: PropTypes.object,
    msg: PropTypes.object,
    todos: PropTypes.object
  }

  render() {
    const {actions, msg: {todos: msg}, todos: {newTodo, list}} = this.props;

    return (
      <DocumentTitle title={msg.title}>
        <div className="todos-page">
          <NewTodo {...{actions, msg, newTodo}} />
          <List {...{actions, list, msg}} />
          <Buttons clearAllEnabled={list.size > 0} {...{actions, msg}} />
        </div>
      </DocumentTitle>
    );
  }

}

import Buttons from './Buttons.react';
import Component from 'react-pure-render/component';
import DocumentTitle from 'react-document-title';
import List from './List.react';
import NewTodo from './NewTodo.react';
import React, {PropTypes} from 'react';
import fetch from '../../common/components/fetch';
import {fetchUserTodos} from '../../common/todos/actions';

// This decorator (higher order component) fetches todos both in browser and
// on server side. It's true isomorphic data fetching and rendering.
@fetch(fetchUserTodos)
export default class Page extends Component {

  static propTypes = {
    actions: PropTypes.object,
    msg: PropTypes.object,
    todos: PropTypes.object
  }

  render() {
    const {actions, msg: {todos: msg}, todos: {newTodo, list}} = this.props;

    return (
      <DocumentTitle title={msg.title}>
        <div className="todos-page">
          <NewTodo {...{actions, msg, newTodo}} />
          <List {...{actions, list, msg}} />
          <Buttons clearAllEnabled={list.size > 0} {...{actions, msg}} />
        </div>
      </DocumentTitle>
    );
  }

}

Change mention of client to browser to match src structure