const groupRe = /^((:?\w|\-|,|, )+):\s*/i
    , reverts = require('./reverts')

function toGroups (summary) {
  summary = reverts.cleanSummary(summary)
  var m = summary.match(groupRe)
  return (m && m[1]) || ''
}

function cleanSummary (summary) {
  return (summary || '').replace(groupRe, '')
}

function isReleaseCommit (summary) {
  return /^Working on v?\d{1,2}\.\d{1,3}\.\d{1,3}$/.test(summary)
         || /^\d{4}-\d{2}-\d{2},? Version \d{1,2}\.\d{1,3}\.\d{1,3} (["'][A-Za-z ]+["'] )?\((Stable|LTS|Maintenance)\)/.test(summary)
         || /^\d{4}-\d{2}-\d{2},? io.js v\d{1,2}\.\d{1,3}\.\d{1,3} Release/.test(summary)
         || /^\d+\.\d+\.\d+$/.test(summary) // `npm version X` style commit
}

module.exports.toGroups        = toGroups
module.exports.cleanSummary    = cleanSummary
module.exports.isReleaseCommit = isReleaseCommit

const groupRe = /^((:?\w|\-|,|, )+):\s*/i
    , reverts = require('./reverts')

function toGroups (summary) {
  summary = reverts.cleanSummary(summary)
  var m = summary.match(groupRe)
  return (m && m[1]) || ''
}

function cleanSummary (summary) {
  return (summary || '').replace(groupRe, '')
}

function isReleaseCommit (summary) {
  return /^Working on v?\d{1,2}\.\d{1,3}\.\d{1,3}$/.test(summary)
         || /^\d{4}-\d{2}-\d{2},? Version \d{1,2}\.\d{1,3}\.\d{1,3} (["'][A-Za-z ]+["'] )?\((Current|Stable|LTS|Maintenance)\)/.test(summary)
         || /^\d{4}-\d{2}-\d{2},? io.js v\d{1,2}\.\d{1,3}\.\d{1,3} Release/.test(summary)
         || /^\d+\.\d+\.\d+$/.test(summary) // `npm version X` style commit
}

module.exports.toGroups        = toGroups
module.exports.cleanSummary    = cleanSummary
module.exports.isReleaseCommit = isReleaseCommit

Rename Node.js "Stable" releases to "Current"


require("./stylesheets/main.less");
var settings = require("./settings");

var commands = codebox.require("core/commands");

var manager = new codebox.tabs.Manager({
    tabMenu: false
});
manager.$el.addClass("component-panels");

// Add tabs to grid
codebox.app.grid.addView(manager, {
    width: 20,
    at: 0
});

// Render the tabs manager
manager.render();

// Toggle panels display
commands.register({
    id: "view.panels.toggle",
    title: "View: Toggle Side Bar",
    run: function() {
        settings.data.set("visible", !settings.data.get("visible"));
        codebox.settings.save();
    }
});

// Update visibility
settings.data.on("change:visible", function() {
    manager._gridOptions.enabled = settings.data.get("visible");
    codebox.app.grid.update();
});

// Make the tab manager global
codebox.panels = manager;

require("./stylesheets/main.less");
var settings = require("./settings");

var commands = codebox.require("core/commands");

var manager = new codebox.tabs.Manager({
    tabMenu: false
});
manager.$el.addClass("component-panels");

// Add tabs to grid
codebox.app.grid.addView(manager, {
    width: 20,
    at: 0
});

// Render the tabs manager
manager.render();

// Toggle panels display
commands.register({
    id: "view.panels.toggle",
    title: "View: Toggle Side Bar",
    run: function() {
        settings.data.set("visible", !settings.data.get("visible"));
        codebox.settings.save();
    }
});

// Update visibility
settings.data.on("change:visible", function() {
    manager._gridOptions.enabled = settings.data.get("visible");
    codebox.app.grid.update();
});

// Add to View menu
if (codebox.menubar) {
    codebox.menubar.createMenu("view", {
        caption: "Toggle Side Bar",
        command: "view.panels.toggle"
    });
}

// Make the tab manager global
codebox.panels = manager;

Add command in view menu


import 'babel-polyfill';

const window = (typeof window !== 'undefined') ? window : {};

// Default config values.
const defaultConfig = {
    loggingFunction: () => true,
    loadInWorker: true, // FIXME cambia il nome
};

// Config used by the module.
const config = {};

// ***** Private functions *****
const formatError = (error = {}) => error;

// Public function.
const funcExecutor = (funcToCall, args = [], scope = undefined) => {
    try {
        funcToCall.apply(scope, ...args);
    } catch (e) {
        // TODO trova modo per fare la compose nativa
        config.loggingFunction(formatError(e));

        throw e;
    }
};

// FIXME capire se è permesso avere la window come default
const attachGlobalHandler = (scope = window) => {
    scope.onerror = () => {
        // TODO trova modo per fare la compose nativa
        config.loggingFunction(formatError({ ...arguments }));

        return false;
    };
};

export default function LogIt(userConfig = defaultConfig) {
    Object.assign(config, userConfig);

    return {
        funcExecutor,
        attachGlobalHandler,
    };
}

import 'babel-polyfill';

import Catcher from './catcher';
import Logger from './logger';

// Default config values.
const defaultConfig = {
    scope: (typeof window !== 'undefined') ? window : {},
    loggingFunction: () => true,
    useWorker: true,
    errorBuffer: 5,
};

// Config used by the module.
let config = {};

const sendErrorToLogger = formattedError => formattedError;

export default function LogIt(userConfig = {}) {
    // TODO npm i --save-dev babel-preset-stage-2
    config = { ...defaultConfig, ...userConfig };

    return {
        ...Catcher,
    };
}

Move cathing functions to catch file


import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route } from 'react-router-dom';
import promise from 'redux-promise'

import PostsIndex from './components/posts_index';
import PostsNew from './components/posts_new';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(promise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <BrowserRouter>
      <div>
        <Route path="/" component={PostsIndex} />
        <Route path="/posts/new" component={PostsNew} />
      </div>
    </BrowserRouter>
  </Provider>
  , document.querySelector('.container'));

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import promise from 'redux-promise'

import PostsIndex from './components/posts_index';
import PostsNew from './components/posts_new';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(promise)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <BrowserRouter>
      <div>
        <Switch>
          <Route path="/posts/new" component={PostsNew} />
          <Route path="/" component={PostsIndex} />
        </Switch>
      </div>
    </BrowserRouter>
  </Provider>
  , document.querySelector('.container'));

Fix bug by adding Switch to the routes and more specific routes shown first in code


'use strict';

var Promise = require('bluebird');
var sinon   = require('sinon');

function thenable (promiseFactory) {
  return Object.keys(Promise.prototype)
    .filter(function (method) {
      return Promise.prototype.hasOwnProperty(method) && method !== 'then';
    })
    .reduce(function (acc, method) {
      acc[method] = function () {
        var args = arguments;
        var promise = this.then();
        return promise[method].apply(promise, args);
      };
      return acc;
    },
    {
      then: function (resolve, reject) {
        return promiseFactory().then(resolve, reject);
      }
    });
}

function resolves (value) {
  /*jshint validthis:true */
  return this.returns(thenable(function () {
    return new Promise(function (resolve) {
      resolve(value);
    });
  }));
}

sinon.stub.resolves = resolves;
sinon.behavior.resolves = resolves;

function rejects (err) {
  if (typeof err === 'string') {
    err = new Error(err);
  }
  /*jshint validthis:true */
  return this.returns(thenable(function () {
    return new Promise(function (resolve, reject) {
      reject(err);
    });
  }));
}

sinon.stub.rejects = rejects;
sinon.behavior.rejects = rejects;

module.exports = function (_Promise_) {
  if (typeof _Promise_ !== 'function') {
    throw new Error('A Promise constructor must be provided');
  }
  else {
    Promise = _Promise_;
  }
  return sinon;
};

'use strict';

var Promise = require('bluebird');
var sinon   = require('sinon');

function thenable (promiseFactory) {
  return Object.getOwnPropertyNames(Promise.prototype)
    .filter(function (method) {
      return method !== 'then';
    })
    .reduce(function (acc, method) {
      acc[method] = function () {
        var args = arguments;
        var promise = this.then();
        return promise[method].apply(promise, args);
      };
      return acc;
    },
    {
      then: function (resolve, reject) {
        return promiseFactory().then(resolve, reject);
      }
    });
}

function resolves (value) {
  /*jshint validthis:true */
  return this.returns(thenable(function () {
    return new Promise(function (resolve) {
      resolve(value);
    });
  }));
}

sinon.stub.resolves = resolves;
sinon.behavior.resolves = resolves;

function rejects (err) {
  if (typeof err === 'string') {
    err = new Error(err);
  }
  /*jshint validthis:true */
  return this.returns(thenable(function () {
    return new Promise(function (resolve, reject) {
      reject(err);
    });
  }));
}

sinon.stub.rejects = rejects;
sinon.behavior.rejects = rejects;

module.exports = function (_Promise_) {
  if (typeof _Promise_ !== 'function') {
    throw new Error('A Promise constructor must be provided');
  }
  else {
    Promise = _Promise_;
  }
  return sinon;
};

Use Object.getOwnPropertyNames for compatibility with native promises


function createDynamicFunction(customAction) {
    return Function('action', 'return function (){ return action.apply(this, [...arguments]) };')(customAction);
}

function formatFunctionName(type) {
    let formattedName = '';

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    type.split('_').map((val, i) => {
        if (i === 0) {
            formattedName += val.toLowerCase();
        } else {
            formattedName += capitalizeFirstLetter(val.toLowerCase());
        }

        return true;
    });

    return formattedName;
}

function generalFactory(type, payloadTranslator) {
    return function nomeDaSostituire(data) {
        const action = {
            type,
        };

        if (data) {
            switch (typeof payloadTranslator) {
                case 'function':
                    action.payload = payloadTranslator(data);
                    break;
                default:
                    action.payload = data;
                    break;
            }
        }

        return action;
    };
}

module.exports = function actionsCreatorFactory(actionsConfig) {
    const funcToExport = {};

    actionsConfig.map((config) => {
        let type = null;
        let payload = null;

        if (typeof config === 'string') {
            type = config;
        } else {
            type = config.type;
            payload = config.payload;
        }

        const functionName = formatFunctionName(type);

        const customFunction = generalFactory(type, payload);
        const customStringFunction = createDynamicFunction(customFunction);

        funcToExport[functionName] = customStringFunction;

        return true;
    });

    return funcToExport;
};

function formatFunctionName(type) {
    let formattedName = '';

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    type.split('_').map((val, i) => {
        if (i === 0) {
            formattedName += val.toLowerCase();
        } else {
            formattedName += capitalizeFirstLetter(val.toLowerCase());
        }

        return true;
    });

    return formattedName;
}

function generalFactory(type, payloadTranslator) {
    return function nomeDaSostituire(data) {
        const action = {
            type,
        };

        if (data) {
            switch (typeof payloadTranslator) {
                case 'function':
                    action.payload = payloadTranslator(data);
                    break;
                default:
                    action.payload = data;
                    break;
            }
        }

        return action;
    };
}

module.exports = function actionsCreatorFactory(actionsConfig) {
    const funcToExport = {};

    actionsConfig.map((config) => {
        let type = null;
        let payload = null;

        if (typeof config === 'string') {
            type = config;
        } else {
            type = config.type;
            payload = config.payload;
        }

        const functionName = formatFunctionName(type);

        const customFunction = generalFactory(type, payload);
        const customStringFunction = customFunction;

        funcToExport[functionName] = customStringFunction;

        return true;
    });

    return funcToExport;
};

Remove not useful function creator


let possibilites = 1;
for (let i = 53; i >= 48; i--) {
    possibilites *= i;
}
console.log('The odds are %d to 1', possibilites);

Use standard JS indent width


var Timer = (function(Event, Util) {
  'use strict';

  // Internal constants for the various timer states.
  var Waiting = 0, Inspecting = 1, Ready = 2, Running = 3, Stopped = 4;

  var state = Waiting;
  var startTime = undefined, endTime = undefined, solveTime = undefined;
  var intervalID = undefined;

  function isWaiting() { return state === Waiting; }
  function isReady() { return state === Ready; }
  function isRunning() { return state === Running; }

  function onWaiting() {
    endTime = undefined;
  }

  function onRunning() {
    startTime = Util.getMilli();
    intervalID = Util.setInterval(runningEmitter, 100);
  }

  function onStopped() {
    endTime = Util.getMilli();
    Util.clearInterval(intervalID);
    setState(Waiting);
  }

  function setState(new_state) {
    state = new_state;
    switch(state) {
    case Waiting: onWaiting(); break;
    case Running: onRunning(); break;
    case Stopped: onStopped(); break;
    }
  }

  function runningEmitter() {
    Event.emit("timer/running");
  }

  function triggerDown() {
    if (isWaiting()) {
      setState(Ready);
    } else if (isRunning()) {
      setState(Stopped);
    }
  }

  function triggerUp() {
    if (isReady()) {
      setState(Running);
    }
  }

  function getCurrent() {
    return (endTime || Util.getMilli()) - startTime;
  }

  return {
    triggerDown: triggerDown,
    triggerUp: triggerUp,
    getCurrent: getCurrent
  };
});

if (typeof module !== 'undefined')
  module.exports = Timer;

var Timer = (function(Event, Util) {
  'use strict';

  // Internal constants for the various timer states.
  var Waiting = 0, Inspecting = 1, Ready = 2, Running = 3, Stopped = 4;

  var state = Waiting;
  var startTime, endTime, solveTime;
  var intervalID;

  function isWaiting() { return state === Waiting; }
  function isReady() { return state === Ready; }
  function isRunning() { return state === Running; }

  function onWaiting() {
    endTime = undefined;
  }

  function onRunning() {
    startTime = Util.getMilli();
    intervalID = Util.setInterval(runningEmitter, 100);
  }

  function onStopped() {
    endTime = Util.getMilli();
    Util.clearInterval(intervalID);
    setState(Waiting);
  }

  function setState(new_state) {
    state = new_state;
    switch(state) {
    case Waiting: onWaiting(); break;
    case Running: onRunning(); break;
    case Stopped: onStopped(); break;
    }
  }

  function runningEmitter() {
    Event.emit("timer/running");
  }

  function triggerDown() {
    if (isWaiting()) {
      setState(Ready);
    } else if (isRunning()) {
      setState(Stopped);
    }
  }

  function triggerUp() {
    if (isReady()) {
      setState(Running);
    }
  }

  function getCurrent() {
    return (endTime || Util.getMilli()) - startTime;
  }

  return {
    triggerDown: triggerDown,
    triggerUp: triggerUp,
    getCurrent: getCurrent
  };
});

if (typeof module !== 'undefined')
  module.exports = Timer;

Remove explicit assignment to undefined.


const Environment = require('../environment')
const { dev_server } = require('../config')
const assetHost = require('../asset_host')
const webpack = require('webpack')

module.exports = class extends Environment {
  constructor() {
    super()

    if (dev_server.hmr) {
      this.plugins.set('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
      this.plugins.set('NamedModules', new webpack.NamedModulesPlugin())
    }
  }

  toWebpackConfig() {
    const result = super.toWebpackConfig()
    if (dev_server.hmr) {
      result.output.filename = '[name]-[hash].js'
    }
    result.output.pathinfo = true
    result.devtool = 'cheap-eval-source-map'
    result.devServer = {
      host: dev_server.host,
      port: dev_server.port,
      https: dev_server.https,
      hot: dev_server.hmr,
      contentBase: assetHost.path,
      publicPath: assetHost.publicPath,
      clientLogLevel: 'none',
      compress: true,
      historyApiFallback: true,
      headers: {
        'Access-Control-Allow-Origin': '*'
      },
      watchOptions: {
        ignored: /node_modules/
      },
      stats: {
        errorDetails: true
      }
    }
    return result
  }
}

const Environment = require('../environment')
const { dev_server } = require('../config')
const assetHost = require('../asset_host')
const webpack = require('webpack')

module.exports = class extends Environment {
  constructor() {
    super()

    if (dev_server.hmr) {
      this.plugins.set('HotModuleReplacement', new webpack.HotModuleReplacementPlugin())
      this.plugins.set('NamedModules', new webpack.NamedModulesPlugin())
    }
  }

  toWebpackConfig() {
    const result = super.toWebpackConfig()
    if (dev_server.hmr) {
      result.output.filename = '[name]-[hash].js'
    }
    result.output.pathinfo = true
    result.devtool = 'cheap-eval-source-map'
    result.devServer = {
      host: dev_server.host,
      port: dev_server.port,
      https: dev_server.https,
      hot: dev_server.hmr,
      contentBase: assetHost.path,
      publicPath: assetHost.publicPath,
      clientLogLevel: 'none',
      compress: true,
      historyApiFallback: true,
      headers: {
        'Access-Control-Allow-Origin': '*'
      },
      overlay: true,
      watchContentBase: true,
      watchOptions: {
        ignored: /node_modules/
      },
      stats: {
        errorDetails: true
      }
    }
    return result
  }
}

Add overlay option for debugging


var exec = require('cordova/exec');

module.exports = {
    splashscreen: {
        win: null,

        show: function() {
            win= window.open('splashscreen.html');
        },

        hide: function() {
            win.close();
            win = null;
        }
    }
};

require("cordova/tizen/commandProxy").add("SplashScreen", module.exports);

( function() {

win = null;

module.exports = {
    show: function() {
        if ( win === null ) {
            win = window.open('splashscreen.html');
        }
    },

    hide: function() {
        if ( win !== null ) {
            win.close();
            win = null;
        }
    }
};

require("cordova/tizen/commandProxy").add("SplashScreen", module.exports);

})();

Correct structure, and only ever create one splashscreen window.


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require_tree .
//= require bootstrap

// Replace link targets with JavaScript handlers to prevent iOS fullscreen web
// app from opening links in extra browser app
if (navigator.userAgent.match(/(ipod|iphone|ipad)/i)) {
	$(function() {
		$('body a[href]').click(function(e) {
	  	e.preventDefault();
	    top.location.href = this;
	  });
	});
}

//hide notification bars after a few seconds
$('.alert').delay(10000).fadeOut('slow');

Hide notification bars after a few seconds.


  /*
      VENDOR
  */

  require( "material-design-lite" );

  /*
      APPLICATION
  */

  const { initTerms } = require( "./term.js" );
  initTerms();

  /*
      VENDOR
  */

  require( "material-design-lite" );

  import "phoenix_html"

  /*
      APPLICATION
  */

  const { initTerms } = require( "./term.js" );
  initTerms();

Add import of phoenix_html back


import React, { useRef, useEffect, useState } from 'react';
import uuid from 'uuid/v4';
import { attempt } from 'lodash-es';
import useModifiedProps from '../UseModifiedProps';
import useAxis from '../UseAxis';

export default function usePlotBandLineLifecycle(props, plotType) {
  const { id = uuid, axisId, children, ...rest } = props;

  const axis = useAxis(axisId);
  const idRef = useRef();
  const [plotbandline, setPlotbandline] = useState(null);
  const modifiedProps = useModifiedProps(rest);

  useEffect(() => {
    if (!axis) return;
    if (!plotbandline || modifiedProps !== false) {
      if (!plotbandline) {
        idRef.current = typeof id === 'function' ? id() : id;
      }
      const myId = idRef.current;
      const opts = {
        id: myId,
        ...rest
      };

      if (plotbandline) axis.removePlotBandOrLine(idRef.current);
      axis.addPlotBandOrLine(opts, plotType);
      setPlotbandline({
        id: myId,
        getPlotBandLine: () => {
          const plotbandlineObject = axis.object.plotLinesAndBands.find(
            plb => plb.id === myId
          );
          return plotbandlineObject;
        }
      });
    }
  });

  useEffect(() => {
    return () => {
      attempt(axis.removePlotBandOrLine, idRef.current);
    };
  }, []);

  return plotbandline;
}

import React, { useRef, useEffect, useState } from 'react';
import uuid from 'uuid/v4';
import { attempt } from 'lodash-es';
import useModifiedProps from '../UseModifiedProps';
import useAxis from '../UseAxis';

export default function usePlotBandLineLifecycle(props, plotType) {
  const { id = uuid, axisId, children, ...rest } = props;

  const axis = useAxis(axisId);
  const idRef = useRef();
  const [plotbandline, setPlotbandline] = useState(null);
  const modifiedProps = useModifiedProps(rest);

  useEffect(() => {
    if (!axis) return;
    if (!plotbandline || modifiedProps !== false) {
      if (!plotbandline) {
        idRef.current = typeof id === 'function' ? id() : id;
      }
      const myId = idRef.current;
      const opts = {
        id: myId,
        ...rest
      };

      if (plotbandline) axis.removePlotBandOrLine(idRef.current);
      axis.addPlotBandOrLine(opts, plotType);
      setPlotbandline({
        id: myId,
        getPlotBandLine: () => {
          if (axis && axis.object && axis.object.plotLinesAndBands) {
            const plotbandlineObject = axis.object.plotLinesAndBands.find(
              plb => plb.id === myId
            );
            return plotbandlineObject;
          }
        }
      });
    }
  });

  useEffect(() => {
    return () => {
      attempt(axis.removePlotBandOrLine, idRef.current);
    };
  }, []);

  return plotbandline;
}

Fix plotband label unmount crashing


var fs = require("fs");
var path = require("path");

var Helper = module.exports = {
	getConfig: function () {
		var filename = process.env.SHOUT_CONFIG;
		if(!filename || !fs.exists(filename)) {
			filename = this.resolveHomePath("config.js");
			if(!fs.exists(filename)) {
				filename = path.resolve(__dirname, "..", "config");
			}
		}
		return require(filename);
	},

	getHomeDirectory: function () {
		return (
			(process.env.SHOUT_CONFIG && fs.exists(process.env.SHOUT_CONFIG) && this.getConfig().home)
			|| process.env.SHOUT_HOME
			|| path.resolve(process.env.HOME, ".shout")
		);
	},

	resolveHomePath: function () {
		var fragments = [ Helper.HOME ].concat([].slice.apply(arguments));
		return path.resolve.apply(path, fragments);
	}
};

Helper.HOME = Helper.getHomeDirectory()

var fs = require("fs");
var path = require("path");

var Helper = module.exports = {
	getConfig: function () {
		var filename = process.env.SHOUT_CONFIG;
		if(!filename || !fs.existsSync(filename)) {
			filename = this.resolveHomePath("config.js");
			if(!fs.existsSync(filename)) {
				filename = path.resolve(__dirname, "..", "config");
			}
		}
		return require(filename);
	},

	getHomeDirectory: function () {
		return (
			(process.env.SHOUT_CONFIG && fs.existsSync(process.env.SHOUT_CONFIG) && this.getConfig().home)
			|| process.env.SHOUT_HOME
			|| path.resolve(process.env.HOME, ".shout")
		);
	},

	resolveHomePath: function () {
		var fragments = [ Helper.HOME ].concat([].slice.apply(arguments));
		return path.resolve.apply(path, fragments);
	}
};

Helper.HOME = Helper.getHomeDirectory()

Fix fs.exists to existsSync where necessary


module.exports = (model, dispatch) => {
  const root = document.createElement('div');

  if (model.channelOnEdit === null) {
    return root;
  }

  const c = model.channelOnEdit;
  const title = model.channels[c].title;

  const row = document.createElement('div');
  row.classList.add('row');
  row.classList.add('row-input');

  const form = document.createElement('form');

  const text = document.createElement('input');
  text.type = 'text';
  text.value = title;

  form.appendChild(text);

  const okBtn = document.createElement('button');
  okBtn.innerHTML = 'OK';
  okBtn.addEventListener('click', ev => {
    dispatch({
      type: 'EDIT_CHANNEL_TITLE',
      channel: c,
      title: text.value
    });
  });
  form.appendChild(okBtn);

  row.appendChild(form);
  root.appendChild(row);

  return root;
}

module.exports = (model, dispatch) => {
  const root = document.createElement('div');

  if (model.channelOnEdit === null) {
    return root;
  }

  const c = model.channelOnEdit;
  const title = model.channels[c].title;

  const row = document.createElement('div');
  row.classList.add('row');
  row.classList.add('row-input');

  const form = document.createElement('form');

  const text = document.createElement('input');
  text.type = 'text';
  text.value = title;
  form.appendChild(text);

  const okBtn = document.createElement('button');
  okBtn.type = 'button';
  okBtn.innerHTML = 'OK';
  form.appendChild(okBtn);

  row.appendChild(form);
  root.appendChild(row);

  // Events

  setTimeout(() => {
    text.focus();
  }, 200);

  form.addEventListener('submit', ev => {
    ev.preventDefault();
    dispatch({
      type: 'EDIT_CHANNEL_TITLE',
      channel: c,
      title: text.value
    });
  });

  okBtn.addEventListener('click', ev => {
    dispatch({
      type: 'EDIT_CHANNEL_TITLE',
      channel: c,
      title: text.value
    });
  });

  return root;
}

Enable form submit by pressing enter


Kadira = {};
Kadira.options = __meteor_runtime_config__.kadira;

if(Kadira.options && Kadira.options.endpoint) {
  Kadira.syncedDate = new Ntp(Kadira.options.endpoint);
  Kadira.syncedDate.sync();
}

/**
 * Send error metrics/traces to kadira server
 * @param  {Object} payload Contains browser info and error traces
 */
Kadira.sendErrors = function (errors) {
  var retryCount = 0;
  var endpoint = Kadira.options.endpoint + '/errors';
  var retry = new Retry({
    minCount: 0,
    baseTimeout: 1000*5,
    maxTimeout: 1000*60,
  });

  var payload = {
    errors: JSON.stringify(errors)
  };

  tryToSend();

  function tryToSend() {
    if(retryCount < 5) {
      retry.retryLater(retryCount++, sendPayload);
    } else {
      console.warn('Error sending error traces to kadira server');
    }
  }

  function sendPayload () {
    $.ajax({
      url: endpoint,
      data: payload,
      crossDomain: true,
      error: tryToSend
    });
  }
}

Kadira.getBrowserInfo = function () {
  return {
    browser: window.navigator.userAgent,
    userId: Meteor.userId,
    url: location.href
  };
}

Kadira = {};
Kadira.options = __meteor_runtime_config__.kadira;

if(Kadira.options && Kadira.options.endpoint) {
  Kadira.syncedDate = new Ntp(Kadira.options.endpoint);
  Kadira.syncedDate.sync();
}

/**
 * Send error metrics/traces to kadira server
 * @param  {Object} payload Contains browser info and error traces
 */
Kadira.sendErrors = function (errors) {
  var retryCount = 0;
  var endpoint = Kadira.options.endpoint + '/errors';
  var retry = new Retry({
    minCount: 0,
    baseTimeout: 1000*5,
    maxTimeout: 1000*60,
  });

  var payload = {
    errors: JSON.stringify(errors)
  };

  tryToSend();

  function tryToSend() {
    if(retryCount < 5) {
      retry.retryLater(retryCount++, sendPayload);
    } else {
      console.warn('Error sending error traces to kadira server');
    }
  }

  function sendPayload () {
    $.ajax({
      url: endpoint,
      data: payload,
      jsonp: 'callback',
      dataType: 'jsonp',
      error: tryToSend
    });
  }
}

Kadira.getBrowserInfo = function () {
  return {
    browser: window.navigator.userAgent,
    userId: Meteor.userId,
    url: location.href
  };
}

Send data using jsonp instead of cors


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

describe('the program', function () {
    it('can handle the truth', function () {
        expect(true).to.equal(true);
    });

});

const {expect} = require('chai');

describe('the program', function () {
    it('can handle the truth', function () {
        expect(true).to.equal(true);
    });

});

Rewrite require to ES6 destructuring


import React from 'react';
import ReactDOM from 'react-dom';
import App from './app.setup.js';
import $ from 'jquery';

export default function setup() {
  const component = ReactDOM.render(<App />,
                                    document.getElementById('test-area'));

  const $component = $(ReactDOM.findDOMNode(component));

  return $component;
}

afterEach(function() {
  ReactDOM.unmountComponentAtNode(document.getElementById('test-area'));
});

Clean up the DOM between tests


import React from 'react';
import styles from "../css/App.css";

export class PlayerScoreComponent extends React.Component {

    /**
     * Constructor
     * @param props
     */
    constructor(props) {
        super(props);
        this.state = {
            score: 0
        }
    }

    updateScore = () => {
        let score = parseInt(this.refs.score.value);
        if (Number.isInteger(score)) {
            this.setState({score: this.state.score + score});
        }
    };

    render() {
        return (

                    <input type="number" className="form-control" ref="score" />

                    <button className="btn btn-default" type="button"
                            onClick={score => this.updateScore()}>{this.props.player.name} - {this.state.score}</button>

        );
    }
}

import React from 'react';
import styles from "../css/App.css";

export class PlayerScoreComponent extends React.Component {

    /**
     * Constructor
     * @param props
     */
    constructor(props) {
        super(props);
        this.state = {
            score: 0,
            history: []
        }
    }

    updateScore = () => {
        let score = parseInt(this.refs.score.value);
        if (Number.isInteger(score)) {
            this.setState({score: this.state.score + score});
            let history = this.state.history;
            history.push(score);
            this.setState({history: history});
        }
    };

    undo = () => {
        let lastValue = this.state.history.slice(-1)[0];
        if (Number.isInteger(parseInt(lastValue))) {
            this.state.history.pop();
            this.setState({score: this.state.score - lastValue});
        }
    }

    render() {
        return (

                        <button className="btn btn-warning" type="button"
                                onClick={score => this.undo()}>Undo</button>

                    <input type="number" className="form-control" ref="score" />

                        <button className="btn btn-success" type="button"
                                onClick={score => this.updateScore()}>{this.props.player.name} - {this.state.score}</button>

        );
    }
}

Undo functionality. In case you typed the wrong number...


/**
 * Checks if "value" is the language type of "Object".
 * @param {*} value The value to check.
 * @returns {boolean} Returns true if "value" is an object, else false.
 */
function isObject(value) {
    var type = typeof value;
    return value && (type === 'function' || type === 'object' || false);
}

/**
 * Checks if "value" is the language type of "Object".
 * @param {*} value The value to check.
 * @returns {boolean} Returns true if "value" is an object, else false.
 */
function isObject(value) {
    var type = typeof value;
    return !!value && (type === 'function' || type === 'object' || false);
}

Fix return value for undefined parameter


import { registerMigration } from './migrationUtils';
import { forEachDocumentBatchInCollection } from '../queryUtil.js';
import { LWEvents } from '../../lib/collections/lwevents'
import { ReadStatuses } from '../../lib/collections/readStatus'

registerMigration({
  name: "denormalizeReadStatus",
  idempotent: true,
  action: async () => {
    forEachDocumentBatchInCollection({
      collection: LWEvents,
      batchSize: 10000,
      filter: {name: "post-view"},
      callback: (postViews) => {
        const updates = postViews.map(view => ({
          updateOne: {
            filter: {
              postId: view.docmentId,
              userId: view.userId,
            },
            update: {
              $max: {
                lastUpdated: view.createdAt,
              },
              $set: {
                isRead: true
              },
            },
            upsert: true,
          }
        }));
        ReadStatuses.rawCollection().bulkWrite(updates);
      }
    })
  }
});

import { registerMigration } from './migrationUtils';
import { forEachDocumentBatchInCollection } from '../queryUtil.js';
import { LWEvents } from '../../lib/collections/lwevents'
import { ReadStatuses } from '../../lib/collections/readStatus/collection.js'

registerMigration({
  name: "denormalizeReadStatus",
  idempotent: true,
  action: async () => {
    forEachDocumentBatchInCollection({
      collection: LWEvents,
      batchSize: 10000,
      filter: {name: "post-view"},
      callback: (postViews) => {
        const updates = postViews.map(view => ({
          updateOne: {
            filter: {
              postId: view.docmentId,
              userId: view.userId,
            },
            update: {
              $max: {
                lastUpdated: view.createdAt,
              },
              $set: {
                isRead: true
              },
            },
            upsert: true,
          }
        }));
        ReadStatuses.rawCollection().bulkWrite(updates);
      }
    })
  }
});

Fix broken import in migraiton script


var path = require("path");

module.exports = {
    id: "nodejs",
    name: "Node.JS",

    detector: path.resolve(__dirname, "detector.sh"),
    runner: [
        {
            id: "run",
            script: path.resolve(__dirname, "run.sh")
        }
    ],

    ignoreRules: [
        "/node_modules"
    ]
};

var path = require("path");

module.exports = {
    id: "nodejs",
    name: "Node.JS",

    detector: path.resolve(__dirname, "detector.sh"),
    runner: [
        {
            name: "npm start",
            id: "run",
            script: path.resolve(__dirname, "run.sh")
        }
    ],

    ignoreRules: [
        "/node_modules"
    ]
};

Change name for default node.js runner


const NotificationBuilder = require('./notification/notification-builder');

class PersistenceProvider {
  constructor(bridge) {
    this.toSave = [];
    this.bridge = bridge;
    this.toProcessAction = [];
    this.publications = [];
    this.fetches = [];
  }

  save(obj) {
    this.toSave.push(obj);
  }

  processAction(obj, action) {
    this.toProcessAction.push({
      target: obj,
      action: action
    });
  }

  createFetchRequest() {
    let  [type, apiVersion, uid] = Array.prototype.slice.call(arguments);
    return this.bridge.newFetchRequest(type, apiVersion, uid);
  }

  publishOutbound() {
    if (!arguments.length) {
      return new NotificationBuilder((publication) => {
        this.publications.push(publication);
      });
    } else if (arguments.length === 1) {
      throw new TypeError('Single parameter publishOutbound function is not supported at this time.');
    } else if (arguments.length === 2) {
      this.publications.push({
        target: arguments[0],
        topic: arguments[1]
      });
    } else {
      throw new TypeError('Unsupported parameters used in publishOutbound function. Please check persistenceProvider API.');
    }
  }

  getSaves() {
    return this.toSave.slice();
  }

  getActionsToProcess() {
    return this.toProcessAction.slice();
  }

  getPublications() {
    return this.publications.slice();
  }

  reset() {
    this.toSave = [];
    this.toProcessAction = [];
    this.publications = [];
  }
}

module.exports = PersistenceProvider;

const NotificationBuilder = require('./notification/notification-builder');

class PersistenceProvider {
  constructor(bridge) {
    this.toSave = [];
    this.bridge = bridge;
    this.toProcessAction = [];
    this.publications = [];
    this.fetches = [];
    this.toSave = [];
  }

  save(obj) {
    this.toSave.push(obj);
  }

  processAction(obj, action) {
    this.toProcessAction.push({
      target: obj,
      action: action
    });
  }

  createFetchRequest() {
    let  [type, apiVersion, uid] = Array.prototype.slice.call(arguments);
    return this.bridge.newFetchRequest(type, apiVersion, uid);
  }

  publishOutbound() {
    if (!arguments.length) {
      return new NotificationBuilder((publication) => {
        this.publications.push(publication);
      });
    } else if (arguments.length === 1) {
      throw new TypeError('Single parameter publishOutbound function is not supported at this time.');
    } else if (arguments.length === 2) {
      this.publications.push({
        target: arguments[0],
        topic: arguments[1]
      });
    } else {
      throw new TypeError('Unsupported parameters used in publishOutbound function. Please check persistenceProvider API.');
    }
  }

  getSaves() {
    return this.toSave.slice();
  }

  getActionsToProcess() {
    return this.toProcessAction.slice();
  }

  getPublications() {
    return this.publications.slice();
  }

  reset() {
    this.toSave = [];
    this.toProcessAction = [];
    this.publications = [];
  }
}

module.exports = PersistenceProvider;

Fix bad refactor on PersistenceProvider


/**
 * Dependencies
 */

var Waterline = require('waterline');

module.exports = Waterline.Collection.extend({

  identity: 'unique',
  tableName: 'uniqueTable',
  connection: 'uniqueConn',
  primaryKey: 'id',

  attributes: {
    name: {
      type: 'string',
      autoMigrations: {
        columnType: 'varchar'
      }
    },
    email: {
      type: 'string',
      autoMigrations: {
        unique: true,
        columnType: 'varchar'
      }
    },
    type: {
      type: 'string',
      autoMigrations: {
        columnType: 'varchar'
      }
    },
    id: {
      type: 'number',
      autoMigrations: {
        autoIncrement: true,
        columnType: 'integer'
      }
    }
  }

});

/**
 * Dependencies
 */

var Waterline = require('waterline');

module.exports = Waterline.Collection.extend({

  identity: 'unique',
  tableName: 'uniqueTable',
  connection: 'uniqueConn',
  primaryKey: 'id',

  attributes: {
    name: {
      type: 'string',
      autoMigrations: {
        columnType: 'varchar'
      }
    },
    email: {
      type: 'string',
      required: true,
      autoMigrations: {
        unique: true,
        columnType: 'varchar'
      }
    },
    type: {
      type: 'string',
      autoMigrations: {
        columnType: 'varchar'
      }
    },
    id: {
      type: 'number',
      autoMigrations: {
        autoIncrement: true,
        columnType: 'integer'
      }
    }
  }

});

Make unique attribute required, to please sails-disk


process.env.MONGOHQ_URL = 'mongodb://localhost:27017/jsonresume-tests';
var mongoUrl = process.env.MONGOHQ_URL;
var mongo = require('../db');

// This bit of code runs before ANY tests start.
before(function beforeAllTests(done) {

    // Connect to db before running tests
    mongo.connect(mongoUrl, function(err) {
        if (err) {
            console.log('Error connecting to Mongo.', {
                err: err
            });
            return process.exit(1)
        }

        mongo.drop(done);
    });
});

var mongoose = require('mongoose');
process.env.MONGOHQ_URL = 'mongodb://localhost:27017/jsonresume-tests';
// register model schemas
require('../models/user');
require('../models/resume');

require('../lib/mongoose-connection');

function dropMongoDatabase(callback) {
	// Drop the database once connected (or immediately if connected).
	var CONNECTION_STATES = mongoose.Connection.STATES;
	var readyState = mongoose.connection.readyState;
	var connected = false;

	var drop = function() {
		mongoose.connection.db.dropDatabase(function(err) {
			if (err) {
				throw err;
			}
			callback(err);
		});
	};

	if (CONNECTION_STATES[readyState] === 'connected') {
		drop();
	} else {
		mongoose.connection.once('connected', drop);
	}
}

// This bit of code runs before ANY tests start.
before(function beforeAllTests(done) {

		dropMongoDatabase(done);
});

Update mocha before test setup to use mongoose.


'use strict';

var test = require('tape');
var nets = require('nets');
var requestGlobalDefaults = require('../');

test('defaulting/overriding a custom querystring', function (t) {
  t.plan(2);

  var defaultOptions = {
    json: true, // so we don't have to JSON.parse(body) later
    qs: {
      'request-globaldefaults': 'default value',
    },
  };

  var overrideOptions = {
    url: 'https://httpbin.org/get',
    qs: {
      'request-globaldefaults': 'override value',
    },
  };

  // The path used here should be `nets` result for require.resolve('request')
  // This path can change based on your dependencies and npm version.
  var innerRequest = require('nets/node_modules/request');
  requestGlobalDefaults(defaultOptions, innerRequest);

  nets('https://httpbin.org/get', function (error, response, body) {
    if (error) {
      t.fail(error);
    }
    else {
      t.equal(body.args['request-globaldefaults'], 'default value');
    }
  });

  nets(overrideOptions, function (error, response, body) {
    if (error) {
      t.fail(error);
    }
    else {
      t.equal(body.args['request-globaldefaults'], 'override value');
    }
  });
});

'use strict';

var test = require('tape');
var nets = require('nets');
var iferr = require('iferr');
var requestGlobalDefaults = require('../');

test('defaulting/overriding a custom querystring', function (t) {
  t.plan(2);

  var defaultOptions = {
    json: true, // so we don't have to JSON.parse(body) later
    qs: {
      'request-globaldefaults': 'default value',
    },
  };

  var overrideOptions = {
    url: 'https://httpbin.org/get',
    qs: {
      'request-globaldefaults': 'override value',
    },
  };

  // The path used here should be `nets` result for require.resolve('request')
  // This path can change based on your dependencies and npm version.
  var innerRequest = require('nets/node_modules/request');
  requestGlobalDefaults(defaultOptions, innerRequest);

  nets('https://httpbin.org/get', iferr(t.fail, function (response, body) {
    t.equal(body.args['request-globaldefaults'], 'default value');
  }));

  nets(overrideOptions, iferr(t.fail, function (response, body) {
    t.equal(body.args['request-globaldefaults'], 'override value');
  }));
});

Use `iferr` to simplify tests


"use strict";

let qUnit = require("qunit");
qUnit.setup({
    log: {
        errors: true,
        tests: true,
        globalSummary: true,
        testing: true
    },
    maxBlockDuration: 2000
});

// one code and tests file
qUnit.run({
    code: "test/adapter/qunit.js",
    tests: "test/tick-generator.js"
}, err => {
    if (err) {
        console.log(err);
    }
});

"use strict";

const fs = require("fs");

let qUnit = require("qunit");
qUnit.setup({
    log: {
        errors: true,
        tests: true,
        globalSummary: true,
        testing: true
    },
    maxBlockDuration: 2000
});

qUnit.run(fs.readdirSync("test")
    .filter(name => -1 === ["adapter", "qunit.js"].indexOf(name))
    .map(name => {
        return {
            code: "test/adapter/qunit.js",
            tests: "test/" + name
        };
    }), err => {
        if (err) {
            console.log(err);
        }
    });

Read test folder to get files


const {TASKS_TYPES} = require('./conf/consts')

const getTaskType = (taskName) =>{
  for (let task_type of TASKS_TYPES) {
    for (let keyword of task_type.keywords) {
      if(taskName..toUpperCase().includes(keyword.toUpperCase()))
        return task_type.name
    }
  }
}

module.exports.formatTasks = (rawtasks,fromDate) => {
  console.log('Formatting raw data.')

  let ftasks = rawtasks.map(el => { // map the project_id attribute of all tasks and save in 'formatted tasks'

    //Set task task type
    el.task_type = getTaskType(el.name)

    el.assignee = el.assignee.name // we are only interested in the Assignee's name. We don't check if this exists since one of our filters for getting the task is the assignee
    return el
  })

  // Filter only tasks that have a "completed at" value and that the "completed_at" month is the same
  // as the month we are requesting (There seems to be no way to filter these out directly in the
  // request to the server)
  let completedTasks = []

  ftasks.forEach(function(task){
    if(task.completed_at !== '' && task.completed_at !== null && (new Date(task.completed_at)).getUTCMonth() === (new Date(fromDate)).getUTCMonth()){
      completedTasks.push(task)
    }
  })

  return completedTasks
}

const {TASKS_TYPES} = require('./conf/consts')

const getTaskType = (taskName) =>{
  for (let task_type of TASKS_TYPES) {
    for (let keyword of task_type.keywords) {
      if(taskName.toUpperCase().includes(keyword.toUpperCase()))
        return task_type.name
    }
  }
}

module.exports.formatTasks = (rawtasks,fromDate) => {
  console.log('Formatting raw data.')

  let ftasks = rawtasks.map(el => { // map the project_id attribute of all tasks and save in 'formatted tasks'

    //Set task task type
    el.task_type = getTaskType(el.name)

    el.assignee = el.assignee.name // we are only interested in the Assignee's name. We don't check if this exists since one of our filters for getting the task is the assignee
    return el
  })

  // Filter only tasks that have a "completed at" value and that the "completed_at" month is the same
  // as the month we are requesting (There seems to be no way to filter these out directly in the
  // request to the server)
  let completedTasks = []

  ftasks.forEach(function(task){
    if(task.completed_at !== '' && task.completed_at !== null && (new Date(task.completed_at)).getUTCMonth() === (new Date(fromDate)).getUTCMonth()){
      completedTasks.push(task)
    }
  })

  return completedTasks
}

Make search for classifying tasks case insensitive.


import React from 'react';

import Button from 'src/Button';
import FlexRow from '../FlexRow';

function handleButtonClick() {
    // eslint-disable-next-line no-console
    console.log('Button clicked');
}

function BasicButtonExample() {
    return (
        <FlexRow>
            <Button
                basic="Blue Button"
                aside="Default color"
                tag="Tag"
                icon="add"
                onClick={handleButtonClick} />

            <Button
                color="red"
                basic="Red"
                aside="Variants"
                tag="Tag"
                icon="add" />

            <Button
                color="white"
                basic="White"
                aside="Variants"
                tag="Tag"
                icon="add" />

            <Button
                color="black"
                basic="Black"
                aside="Variants"
                tag="Tag"
                icon="add" />
        </FlexRow>
    );
}

export default BasicButtonExample;

import React from 'react';
import { action } from '@kadira/storybook';

import Button from 'src/Button';
import FlexRow from '../FlexRow';

function BasicButtonExample() {
    return (
        <FlexRow>
            <Button
                basic="Blue Button"
                aside="Default color"
                tag="Tag"
                icon="add"
                onClick={action('clicked')} />

            <Button
                color="red"
                basic="Red"
                aside="Variants"
                tag="Tag"
                icon="add" />

            <Button
                color="white"
                basic="White"
                aside="Variants"
                tag="Tag"
                icon="add" />

            <Button
                color="black"
                basic="Black"
                aside="Variants"
                tag="Tag"
                icon="add" />
        </FlexRow>
    );
}

export default BasicButtonExample;

Use `action` provided by storybook


'use strict';

/**
 * Module dependencies.
 */
var assert = require('chai').assert;
var mocks = require('./mocks/');
var htmlparser = require('htmlparser2');

/**
 * Tests for parser.
 */
describe('html-dom-parser', function() {

    describe('server parser', function() {
        var parser = require('../');

        it('is equivalent to `htmlparser2.parseDOM()`', function() {
            // html
            Object.keys(mocks.html).forEach(function(type) {
                var html = mocks.html[type];
                assert.deepEqual(parser(html), htmlparser.parseDOM(html));
            });

            // svg
            Object.keys(mocks.svg).forEach(function(type) {
                var svg = mocks.svg[type];
                assert.deepEqual(parser(svg), htmlparser.parseDOM(svg));
            });
        });
    });

});

'use strict';

/**
 * Module dependencies.
 */
var assert = require('chai').assert;
var mocks = require('./mocks/');
var htmlparser = require('htmlparser2');

/**
 * Helper that creates and runs tests based on mock data.
 *
 * @param {Function} parser  - The parser.
 * @param {Object}   mockObj - The mock object.
 */
function runTests(parser, mockObj) {
    Object.keys(mockObj).forEach(function(type) {
        it(type, function() {
            var data = mockObj[type];
            assert.deepEqual(parser(data), htmlparser.parseDOM(data));
        })
    });
}

/**
 * Tests for parser.
 */
describe('html-dom-parser', function() {

    // server
    describe('server parser', function() {
        var parser = require('../');

        // should be equivalent to `htmlparser2.parseDOM()`
        runTests(parser, mocks.html);
        runTests(parser, mocks.svg);
    });

});

Refactor tests with `runTests()` helper


Change expiration to 30 days


var config = {};

config.thinkingThings = {
    logLevel: 'ERROR',
    port: 8000,
    root: '/thinkingthings',
    sleepTime: 300
};

config.ngsi = {
    logLevel: 'ERROR',
    defaultType: 'ThinkingThing',
    contextBroker: {
        host: '192.168.56.101',
        port: '1026'
    },
    server: {
        port: 4041
    },
    deviceRegistry: {
        type: 'memory'
    },
    types: {
        'ThinkingThing': {
            service: 'smartGondor',
            subservice: '/gardens',
            type: 'ThinkingThing',
            commands: [],
            lazy: [],
            active: [
                {
                    name: 'humidity',
                    type: 'Number'
                }
            ]
        }
    },
    service: 'smartGondor',
    subservice: '/gardens',
    providerUrl: 'http://192.168.56.1:4041',
    deviceRegistrationDuration: 'P1M'
};

module.exports = config;

var config = {};

config.thinkingThings = {
    logLevel: 'ERROR',
    port: 8000,
    root: '/thinkingthings',
    sleepTime: 300
};

config.ngsi = {
    logLevel: 'ERROR',
    defaultType: 'ThinkingThing',
    contextBroker: {
        host: '127.0.0.1',
        port: '1026'
    },
    server: {
        port: 4041
    },
    deviceRegistry: {
        type: 'memory'
    },
    types: {
        'ThinkingThing': {
            service: 'smartGondor',
            subservice: '/gardens',
            type: 'ThinkingThing',
            commands: [],
            lazy: [],
            active: [
                {
                    name: 'humidity',
                    type: 'Number'
                }
            ]
        }
    },
    service: 'smartGondor',
    subservice: '/gardens',
    providerUrl: 'http://127.0.0.1:4041',
    deviceRegistrationDuration: 'P1M'
};

module.exports = config;

FIX Use localhost as default URL


import Circle    from './stores/Circle'
import Microcosm from '../../../dist/Microcosm'

export default class SimpleSVG extends Microcosm {

  constructor() {
    super()

    this.addStore('circle', Circle)

    if (module.hot) {
      module.hot.accept('./stores/Circle', () => {
        Circle.register = require('./stores/Circle').register
      })
    }

  }

}

import Circle    from './stores/Circle'
import Microcosm from '../../../src/Microcosm'

export default class SimpleSVG extends Microcosm {

  constructor() {
    super()

    this.addStore('circle', Circle)

    if (module.hot) {
      module.hot.accept('./stores/Circle', () => {
        Circle.register = require('./stores/Circle').register
      })
    }

  }

}

Use src Microcosm in simple svg example


(function() {
  "use strict";

  // See https://angular-translate.github.io/docs/#/guide
  angular.module('dimApp')
    .config(['$translateProvider', function($translateProvider) {
      $translateProvider.useSanitizeValueStrategy('escape');

      $translateProvider
        .translations('en', {
          Level: "Level",
          Weapons: "Weapons",
          Armor: "Armor",
          Equip: "Equip",
          Vault: "Vault",
          Vanguard: "Vanguard"
        })
        .translations('it', {
          Level: "Livello",
          Weapons: "Armi",
          Armor: "Armatura",
          Equip: "Equipaggia",
          Vault: "Deposito"
        })
        .translations('de', {
          Equip: "Ausstatten",
          Vault: "Ausrüstungstresor"
        })
        .translations('fr', {
        })
        .translations('es', {
          Level: "Nivel",
          Weapons: "Arma",
          Armor: "Armadura",
          Vault: "Bóveda",
          Vanguard: "Vanguardia"
        })
        .translations('ja', {
        })
        .translations('pt-br', {
        })
        .fallbackLanguage('en');
    }]);
})();

(function() {
  "use strict";

  // See https://angular-translate.github.io/docs/#/guide
  angular.module('dimApp')
    .config(['$translateProvider', function($translateProvider) {
      $translateProvider.useSanitizeValueStrategy('escape');

      $translateProvider
        .translations('en', {
          Level: "Level",
          Weapons: "Weapons",
          Armor: "Armor",
          Equip: "Equip",
          Vault: "Vault",
          Vanguard: "Vanguard"
        })
        .translations('it', {
          Level: "Livello",
          Weapons: "Armi",
          Armor: "Armatura",
          Equip: "Equipaggia",
          Vault: "Deposito"
        })
        .translations('de', {
          Weapons: "Waffen",
          Armor: "Schutz",
          Equip: "Ausstatten",
          Vault: "Ausrüstungstresor"
        })
        .translations('fr', {
          Level: "Niveau",
          Weapons: "Armes",
          Armor: "Armure",
          Equip: "Équiper",
          Vault: "Coffres"
        })
        .translations('es', {
          Level: "Nivel",
          Weapons: "Armas",
          Armor: "Armadura",
          Equip: "Equipar",
          Vault: "Bóveda",
          Vanguard: "Vanguardia"
        })
        .translations('ja', {
        })
        .translations('pt-br', {
          Level: "Nivel",
          Weapons: "Armas",
          Armor: "Armadura",
          Equip: "Equipar",
          Vault: "Cofres"
        })
        .fallbackLanguage('en');
    }]);
})();

Update German, French, Spanish, and Portugese-Brasil Translations


import openstackBackupsService from './openstack-backups-service';
import openstackBackupsList from './openstack-backups-list';
import backupSnapshotsList from './backup-snapshots-list';

export default module => {
  module.service('openstackBackupsService', openstackBackupsService);
  module.directive('openstackBackupsList', openstackBackupsList);
  module.directive('backupSnapshotsList', backupSnapshotsList);
  module.config(actionConfig);
  module.config(tabsConfig);
};

// @ngInject
function actionConfig(ActionConfigurationProvider, DEFAULT_EDIT_ACTION) {
  ActionConfigurationProvider.register('OpenStackTenant.Backup', {
    order: [
      'edit'
    ],
    options: {
      edit: angular.merge({}, DEFAULT_EDIT_ACTION, {
        successMessage: 'Backup has been updated',
        fields: {
          kept_until: {
            help_text: 'Guaranteed time of backup retention. If null - keep forever.',
            label: 'Kept until',
            required: false,
            type: 'datetime'
          }
        }
      })
    }
  });
}

// @ngInject
function tabsConfig(ResourceTabsConfigurationProvider, DEFAULT_RESOURCE_TABS) {
  ResourceTabsConfigurationProvider.register('OpenStackTenant.Backup', {
    order: [
      ...DEFAULT_RESOURCE_TABS.order,
      'snapshots',
    ],
    options: angular.merge({}, DEFAULT_RESOURCE_TABS.options, {
      snapshots: {
        heading: 'Snapshots',
        component: 'backupSnapshotsList'
      },
    })
  });
}

import openstackBackupsService from './openstack-backups-service';
import openstackBackupsList from './openstack-backups-list';
import backupSnapshotsList from './backup-snapshots-list';

export default module => {
  module.service('openstackBackupsService', openstackBackupsService);
  module.directive('openstackBackupsList', openstackBackupsList);
  module.directive('backupSnapshotsList', backupSnapshotsList);
  module.config(actionConfig);
  module.config(tabsConfig);
};

// @ngInject
function actionConfig(ActionConfigurationProvider, DEFAULT_EDIT_ACTION) {
  ActionConfigurationProvider.register('OpenStackTenant.Backup', {
    order: [
      'edit',
      'restore',
      'destroy',
    ],
    options: {
      edit: angular.merge({}, DEFAULT_EDIT_ACTION, {
        successMessage: 'Backup has been updated',
        fields: {
          kept_until: {
            help_text: 'Guaranteed time of backup retention. If null - keep forever.',
            label: 'Kept until',
            required: false,
            type: 'datetime'
          }
        }
      })
    }
  });
}

// @ngInject
function tabsConfig(ResourceTabsConfigurationProvider, DEFAULT_RESOURCE_TABS) {
  ResourceTabsConfigurationProvider.register('OpenStackTenant.Backup', {
    order: [
      ...DEFAULT_RESOURCE_TABS.order,
      'snapshots',
    ],
    options: angular.merge({}, DEFAULT_RESOURCE_TABS.options, {
      snapshots: {
        heading: 'Snapshots',
        component: 'backupSnapshotsList'
      },
    })
  });
}

Enable backup restore and destroy actions.


(function (window) {
  "use strict";

  window.GOVUK = window.GOVUK || {};

  const trackingId = 'UA-26179049-1';

  // Disable analytics by default
  window[`ga-disable-${trackingId}`] = true;

  const initAnalytics = function () {

    // guard against being called more than once
    if (!('analytics' in window.GOVUK)) {

      window[`ga-disable-${trackingId}`] = false;

      // Load Google Analytics libraries
      window.GOVUK.Analytics.load();

      // Configure profiles and make interface public
      // for custom dimensions, virtual pageviews and events
      window.GOVUK.analytics = new GOVUK.Analytics({
        trackingId: trackingId,
        cookieDomain: 'auto',
        anonymizeIp: true,
        displayFeaturesTask: null,
        transport: 'beacon',
        name: 'GOVUK.analytics',
        expires: 365
      });

      // Track initial pageview
      window.GOVUK.analytics.trackPageview();

    }

  };

  window.GOVUK.initAnalytics = initAnalytics;
})(window);

(function (window) {
  "use strict";

  window.GOVUK = window.GOVUK || {};

  const trackingId = 'UA-75215134-1';

  // Disable analytics by default
  window[`ga-disable-${trackingId}`] = true;

  const initAnalytics = function () {

    // guard against being called more than once
    if (!('analytics' in window.GOVUK)) {

      window[`ga-disable-${trackingId}`] = false;

      // Load Google Analytics libraries
      window.GOVUK.Analytics.load();

      // Configure profiles and make interface public
      // for custom dimensions, virtual pageviews and events
      window.GOVUK.analytics = new GOVUK.Analytics({
        trackingId: trackingId,
        cookieDomain: 'auto',
        anonymizeIp: true,
        displayFeaturesTask: null,
        transport: 'beacon',
        name: 'GOVUK.analytics',
        expires: 365
      });

      // Track initial pageview
      window.GOVUK.analytics.trackPageview();

    }

  };

  window.GOVUK.initAnalytics = initAnalytics;
})(window);

Fix Google Analytics tracking code


/**
 * @module timed
 * @submodule timed-components
 * @public
 */
import Component from 'ember-component'
import service from 'ember-service/inject'

const ENTER_CHAR_CODE = 13

/**
 * The tracking bar component
 *
 * @class TrackingBarComponent
 * @extends Ember.Component
 * @public
 */
export default Component.extend({
  tracking: service('tracking'),

  /**
   * Key press event
   *
   * Start activity if the pressed key is enter
   *
   * @event keyPress
   * @param {jQuery.Event} e The keypress event
   * @public
   */
  keyPress(e) {
    if (
      e.charCode === ENTER_CHAR_CODE &&
      !e.target.classList.contains('tt-input')
    ) {
      this.get('tracking.startActivity').perform()
    }
  }
})

/**
 * @module timed
 * @submodule timed-components
 * @public
 */
import Component from 'ember-component'
import service from 'ember-service/inject'
import { observes } from 'ember-computed-decorators'
import { later } from 'ember-runloop'

const ENTER_CHAR_CODE = 13

/**
 * The tracking bar component
 *
 * @class TrackingBarComponent
 * @extends Ember.Component
 * @public
 */
export default Component.extend({
  tracking: service('tracking'),

  /**
   * Key press event
   *
   * Start activity if the pressed key is enter
   *
   * @event keyPress
   * @param {jQuery.Event} e The keypress event
   * @public
   */
  keyPress(e) {
    if (
      e.charCode === ENTER_CHAR_CODE &&
      !e.target.classList.contains('tt-input')
    ) {
      this.get('tracking.startActivity').perform()
    }
  },

  /**
   * Set the focus to the comment field as soon as the task is selected
   *
   * The 'later' needs to be there so that the focus happens after all the
   * other events are done. Otherwise it'd focus the play button.
   *
   * @method _setCommentFocus
   * @public
   */
  @observes('tracking.activity.task')
  _setCommentFocus() {
    if (this.get('tracking.activity.task.id')) {
      later(this, () => {
        this.$('input[name=comment]').focus()
      })
    }
  }
})

Set the focus to the comment box after selecting a task


{
  class UsersService {
    create () {
      console.log('CREATED!');
      console.log(user);
    }
  }

  angular.module('meganote.users')
    .service('UsersService', UsersService);
}

{
  angular.module('meganote.users')
    .service('UsersService', [
      '$hhtp',
      'API_BASE',
      ($http, API_BASE) => {

        class UsersService {
          create (users) {
            $http.get(API_BASE)
              .then(
                res => {
                  console.log(res.data);
                }
              );
          }
        }
        return new UsersService();
      }
    ]);
}

Refactor SignUp directive to use UsersService.


'use strict';

describe('github banner', function() {
  beforeEach(function() {
    browser.get('http://localhost:3000/');
  });

  it('should load', function() {
    var list = element.all(by.css(
      'a[href="https://github.com/solarnz/ec2pric.es"]'
    ));

    expect(list.count()).toBe(1);
  });
});

'use strict';

describe('github banner', function() {
  var banner;

  beforeEach(function() {
    browser.get('http://localhost:3000/');

    banner = element(by.css(
      'a[href="https://github.com/solarnz/ec2pric.es"]'
    ));
  });

  it('should be present', function() {
    expect(banner.isPresent).toBeTruthy();
  });
});

Clean up the github banner tests a little bit


import React from 'react';

function getViewportData() {
  let viewport = 'xs';
  if (window.innerWidth >= 544) viewport = 'sm';
  if (window.innerWidth >= 768) viewport = 'md';
  if (window.innerWidth >= 992) viewport = 'lg';
  if (window.innerWidth >= 1200) viewport = 'xl';
  return viewport;
}

function renderThemedChildren(props) {
  return React.Children.map(props.children, (child) => {
    if (!child) return null;
    return React.cloneElement(child, { theme: props.theme, viewport: getViewportData() });
  });
}

const ContextPropagator = (props) => {
  return (
    <div style={props.wrapperStyle}>
      { renderThemedChildren(props) }
    </div>
  );
}

ContextPropagator.propTypes = {
  wrapperStyle: React.PropTypes.object,
  children: React.PropTypes.arrayOf(React.PropTypes.element)
};

export default ContextPropagator;

import React from 'react';

function getViewportData() {
  let viewport = 'xs';
  if (window.innerWidth >= 544) viewport = 'sm';
  if (window.innerWidth >= 768) viewport = 'md';
  if (window.innerWidth >= 992) viewport = 'lg';
  if (window.innerWidth >= 1200) viewport = 'xl';
  return viewport;
}

function renderThemedChildren(props) {
  return React.Children.map(props.children, (child) => {
    if (!child) return null;
    return React.cloneElement(child, { theme: props.theme, viewport: getViewportData() });
  });
}

const ContextPropagator = (props) => {
  return (
    <div style={props.wrapperStyle}>
      { renderThemedChildren(props) }
    </div>
  );
}

ContextPropagator.propTypes = {
  wrapperStyle: React.PropTypes.object,
  children: React.PropTypes.node
};

export default ContextPropagator;

Use node instead of element array for prop validation


// @flow
const React = require("react");
const { DOM: dom } = React;

const ReactDOM = require("react-dom");

require("./ConditionalPanel.css");

function renderConditionalPanel({ condition, closePanel, setBreakpoint }:
  { condition: boolean, closePanel: Function, setBreakpoint: Function }) {
  let panel = document.createElement("div");

  function onKey(e: SyntheticKeyboardEvent) {
    if (e.key != "Enter") {
      return;
    }

    if (e.target && e.target.value) {
      setBreakpoint(e.target.value);
      closePanel();
    }
  }

  ReactDOM.render(
    dom.div(
      { className: "conditional-breakpoint-panel" },
      dom.div({
        className: "prompt",
        dangerouslySetInnerHTML: { __html: "»" }
      }),
      dom.input({
        defaultValue: condition,
        placeholder: L10N.getStr("editor.conditionalPanel.placeholder"),
        onKeyPress: onKey
      })
    ),
    panel
  );

  return panel;
}

module.exports = {
  renderConditionalPanel
};

// @flow
const React = require("react");
const { DOM: dom } = React;

const ReactDOM = require("react-dom");

require("./ConditionalPanel.css");

function renderConditionalPanel({ condition, closePanel, setBreakpoint }:
  { condition: boolean, closePanel: Function, setBreakpoint: Function }) {
  let panel = document.createElement("div");

  function onKey(e: SyntheticKeyboardEvent) {
    if (e.key != "Enter") {
      return;
    }

    if (e.target && e.target.value) {
      setBreakpoint(e.target.value);
      closePanel();
    }
  }

  ReactDOM.render(
    dom.div(
      { className: "conditional-breakpoint-panel" },
      dom.div({ className: "prompt" }, "»"),
      dom.input({
        defaultValue: condition,
        placeholder: L10N.getStr("editor.conditionalPanel.placeholder"),
        onKeyPress: onKey
      })
    ),
    panel
  );

  return panel;
}

module.exports = {
  renderConditionalPanel
};

Fix to use unicode char instead of innerHTML


import app from 'ampersand-app'
import React, {Component, PropTypes} from 'react'
import localLinks from 'local-links'
import * as modalActions from 'gModules/modal/actions.js'
import {connect} from 'react-redux';

@connect()
export default class NavHelper extends Component{
  displayName: 'NavHelper'

  onClick (event) {
    const pathname = localLinks.getLocalPathname(event)

    if (pathname) {
      event.preventDefault()
      app.router.history.navigate(pathname)
      this.props.dispatch(modalActions.close())
    }
  }

  render () {
    return (
      <div className='navHelper' onClick={this.onClick.bind(this)}>
        {this.props.children}
      </div>
    )
  }
}

import app from 'ampersand-app'
import React, {Component, PropTypes} from 'react'
import localLinks from 'local-links'
import * as modalActions from 'gModules/modal/actions.js'
import {connect} from 'react-redux';
import $ from 'jquery'

@connect()
export default class NavHelper extends Component{
  displayName: 'NavHelper'

  onClick (event) {
    const pathname = localLinks.getLocalPathname(event)

    if (pathname) {
      event.preventDefault()
      app.router.history.navigate(pathname)
      this.props.dispatch(modalActions.close())
    }
  }

  componentDidMount(){
    $(document).on('keydown', (e) => {
      if (e.which === 8 && $(e.target).is('body')) {
        e.preventDefault();
      }
    });
  }

  render () {
    return (
      <div className='navHelper' onClick={this.onClick.bind(this)}>
        {this.props.children}
      </div>
    )
  }
}

Use NavHelper to ensure that backspace when nothing is selected will not go back in history


import express from 'express';
import path from 'path';
import lodashExpress from 'lodash-express';
import fs from 'fs';

const app = express();
const staticPath = path.join(__dirname, '../build/');

app.use(express.static(staticPath));
lodashExpress(app, 'html');
app.set('view engine', 'html');

const hash = fs.readFileSync(path.join(staticPath, 'hash'));

app.get('/', (req, res) => {
    res.redirect('/portal')
});

app.get('/portal*', (req, res) => {
    res.render('index-prod', {hash});
})

app.listen(3000, function() {
    console.log('Server is listening on port 3000');
});

import express from 'express';
import path from 'path';
import lodashExpress from 'lodash-express';
import fs from 'fs';

const app = express();
const staticPath = path.join(__dirname, '../build/');

app.use(express.static(staticPath));
lodashExpress(app, 'html');
app.set('view engine', 'html');

const hash = fs.readFileSync(path.join(staticPath, 'hash'));

app.get('/', (req, res) => {
    res.redirect('/portal')
});

app.get('/portal*', (req, res) => {
    res.render('index-prod', {hash});
})

const port = +(process.env.HTTP_PORT || 3000);

app.listen(, function() {
    console.log(`hdo-portal is listening on port ${port}`);
});

Make port configurable through env


import React from 'react'
import { Link, hashHistory } from 'react-router'

export default function App({ children }) {
  return (

        Links:
        {' '}
        <Link to="/">Home</Link>
        {' '}
        <Link to="/foo">Foo</Link>
        {' '}
        <Link to="/bar">Bar</Link>

        <button onClick={() => hashHistory.push('/foo')}>Go to /foo</button>

{children}

  )
}

import React from 'react'
import { Link, browserHistory } from 'react-router'

export default function App({ children }) {
  return (

        Links:
        {' '}
        <Link to="/">Home</Link>
        {' '}
        <Link to="/foo">Foo</Link>
        {' '}
        <Link to="/bar">Bar</Link>

        <button onClick={() => browserHistory.push('/foo')}>Go to /foo</button>

{children}

  )
}

Use browserHistory instead of hashHistory


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

app.set('port', process.env.PORT || 3000);

//custom 404 page.
app.use(function (req, res){
    res.type('text/plain');
    res.status(404);
    res,send('404 - Not Found');
});

//custom 500 page.
app.use(function (err, req, res, next){
    console.error(err.stack);
    res.type('text/plain');
    res.status(500);
    res.send('500 - Server Error');
});

app.listen(app.get('port'), function(){
    console.log('Express started on http://localhost:' +
               app.get('port' + '; press Ctrl-C to terminate.'));
});

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

app.set('port', process.env.PORT || 3000);

// View engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');//Set the view engine to ejs for renderring html content.

// Default landing page
app.get('/', function(req, res) {
    res.send('Welcome');
});

// Custom 404 page.
app.use(function (req, res){
    res.type('text/plain');
    res.status(404);
    res.send('404 - Not Found');
});

// Custom 500 page.
app.use(function (err, req, res, next){
    console.error(err.stack);
    res.type('text/plain');
    res.status(500);
    res.send('500 - Server Error');
});

// Start the server
app.listen(app.get('port'), function(){
    console.log('Express started.');
});

Set the view engine, set the welcome page


"use strict"

var namespace = 'azure-service-bus-nodejs',
	accessKey = '[Access key for this namespace]',
	azure = require('azure');

var client = azure.createServiceBusService(namespace, accessKey);

client.listTopics(function(error, result, response) {
    if (error) {
        console.log(error);
        return;
    }

    console.log(JSON.stringify(result, null, 3));
});

"use strict"

var namespace = 'azure-service-bus-nodejs',
    accessKey = '[Access key for this namespace]',
    azure = require('azure'),
    http = require('http');

var client = azure.createServiceBusService(namespace, accessKey);

var server = http.createServer(function(httpReq, httpResp) {
    client.listTopics(function(error, result, response) {
        if (error) {
            httpResp.writeHead(500, {'Content-Type': 'application/json'});
            httpResp.write(JSON.stringify(error, null, 3));
            httpResp.end();
            return;
        }

        var topics = result.map(function(topic) {
            return {
                name: topic.TopicName,
                totalSubscriptions: topic.SubscriptionCount,
                totalSize: topic.SizeInBytes
            };
        });

        httpResp.writeHead(200, {'Content-Type': 'application/json'});
        httpResp.write(JSON.stringify(topics, null, 3));
        httpResp.end();
    });
});

server.listen(8080);

Make it a web service


var cuecard = require('cuecard');

cuecard.configure({
	title: 'Getting Closure',
	html: __dirname + '/slides.html',
	css: __dirname + '/slides.css'
});

cuecard.server.listen(3000);

var cuecard = require('cuecard');

cuecard.create({
	port: 3000,
	remoteUrl: '/my-remote-url',
	title: 'Getting Closure',
	html: __dirname + '/slides.html',
	css: __dirname + '/slides.css'
});

Use port and remoteUrl options


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

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

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

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

app.use(express.static('public', {index: 'index.html'}));

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});

Configure path to index.html manually


var sql = require('msnodesql');
// Change the connectionString. Example
// "Driver={SQL Server Native Client 11.0};Server=tcp:?????.database.windows.net,1433;Database=????;Uid=?????@?????;Pwd=?????";
var connectionString = "";
var testQuery = "SELECT 1";

if(connectionString ==  "") {
	console.log("This script cannot run without a connection string");
	return;
}

var http = require('http');
var port = process.env.PORT || 1337;
var httpServer = http.createServer(function (req, res) {
	res.writeHead(200, {'Content-Type': 'text/plain'});
	sql.open(connectionString, function(err, conn) {
		if(err)
			res.end("Connection Failed \n");

		conn.query(testQuery, [], function(err, result) {
			if(err)
				res.end("Query Failed \n");
			else
				res.end("Query result - " + result[0]['Column0'] + " \n");
		});
	});
});

httpServer.listen(port);
console.log('Server running at localhost:'+port);

var sql = require('msnodesql');
// Change the connectionString. Example
// "Driver={SQL Server Native Client 11.0};Server=tcp:?????.database.windows.net,1433;Database=????;Uid=?????@?????;Pwd=?????";
var connectionString = "";
var testQuery = "SELECT 1";

if(connectionString ==  "") {
	console.log("This script cannot run without a connection string");
	return;
}

var http = require('http');
var port = process.env.PORT || 1337;
var httpServer = http.createServer(function (req, res) {
	res.writeHead(200, {'Content-Type': 'text/plain'});

	sql.query(connectionString, testQuery, function(err, result) {
		if(err)
			res.end("Query Failed \n");
		else
			res.end("Query result: " + result[0]['Column0'] + " \n");
	});
});

httpServer.listen(port);
console.log('Server running at localhost:'+port);

Use sql.query instead of sql.open/conn.query


var socketio = require('socket.io');
var io;
var guestNumber = 1;
var nickNames = {};
var namesUsed = [];
var currentRoom = {};

exports.listen = function(server) {
  io = socketio.listen(server);
  io.set('log level', 1);
  io.sockets.on('connection', function(socket) {
    guestNumber = assignGuestName(socket, guestNumber, nickNames, namesUsed);
    joinRoom(socket, 'Lobby');

    handleMessageBroadcasting(socket, nickNames);
    handleNameChangeAttempts(socket, nickNames, namesUsed);
    handleRoomJoining(socket);

    socket.on('rooms', function() {
      socket.emit('rooms', io.sockets.manager.rooms);
    });

    handleClientDisconnection(socket, nickNames, namesUsed);
  });
};

function assignGuestName(socket, guestNumber, nickNames, namesUsed) {
  var name = 'Guest' + guestNumber;

  nickNames[socket.id] = name;

  socket.emit('nameResult', {
    success: true,
    name: name
  });

  namesUsed.push(name);

  return guestNumber + 1;
}

function joinRoom(socket, room) {
  socket.join(room);

  currentRoom[socket.id] = room;

  socket.emit('joinResult', {room: room});

  socket.broadcast.to(room).emit('message', {
    text: nickNames[socket.io] + 'has joined' + room + '.'
  });

  var usersInRoom = io.sockets.clients(room);
  if (usersInRoom.length > 1) {
    var usersInRoomSummary = 'Users currently in ' + room + ': ';

    for(var index in usersInRoom) {
      var userSocketId = usersInRoom[index].id;
      if (userSocketId != socket.id) {
        if (index > 0) {
          usersInRoomSummary += ', ';
        }
        usersInRoomSummary += nickNames[userSocketId];
      }
    }

    usersInRoomSummary += '.';

    socket.emit('message', {text: usersInRoomSummary});
  }
}

Add helper function for joining rooms


/* JupyROOT JS */

// Terminal button
$(document).ready(function() {
    $('div#header-container').append("Terminal");
});

Fix path to terminal from ROOTbook


import Ember from 'ember';

export default Ember.Controller.extend({
    fetchedNode: null,
    fetchedChild: null,
    actions: {
        fetchNodePreprintsEmbedded() {
            this.store.findRecord('node', 'ee2t9').then((node) => {
                this.set('fetchedNode', node);
            });
        },
        fetchNodeParentEmbedded() {
            this.store.findRecord('node', 'pe8s6').then((node) => {
                this.set('fetchedChild', node);
            });
        }
      }
});

import Ember from 'ember';

export default Ember.Controller.extend({
    fetchedNode: null,
    fetchedChild: null,
    actions: {
        fetchNodePreprintsEmbedded() {
            this.store.findRecord('node', '7gzxb', {include: 'preprints'}).then((node) => {
                this.set('fetchedNode', node);
            });
        },
        fetchNodeParentEmbedded() {
            this.store.findRecord('node', 'ddyuz', {include: 'parent'}).then((node) => {
                this.set('fetchedChild', node);
            });
        }
      }
});

Update dummy app to use included resources.


var Draft = {
  mixins: {},

  // TODO:50 test safety checks for Draft.px()
  px: function(val) {
    var num = parseFloat(val, 10);
    var units = testUnits(val);

    // Remain unchanged if units are already px
    if (units == 'px') {
      return num;
    }
    // Points and picas (pt, pc)
    else if (units == 'pt') {
      return Draft.px(num / 72 + 'in');
    } else if (units == 'pc') {
      return Draft.px(num * 12 + 'pt');
    }
    // Imperial units (in, ft, yd, mi)
    else if (units == 'in') {
      return num * defaults.dpi;
    } else if (units == 'ft') {
      return Draft.px(num * 12 + 'in');
    } else if (units == 'yd') {
      return Draft.px(num * 3 + 'ft');
    } else if (units == 'mi') {
      return Draft.px(num * 1760 + 'yd');
    }
    // Metric units (mm, cm, m, km)
    else if (units.endsWith('m')) {
      if (units == 'mm') {
        num *= 1;
      } else if (units == 'cm') {
        num *= 10;
      } else if (units == 'km') {
        num *= 1000000;
      }

      return Draft.px(num / 25.4 + 'in');
    } else {
      return undefined;
    }
  }
};

var Draft = {
  mixins: {},

  // TODO:50 test safety checks for Draft.px()
  px: function(val) {
    var num = parseFloat(val, 10);
    var units = testUnits(val);

    switch (units) {
      // Remain unchanged if units are already px
      case 'px':
        return num;

      // Points and picas (pt, pc)
      case 'pc':
        num *= 12;
        // Falls through
      case 'pt':
        num /= 72;
        break;

      // Metric units (mm, cm, dm, m, km)
      case 'km':
        num *= 1000;
        // Falls through
      case 'm':
        num *= 10;
        // Falls through
      case 'dm':
        num *= 10;
        // Falls through
      case 'cm':
        num *= 10;
        // Falls through
      case 'mm':
        num /= 25.4;
        break;

      // Imperial units (in, ft, yd, mi)
      case 'mi':
        num *= 1760;
        // Falls through
      case 'yd':
        num *= 3;
        // Falls through
      case 'ft':
        num *= 12;
        // Falls through
      case 'in':
        break;
      default:
        return undefined;
    }

    return num * Draft.defaults.dpi;
  }
};

Use switch statement for Draft.px()


import {Block} from '../../dist/cyclow'
import Confirm from './confirm'

const Field = () => Block({
  outputs: ['submission'],
  components: {confirm: Confirm()},
  on: {
    init: instruction => [state => ({instruction, input: ''}), 'confirm.init'],
    text: newText => state => ({...state, input: newText}),
    'confirm.confirmation': (_, {input}) => [['out.submission', input]],
    state: ({input}) => [['confirm.disabled', !input]]
  },
  view: ({instruction, input}, {confirm}) => ({content: [
    `${instruction}:`,
    {
      tag: 'input',
      attrs: {id: 'field', value: input},
      on: {keyup: (e, next) => next(['text', e.target.value])}
    },
    confirm
  ]})
})

export default Field

import {Block} from '../../dist/cyclow'
import Confirm from './confirm'

const Field = () => Block({
  outputs: ['submission'],
  components: {confirm: Confirm()},
  on: {
    init: instruction => [state => ({instruction, input: ''}), 'confirm.init'],
    text: newText => state => ({...state, input: newText}),
    'confirm.confirmation': (_, {input}) => [
      ['out.submission', input],
      state => ({...state, input: ''})
    ],
    state: ({input}) => [['confirm.disabled', !input]]
  },
  view: ({instruction, input}, {confirm}) => ({content: [
    `${instruction}:`,
    {
      tag: 'input',
      attrs: {id: 'field', value: input},
      on: {keyup: (e, next) => next(['text', e.target.value])}
    },
    confirm
  ]})
})

export default Field

Clear inputbox after click Confirm button


import syntax from '@babel/plugin-syntax-jsx'
import pureAnnotation from './visitors/pure'
import minify from './visitors/minify'
import displayNameAndId from './visitors/displayNameAndId'
import templateLiterals from './visitors/templateLiterals'
import assignStyledRequired from './visitors/assignStyledRequired'
import transpileCssProp from './visitors/transpileCssProp'

export default function({ types: t }) {
  return {
    inherits: syntax,
    visitor: {
      // These visitors insert newly generated code and missing import/require statements
      Program: {
        enter(path, state) {
          state.required = false
        },
      },
      JSXAttribute(path, state) {
        transpileCssProp(t)(path, state)
      },
      CallExpression(path, state) {
        displayNameAndId(t)(path, state)
        pureAnnotation(t)(path, state)
      },
      TaggedTemplateExpression(path, state) {
        minify(t)(path, state)
        displayNameAndId(t)(path, state)
        templateLiterals(t)(path, state)
        pureAnnotation(t)(path, state)
      },
      VariableDeclarator(path, state) {
        assignStyledRequired(t)(path, state)
      },
    },
  }
}

import syntax from '@babel/plugin-syntax-jsx'
import pureAnnotation from './visitors/pure'
import minify from './visitors/minify'
import displayNameAndId from './visitors/displayNameAndId'
import templateLiterals from './visitors/templateLiterals'
import assignStyledRequired from './visitors/assignStyledRequired'
import transpileCssProp from './visitors/transpileCssProp'

export default function({ types: t }) {
  return {
    inherits: syntax,
    visitor: {
      JSXAttribute(path, state) {
        transpileCssProp(t)(path, state)
      },
      CallExpression(path, state) {
        displayNameAndId(t)(path, state)
        pureAnnotation(t)(path, state)
      },
      TaggedTemplateExpression(path, state) {
        minify(t)(path, state)
        displayNameAndId(t)(path, state)
        templateLiterals(t)(path, state)
        pureAnnotation(t)(path, state)
      },
      VariableDeclarator(path, state) {
        assignStyledRequired(t)(path, state)
      },
    },
  }
}

Remove unnecessary default of state.required to false


var creep = exports;

var _ = require('lodash');
var config = require('./config');

require('./filters/js');
require('./filters/coffee');
require('./parsers/matter');

creep.config = require('./config');
creep.crawl = require('./crawl');
creep.query = require('./query');
creep.filters = require('./filters');
creep.parsers = require('./parsers');
creep.utils = require('./utils');

creep.list = function(query) {
};

creep.link = function(query) {
};

creep.unlink = function(query) {
};

_.each(config.parsers, function(parser, name) {
  creep.parsers.register.exts(name, parser.exts);
});

var creep = exports;

var _ = require('lodash');
var config = require('./config');

require('./filters/js');
require('./filters/coffee');
require('./parsers/matter');

creep.config = require('./config');
creep.crawl = require('./crawl');
creep.query = require('./query');
creep.filters = require('./filters');
creep.parsers = require('./parsers');
creep.utils = require('./utils');

_.each(config.parsers, function(parser, name) {
  creep.parsers.register.exts(name, parser.exts);
});

Remove old api method stubs that won't be happening anymore


// External dependencies
const os = require('os');
const Koa = require('koa');
const send = require('koa-send');
const logger = require('koa-logger');
const assert = require('assert');
const debug = require('debug')('reviewly');

// Internal modules
const config = require('./config')();
assert(!!config, `config needs to be defined for ${ process.env.NODE_ENV }`);

// Setup the app
const app = new Koa();
const rootFolder = process.env.ROOT_FOLDER || os.homedir();

// Add middleware
app.use(logger());

// Serve folder based on subdomain
app.use(async (ctx) => {
  const subdomains = ctx.req.headers.host.split('.');
  const featureName = subdomains[0];
  const path = ctx.path === '/' ? 'index.html' : ctx.path;
  debug('rootFolder', rootFolder, 'featureName', featureName, 'path', path);
  // TODO NRT: Verify the resource exists, if not, return index.html
  await send(ctx, path, { root: `${ rootFolder }/${ featureName }` });
});

// Start server
app.listen(config.port, () => /* eslint-disable no-console */ console.log(`Reviewly successfuly started on port ${ config.port } with NODE_ENV ${ process.env.NODE_ENV }`) /* eslint-enable no-console */);

// Export server to allow testing
module.exports = app;

// External dependencies
const os = require('os');
const Koa = require('koa');
const send = require('koa-send');
const logger = require('koa-logger');
const assert = require('assert');
const debug = require('debug')('reviewly');

// Internal modules
const config = require('./config')();
assert(!!config, `config needs to be defined for ${ process.env.NODE_ENV }`);

// Setup the app
const app = new Koa();
const rootFolder = process.env.ROOT_FOLDER || os.homedir();

// Add middleware
app.use(logger());

// Serve folder based on subdomain
app.use(async (ctx) => {
  const subdomains = ctx.req.headers.host.split('.');
  const featureName = subdomains[1];
  const path = ctx.path === '/' ? 'index.html' : ctx.path;
  debug('rootFolder', rootFolder, 'featureName', featureName, 'path', path);
  // TODO NRT: Verify the resource exists, if not, return index.html
  await send(ctx, path, { root: `${ rootFolder }/${ featureName }` });
});

// Start server
app.listen(config.port, () => /* eslint-disable no-console */ console.log(`Reviewly successfuly started on port ${ config.port } with NODE_ENV ${ process.env.NODE_ENV }`) /* eslint-enable no-console */);

// Export server to allow testing
module.exports = app;

Use second subdomain as feature name


'use strict'

import md5 from './md5'
import fs from 'fs'
const filename = process.argv[2]

md5(fs.ReadStream(filename)).then((sum) => {
  console.log(`MD5 sum of "${filename}" is ${sum}`)
}).catch((err) => {
  console.log(`something is wrong: ${err}`)
})

Handle error case in cli


import { consola } from './utils';

import initWebSocket from './initWebSocket';
import closeWebSocket from './closeWebSocket';
import * as types from './types';

export * from './types';

const createMiddleware = () => {
  let websocket;

  return store => next => (action) => {
    switch (action.type) {
      case types.WEBSOCKET_CONNECT:
        websocket = closeWebSocket(websocket);

        websocket = initWebSocket(store, action.payload);

        return next(action);

      case types.WEBSOCKET_SEND:
        if (websocket) {
          websocket.send(JSON.stringify(action.payload));
        }

        consola.warn('WebSocket is not open. To open, dispatch action WEBSOCKET_CONNECT.');

        return next(action);

      case types.WEBSOCKET_DISCONNECT:
        websocket = closeWebSocket(websocket);

        return next(action);

      default:
        return next(action);
    }
  };
};

export default createMiddleware();

import { consola } from './utils';

import initWebSocket from './initWebSocket';
import closeWebSocket from './closeWebSocket';
import * as types from './types';

export * from './types';

const createMiddleware = () => {
  let websocket;

  return store => next => (action) => {
    switch (action.type) {
      case types.WEBSOCKET_CONNECT:
        websocket = closeWebSocket(websocket);

        websocket = initWebSocket(store, action.payload);

        return next(action);

      case types.WEBSOCKET_SEND:
        if (websocket) {
          websocket.send(JSON.stringify(action.payload));
        } else {
          consola.warn('WebSocket is not open. To open, dispatch action WEBSOCKET_CONNECT.');
        }

        return next(action);

      case types.WEBSOCKET_DISCONNECT:
        websocket = closeWebSocket(websocket);

        return next(action);

      default:
        return next(action);
    }
  };
};

export default createMiddleware();

Correct warning print to only happen if the socket is not available.


import { createStore, compose, applyMiddleware } from 'redux';
import generateCards from './middlewares/generateCards.js';
import calculateScore from './middlewares/calculateScore.js';
import createLogger from 'redux-logger';
import reducer from './reducers/index.js';

const configureStore = initialState => {
    const logger = createLogger();

    return compose(
        applyMiddleware(logger, generateCards, calculateScore),
        window.devToolsExtension ? window.devToolsExtension() : f => f
    )(createStore)(reducer, initialState);
};

export default configureStore;

import { createStore, compose, applyMiddleware } from 'redux';
import generateCards from './middlewares/generateCards.js';
import calculateScore from './middlewares/calculateScore.js';
import createLogger from 'redux-logger';
import reducer from './reducers/index.js';

const configureStore = initialState => {
    const logger = createLogger();

    return compose(
        applyMiddleware(logger, generateCards, calculateScore),
        typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f
    )(createStore)(reducer, initialState);
};

export default configureStore;

Check window before referencing it to prevent issues when running in Node


var fs = require('fs')
var test = require('tap').test
var walkSync = require('../')

test('walkSync', function (t) {
  t.deepEqual(walkSync('fixtures'), [
    'dir/',
    'dir/bar.txt',
    'dir/subdir/',
    'dir/subdir/baz.txt',
    'dir/zzz.txt',
    'foo.txt',
    'symlink1',
    'symlink2'
  ])
  t.end()
})

var fs = require('fs')
var test = require('tap').test
var walkSync = require('../')

test('walkSync', function (t) {
  t.deepEqual(walkSync('fixtures'), [
    'dir/',
    'dir/bar.txt',
    'dir/subdir/',
    'dir/subdir/baz.txt',
    'dir/zzz.txt',
    'foo.txt',
    'symlink1',
    'symlink2'
  ])

  t.throws(function () {
    walkSync('doesnotexist')
  }, {
    name: 'Error',
    message: "ENOENT, no such file or directory 'doesnotexist/'"
  })

  t.throws(function () {
    walkSync('fixtures/foo.txt')
  }, {
    name: 'Error',
    message: "ENOTDIR, not a directory 'fixtures/foo.txt/'"
  })

  t.end()
})

Test failure modes as well


module.exports = {
  'GitHub example testing': function (test) {
  test
    .open('https://github.com')
    .waitForElement('input[name=q]')
    .assert.title().is('GitHub · Build software better, together.', 'GitHub has the correct page title!')
    .type('input[name=q]', 'dalekjs')
    .submit('.js-site-search-form')
    .assert.text('.sort-bar > h3:nth-child(2)', 'We\'ve found 53 repository results')
    .waitFor(function() {
      return $('li.repo-list-item:nth-child(1) > h3:nth-child(2) > a:nth-child(1)').text() === 'dalekjs/dalek'
    })
    .done();
  }
};

module.exports = {
  'GitHub example testing': function (test) {
  test
    .open('https://github.com')
    .waitForElement('input[name=q]')
    .assert.title().is('GitHub · Build software better, together.', 'GitHub has the correct page title!')
    .type('input[name=q]', 'dalekjs')
    .submit('.js-site-search-form')
    .waitFor(function() {
      return $('li.repo-list-item:nth-child(1) > h3:nth-child(2) > a:nth-child(1)').text() === 'dalekjs/dalek'
    })
    .assert.text('.sort-bar > h3:nth-child(2)', 'We\'ve found 53 repository results')
    .done();
  }
};

Change execution order within test


var chalk = require('chalk');
var inquirer = require('inquirer');
var fs = require('fs-extra');
var path = require('path');

module.exports = function(libDir) {

    return {
        init: init
    };

    function init(name) {
        console.log('Creating a new project: %s', chalk.underline(name));

        inquirer.prompt([{
            type: "confirm",
            name: "needTravis",
            message: "Copying over files to current directory. Press enter to confirm",
            default: true
        }], function(answers) {
            console.log('copying over files...');

            fs.copy(libDir, process.cwd(), function (err) {
              if (err) return console.error(err)
              console.log("success! - files copied");
            })
        })
    }
}

var chalk = require('chalk');
var inquirer = require('inquirer');
var fs = require('fs-extra');
var path = require('path');

var PROMPT_OPTIONS = [{
    type: "confirm",
    name: "okToCopyFiles",
    message: "Copying over files to current directory. Press enter to confirm",
    default: true
}]

module.exports = function(libDir) {

    return {
        init: init
    };

    function init(name) {
        console.log('Creating a new project: %s', chalk.underline(name));
        inquirer.prompt(PROMPT_OPTIONS, inquirerCallback)
    }

    function inquirerCallback(answers) {

        console.log('copying over files...');

        fs.copy(libDir, process.cwd(), function (err) {
          if (err) return console.error(err)
          console.log("success! - files copied");
        })
    }
}

Add prompts to array. Split up copy code into function