export function nbCodesFromId(codeListById, id) {
  return id  ? nbCodes(codeListById[id]) : 0
}

function nbCodes({ isSpec, isLoaded, codes }) {
  return isSpec && !isLoaded ? 10 : codes.length
}

/**
 * Returns the number of code in a code list from its `id`
 *
 * For a code list specification, it returns `1`.
 * If the `id` is not provided, it returns `1`.
 *
 * Explanations :
 *
 * For a code list specification which has not been loaded yet, we do not know
 * the number of codes in the code list. We need this number in order to
 * serialize the questionnaire (how many `Response` do we need to create ?) and
 * for parsing the questionnaire (if we have a TABLE response format with two
 * information axes and multiple measures, how do we know which response goes
 * with which measure ? => We need this informtion to extract the dataytype from
 * thoses responses). If a code list specification has been loaded (ie
 * `isLoaded` set to `true`), we could know the number of codes, but since we
 * cannot ensure that the specification will be loaded when the questionnaire
 * will be parsed, we cannot rely on this number and use 1 as a convention,
 * whether it has been loaded or not.
 *
 * If the `id` is not provided, the user might not have selected the code list
 * yet, so we do not know the number of codes. But since this number will be
 * used to generate responses and responses hold the information about the
 * datatype, we choose to return `1` by default to have at least one response
 * to infer datatype when retrieving a questionnaire.
 *
 * @param  {Object} codeListById collection of code lists (comes from the
 *                               reducer)
 * @param  {String} id           code list id
 * @return {Number}              number of codes in the code list
 */
export function nbCodesFromId(codeListById, id) {
  return id  ? nbCodes(codeListById[id]) : 1
}
/**
 * Returns the number of code in a code list
 *
 * For a code list specification which has not been loaded yet, it returns `1`.
 *
 * @param  {Boolean} isSpec    does this code list comes from a specification
 * @param  {Boolean} isLoaded  if it's a code list specification, has it been
 *                             loaded ?
 * @param  {Array}  codes     codes of the code list
 * @return {Number}           number of codes in the code list
 */
function nbCodes({ isSpec, isLoaded, codes }) {
  return isSpec ? 1 : codes.length
}

Use 1 as a default value for the number of codes in a code list


define([], function() {
    var saveSelection, restoreSelection;
    if (window.getSelection && document.createRange) {
        saveSelection = function(el) {
            var sel = window.getSelection && window.getSelection();
            if (sel && sel.rangeCount > 0) {
                return sel.getRangeAt(0);
            }
        };

        restoreSelection = function(el, sel) {
            var range = document.createRange();
            range.setStart(sel.startContainer, sel.startOffset);
            range.setEnd(sel.endContainer, sel.endOffset)

            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        }
    } else if (document.selection && document.body.createTextRange) {
        saveSelection = function(el) {
            return document.selection.createRange();
        };

        restoreSelection = function(el, sel) {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.setStart(sel.startContanier, sel.startOffset);
            textRange.setEnd(sel.endContainer, sel.endOffset);
            textRange.select();
        };
    }
});

define([], function() {
    var saveSelection, restoreSelection;
    if (window.getSelection && document.createRange) {
        saveSelection = function(el) {
            var sel = window.getSelection && window.getSelection();
            if (sel && sel.rangeCount > 0) {
                return sel.getRangeAt(0);
            }
        };

        restoreSelection = function(el, sel) {
            var range = document.createRange();
            range.setStart(sel.startContainer, sel.startOffset);
            range.setEnd(sel.endContainer, sel.endOffset)

            sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        }
    } else if (document.selection && document.body.createTextRange) {
        saveSelection = function(el) {
            return document.selection.createRange();
        };

        restoreSelection = function(el, sel) {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.setStart(sel.startContainer, sel.startOffset);
            textRange.setEnd(sel.endContainer, sel.endOffset);
            textRange.select();
        };
    }
});

Fix typo startContanier should be startContainer.


import React from 'react';
import {
  Link
} from 'react-router';
import './Menu.css';
import User from './User';
import language from '../language/language';

const menuLanguage = language.components.menu;

let Menu = React.createClass ({

  getInitialState() {
    return { showUser: false };
  },

  onClick(e) {
    e.preventDefault(e);
    if (!this.state.showUser) {
      this.setState({showUser : true});
    } else {
      this.setState({showUser : false});
    }
  },

  render() {

    const {
      user
    } = this.props;

    let userElement;
    userElement = (
      <User
        user={user} />
    );

    return (

            <Link
              to="recent-tracks"
              className="Menu__item">
              {menuLanguage.recentTracks}
            </Link>

            <Link
              to="top-artists"
              className="Menu__item">
              {menuLanguage.topArtists}
            </Link>

            <Link
              className="Menu__item"
              onClick={this.onClick}>
              {menuLanguage.userInfo}
            </Link>

        {this.state.showUser ? userElement : null}

    );
  }
});

export default Menu;

import React from 'react';
import {
  Link
} from 'react-router';
import './Menu.css';
import User from './User';
import language from '../language/language';

const menuLanguage = language.components.menu;

let Menu = React.createClass ({

  getInitialState() {
    return { showUser: false };
  },

  toggleUser(e) {
    e.preventDefault(e);
    if (!this.state.showUser) {
      this.setState({showUser : true});
    } else {
      this.setState({showUser : false});
    }
  },

  render() {

    const {
      user
    } = this.props;

    let userElement;
    userElement = (
      <User
        user={user} />
    );

    return (

            <Link
              to="recent-tracks"
              className="Menu__item">
              {menuLanguage.recentTracks}
            </Link>

            <Link
              to="top-artists"
              className="Menu__item">
              {menuLanguage.topArtists}
            </Link>

            <Link
              className="Menu__item"
              onClick={this.toggleUser}>
              {menuLanguage.userInfo}
            </Link>

        {this.state.showUser ? userElement : null}

    );
  }
});

export default Menu;

Rename click handler function so it’s more explicit what it does


angular.module('webapp').factory('mp', function($q, $rootScope, $timeout, host) {
	var socket = new WebSocket("ws://" + host + ":8080/stomp");

	var stompClient = Stomp.over(socket);
	//stompClient.debug = angular.noop();

	var connectedDeferred = $q.defer();
	var connected = connectedDeferred.promise;

	stompClient.connect({}, function() {
		connectedDeferred.resolve();
	});

	return {
		connected: connected,

		subscribe: function(queue, callback) {
			connected.then(function() {
				stompClient.subscribe(queue, function(frame) {
					$timeout(function() {
						if (typeof frame.body === 'string' && frame.body && (frame.body.charAt(0) === '{' || frame.body.charAt(0) === '['))
							frame.body = JSON.parse(frame.body);
						callback(frame);
					})
				});
			})
		},

		send: function(destination, message) {
			if (typeof message === 'object')
				message = JSON.stringify(message);
			connected.then(function() {
				stompClient.send(destination, {}, message);
			})
		}
	}
});

angular.module('webapp').factory('mp', function($q, $rootScope, $timeout, host) {
	var socket = new WebSocket("ws://" + host + ":8080/stomp");

	var stompClient = Stomp.over(socket);
	stompClient.debug = angular.noop();

	var connectedDeferred = $q.defer();
	var connected = connectedDeferred.promise;

	stompClient.connect({}, function() {
		connectedDeferred.resolve();
	});

	return {
		connected: connected,

		subscribe: function(queue, callback) {
			connected.then(function() {
				stompClient.subscribe(queue, function(frame) {
					$timeout(function() {
						if (typeof frame.body === 'string' && frame.body && (frame.body.charAt(0) === '{' || frame.body.charAt(0) === '['))
							frame.body = JSON.parse(frame.body);
						callback(frame);
					})
				});
			})
		},

		send: function(destination, message) {
			if (typeof message === 'object')
				message = JSON.stringify(message);
			connected.then(function() {
				stompClient.send(destination, {}, message);
			})
		}
	}
});

Revert accidental commit of debug logging


$().ready(() => {
  loadContentSection().then(() =>{
    $("#loader").addClass("hide");
    $("#real-body").removeClass("hide");
    $("#real-body").addClass("body");

    $(".keyword").click(function() {
      $(this).addClass("active");
      $(".base").hide(200);
      $("#real-body").addClass("focus");
    });

    $(".close").click(function(event) {
      event.stopPropagation();
      $(this).parent().removeClass("active");
      $(".base").show(200);
      $("#real-body").removeClass("focus");
    });

    $(".active .item").click(function() {
      $(".item").off("click");
      const url = $(this).attr("data-url");
      window.location.replace(url);
    });
  });
});

$().ready(() => {
  loadContentSection().then(() =>{
    $("#loader").addClass("hide");
    $("#real-body").removeClass("hide");
    $("#real-body").addClass("body");

    $(".keyword").click(function() {
      $(this).addClass("active");
      $(".base").hide(200);
      $("#real-body").addClass("focus");
      $(".active .item").click(function() {
        $(".item").off("click");
        const url = $(this).attr("data-url");
        window.location.href = url;
      });
    });

    $(".close").click(function(event) {
      event.stopPropagation();
      $(this).parent().removeClass("active");
      $(".base").show(200);
      $("#real-body").removeClass("focus");
    });
  });
});

Fix redirecting and back button bug


import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';

import { logoutUser } from '../../redux/actions';

const NavBar = ({ isAuthenticated, logoutUser }) => (

<Link to="/">Home</Link>

        { isAuthenticated &&
            [

<Link to="/history">History</Link>
,

<Link to="/history/april">April</Link>
,

<Link to="/stopwatch">Stopwatch</Link>

            ]
        }
        { !isAuthenticated &&
            [

<Link to="/signup">Signup</Link>
,

                    <Link to="/login">Login</Link>

            ]
        }
        { isAuthenticated &&

                <button onClick={ logoutUser }>Logout</button>

        }

);

export default connect(
    ({ root }) => ({ isAuthenticated: root.isAuthenticated }),
    { logoutUser }
)(NavBar);

Fix React missing key iterator warning


var STATUSES = {
  UP: 0,
  DOWN: 1
}
var mouseStatus = {
  left: STATUSES.UP,
  right: STATUSES.UP
}

var BUTTONS = {
  LEFT: 1,
  RIGHT: 3
};

document.onmousedown = function(event) {
  if (event.which === BUTTONS.LEFT) {
    mouseStatus.left = STATUSES.DOWN;
    if (mouseStatus.right === STATUSES.DOWN) {
      chrome.extension.sendMessage({
        event: 'previous',
        mouseStatus: mouseStatus
      });
    }
  } else if (event.which === BUTTONS.RIGHT) {
    mouseStatus.right = STATUSES.DOWN;

    if (mouseStatus.left === STATUSES.DOWN) {
      chrome.extension.sendMessage({
        event: 'next',
        mouseStatus: mouseStatus
      });
    }
  }
};

document.onmouseup = function(event) {
  if (event.which === BUTTONS.LEFT) {
    mouseStatus.left = STATUSES.UP;
  } else if (event.which === BUTTONS.RIGHT) {
    mouseStatus.right = STATUSES.UP;
  }
  chrome.extension.sendMessage({mouseStatus: mouseStatus});
};

document.oncontextmenu = function(event) {
  if (mouseStatus.left === STATUSES.DOWN) {
    return false;
  }
};

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  mouseStatus = request;
});

var STATUSES = {
  UP: 0,
  DOWN: 1
}
var mouseStatus = {
  left: STATUSES.UP,
  right: STATUSES.UP
}

var BUTTONS = {
  LEFT: 1,
  RIGHT: 3
};

document.addEventListener('mousedown', function(event) {
  if (event.which === BUTTONS.LEFT) {
    mouseStatus.left = STATUSES.DOWN;
    if (mouseStatus.right === STATUSES.DOWN) {
      chrome.extension.sendMessage({
        event: 'previous',
        mouseStatus: mouseStatus
      });
    }
  } else if (event.which === BUTTONS.RIGHT) {
    mouseStatus.right = STATUSES.DOWN;

    if (mouseStatus.left === STATUSES.DOWN) {
      chrome.extension.sendMessage({
        event: 'next',
        mouseStatus: mouseStatus
      });
    }
  }
});

document.addEventListener('mouseup', function(event) {
  if (event.which === BUTTONS.LEFT) {
    mouseStatus.left = STATUSES.UP;
  } else if (event.which === BUTTONS.RIGHT) {
    mouseStatus.right = STATUSES.UP;
  }
  chrome.extension.sendMessage({mouseStatus: mouseStatus});
});

document.addEventListener('contextmenu', function(event) {
  if (mouseStatus.left === STATUSES.DOWN) {
    return event.preventDefault();
  }
});

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  mouseStatus = request;
});

Use addEventListener instead of setting old onmouse* properties


define(['mathlive/mathlive'],
    function(mLive) {
	  MathLive = mLive;
	  MathLive.renderMathInDocument();
	  TheActiveMathField = MathLive.makeMathField(
		document.getElementById('mathEditorActive'),
	  	{//commandbarToggle: 'hidden',
		 overrideDefaultInlineShortcuts: false,
		 onSelectionDidChange: UpdatePalette
		}
	  );
	}
)

define(['mathlive/mathlive'],
    function(mLive) {
	  MathLive = mLive;
	  MathLive.renderMathInDocument();
	  TheActiveMathField = MathLive.makeMathField(
		document.getElementById('mathEditorActive'),
	  	{commandbarToggle: 'hidden',
		 overrideDefaultInlineShortcuts: false,
		 onSelectionDidChange: UpdatePalette,
		}
	  );
	  document.onkeydown = HandleKeyDown;
	}
)

Add handler for cntl+backspace/delete to be a crossout


const {app, BrowserWindow} = require('electron')
const path = require('path')
const url = require('url')

let win

function createWindow () {
  win = new BrowserWindow({width: 650, height: 450})

  win.loadURL(url.format({
    pathname: path.join(__dirname, 'public/index.html'),
    protocol: 'file:',
    slashes: true
  }))

  if (process.env.REACT_DEBUG) {
    BrowserWindow.addDevToolsExtension(process.env.REACT_DEBUG)
    win.webContents.openDevTools()
  }

  win.on('closed', () => {
    win = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (win === null) {
    createWindow()
  }
})

const {app, shell, BrowserWindow, Menu} = require('electron')
const path = require('path')
const url = require('url')

let win

process.env.PATH = `${process.env.PATH}:/usr/local/bin`

const menu = Menu.buildFromTemplate([
  {
    label: app.getName(),
    submenu: [{
      label: 'About',
      click() {
        shell.openExternal('https://github.com/jysperm/elecpass')
      }
    },{
      label: 'Open DevTools',
      click() {
        win.webContents.openDevTools()
      }
    },{
      role: 'quit'
    }]
  }
])

function createWindow () {
  Menu.setApplicationMenu(menu)

  win = new BrowserWindow({width: 650, height: 450})

  win.loadURL(url.format({
    pathname: path.join(__dirname, 'public/index.html'),
    protocol: 'file:',
    slashes: true
  }))

  if (process.env.REACT_DEBUG) {
    BrowserWindow.addDevToolsExtension(process.env.REACT_DEBUG)
    win.webContents.openDevTools()
  }

  win.on('closed', () => {
    win = null
  })
}

app.on('ready', createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (win === null) {
    createWindow()
  }
})

Add menu to open dev tools


var uuid = require('node-uuid');
var JSData = require('js-data');

var store;
var adapter;
var Report;

function error(msg) {
  return new Promise(function(resolve, reject) {
    return resolve({ error: msg });
  });
}

function get(id) {
  if (!id) return error('No id specified.');

  if (!adapter) {
    return new Promise(function(resolve) {
      var report = Report.get(id);
      return resolve(report);
    });
  }
  return Report.find(id);
}

function add(data) {
  if (!data.type || !data.payload) {
    return error('Required parameters aren\'t specified.');
  }

  var obj = {
    id: uuid.v4(),
    type: data.type,
    payload: data.payload
  };

  if (!adapter) {
    return new Promise(function(resolve) {
      var report = Report.inject(obj);
      return resolve(report);
    });
  }
  return Report.create(obj);
}

function createStore(options) {
  store = new JSData.DS();
  Report = store.defineResource('report');

  return {
    get: get,
    add: add
  };
}

module.exports = createStore;

var uuid = require('node-uuid');
var JSData = require('js-data');

var store;
var adapter;
var Report;

function error(msg) {
  return new Promise(function(resolve, reject) {
    return resolve({ error: msg });
  });
}

function get(id) {
  if (!id) return error('No id specified.');

  if (!adapter) {
    return new Promise(function(resolve) {
      var report = Report.get(id);
      return resolve(report);
    });
  }
  return Report.find(id);
}

function add(data) {
  if (!data.type || !data.payload) {
    return error('Required parameters aren\'t specified.');
  }

  var obj = {
    id: uuid.v4(),
    type: data.type,
    title: data.title,
    description: data.description,
    failed: data.failed,
    payload: data.payload,
    screen: data.screen,
    user: data.user,
    isLog: !!data.isLog,
    added: Date.now()
  };

  if (!adapter) {
    return new Promise(function(resolve) {
      var report = Report.inject(obj);
      return resolve(report);
    });
  }
  return Report.create(obj);
}

function createStore(options) {
  store = new JSData.DS();
  Report = store.defineResource('report');

  return {
    get: get,
    add: add
  };
}

module.exports = createStore;

Add more data to the report


const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const path = require("path");

module.exports = {
    mode: "development",
    devtool: "inline-source-map",
    entry: {
        IntelliSearch: "./src/SearchClient.ts",
        "IntelliSearch.min": "./src/SearchClient.ts"
    },
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "[name].js",
        libraryTarget: "umd",
        library: "IntelliSearch",
        umdNamedDefine: true
    },
    resolve: {
        mainFields: ["browser", "module", "main"],
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: [".ts", ".tsx", ".js"]
    },
    plugins: [
        new UglifyJsPlugin({
            sourceMap: true,
            include: /\.min\.js$/
        })
    ],
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            {
                test: /\.tsx?$/,
                loader: "ts-loader"
            }
        ]
    },
    watch: false,
    watchOptions: {
        aggregateTimeout: 300, // The default
        ignored: ["dist", "es", "lib", "doc", "samples", "node_modules"]
    }
};

const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const path = require("path");

module.exports = {
    mode: "development",
    devtool: "inline-source-map",
    entry: {
        IntelliSearch: "./src/SearchClient.ts",
        "IntelliSearch.min": "./src/SearchClient.ts"
    },
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "[name].js",
        libraryTarget: "umd",
        library: "IntelliSearch",
        umdNamedDefine: true
    },
    resolve: {
        mainFields: ["browser", "module", "main"],
        // Add `.ts` and `.tsx` as a resolvable extension.
        extensions: [".ts", ".tsx", ".js"]
    },
    plugins: [
        new UglifyJsPlugin({
            sourceMap: false,
            extractComments: true,
            include: /\.min\.js$/
        })
    ],
    module: {
        rules: [
            // all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`
            {
                test: /\.tsx?$/,
                loader: "ts-loader"
            }
        ]
    },
    watch: false,
    watchOptions: {
        aggregateTimeout: 300, // The default
        ignored: ["dist", "es", "lib", "doc", "samples", "node_modules"]
    }
};

Remove comments and source-map from the minified version.


var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: {
    index: './src/main/index.js'
  },
  output: {
    path: './target/out',
    filename: '[name].js',
    libraryTarget: 'commonjs'
  },
  externals: [
    {
      'react': true,
      'react-dom': true
    }
  ],
  plugins: [
    new ExtractTextPlugin('[name].css')
  ],
  module: {
    loaders: [
      {test: /\.js$/, loader: 'babel'},
      {test: /\.less$/, loader: ExtractTextPlugin.extract('style', 'css!less?strictUnits=true&strictMath=true')}
    ]
  }
};

var path = require('path'),
    ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
  entry: {
    index: [
      './src/main/index.js',
      './src/main/index.less'
    ]
  },
  output: {
    path: './target/out',
    filename: '[name].js',
    libraryTarget: 'commonjs'
  },
  externals: [
    {
      'react': true,
      'react-dom': true
    }
  ],
  resolve: {
    root: [
      path.resolve(__dirname, '..'),
      path.resolve(__dirname, 'node_modules')
    ]
  },
  plugins: [
    new ExtractTextPlugin('[name].css')
  ],
  module: {
    loaders: [
      {test: /\.js$/, loader: 'babel'},
      {test: /\.less$/, loader: ExtractTextPlugin.extract('style', 'css!less?strictUnits=true&strictMath=true')}
    ]
  }
};

Build styles apart from JS code


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

const exec = require('child_process').exec;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec('node --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

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

const exec = require('child_process').exec;
const nodepath = process.env._;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec(nodepath+' --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

Use node path from process.env._


// Modules
var http = require('http'),
    urllib = require('url'),
    RPCHandler = require('jsonrpc').RPCHandler,
    scheduler = require('./schedulerRpcWrapper');

// Configuration
var cfg = require('config')('ControlNode', {
  port: 46212,
  address: "",
  jsonRpcPath: "/jsonrpc",
  debugRpc: false
});

// Local variables
var version = "0.1.4"
    versionString = "ControlNode " + version + " on node.js";

var schedulerWrapper = new scheduler.Wrapper(cfg.mongodbAddress);

var handleHttpRequest = function(req, res) {
    if(req.method == "POST"){
        // Define whether this is JSON request.
        if (urllib.parse(req.url).pathname == cfg.jsonRpcPath) {
            new RPCHandler(req, res, schedulerWrapper, cfg.debugRpc);
        } else {
            res.writeHead(404, {'Content-Type': 'text/plain'});
            res.end('Unknown path!\n');
        }
    } else {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        //res.end('Hello World\n');
        res.end(JSON.stringify(schedulerWrapper.getStatus(), null, 4))
    }
};

// Run server.
http.createServer(handleHttpRequest).listen(cfg.port, cfg.address);
console.log(['Server running at http://', cfg.address, ':', cfg.port, ' on ',
             process.version].join(''));

// Modules
var http = require('http'),
    urllib = require('url'),
    RPCHandler = require('jsonrpc').RPCHandler,
    scheduler = require('./schedulerRpcWrapper');

// Configuration
var cfg = require('config')('ControlNode', {
  port: 46212,
  address: "",
  jsonRpcPath: "/jsonrpc",
  debugRpc: false
});

// Local variables
var version = "0.1.5",
    versionString = ["ControlNode;v", version, ";node.js ", process.version].join("");

var schedulerWrapper = new scheduler.Wrapper(cfg.mongodbAddress);

var handleHttpRequest = function(req, res) {
    if(req.method == "POST"){
        // Define whether this is JSON request.
        if (urllib.parse(req.url).pathname == cfg.jsonRpcPath) {
            new RPCHandler(req, res, schedulerWrapper, cfg.debugRpc);
        } else {
            res.writeHead(404, {'Content-Type': 'text/plain'});
            res.end('Unknown path!\n');
        }
    } else {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        //res.end('Hello World\n');
        res.end(JSON.stringify(schedulerWrapper.getStatus(), null, 4))
    }
};

// Run server.
http.createServer(handleHttpRequest).listen(cfg.port, cfg.address);
console.log([versionString, ";at http://", cfg.address, ':', cfg.port].join(''));

Change version string in control node.


const { Compile } = require("@truffle/compile-solidity");

class DebugCompiler {
  constructor(config) {
    this.config = config;
  }

  async compile(sources = undefined) {
    const compileConfig = this.config.with({ quiet: true });

    const { compilations } = sources
      ? await Compile.sources({ sources, options: compileConfig }) //used by external.js
      : await Compile.all(compileConfig);

    return compilations;
  }
}

module.exports = {
  DebugCompiler
};

const { Compile } = require("@truffle/compile-solidity");
const WorkflowCompile = require("@truffle/workflow-compile");

class DebugCompiler {
  constructor(config) {
    this.config = config;
  }

  async compile(sources = undefined) {
    const compileConfig = this.config.with({ quiet: true });

    const { compilations } = sources
      ? await Compile.sources({ sources, options: compileConfig }) //used by external.js
      : await WorkflowCompile.compile(compileConfig.with({ all: true }));
    //note: we don't allow for the possibility here of compiling with specified sources
    //that are *not* solidity.  only external.js specifies sources, and making that work
    //with Vyper is a hard problem atm (how do we get the right version??)

    return compilations;
  }
}

module.exports = {
  DebugCompiler
};

Allow CLI debugger to compile non-Solidity sources


var AudioChannel = function(args) {
  this.context = AudioContext ? new AudioContext() : new webkitAudioContext();
  this.oscill = this.context.createOscillator();
  this.gain = this.context.createGain();

  if(args) {
    this.frequency = args.freq ? args.freq : 220;
    this.wave = args.wave ? args.wave : "triangle";
    this.volume = args.gain ? args.gain : 0.05;
  }
}
AudioChannel.prototype.setNodes = function() {
  this.oscill = this.context.createOscillator();
  this.gain = this.context.createGain();

  this.oscill.connect(this.gain);
  this.gain.connect(this.context.destination);

  this.oscill.frequency.value = this.frequency;
  this.oscill.type = this.wave;
  this.gain.gain.value = this.volume;
};
AudioChannel.prototype.playSong = function(song) {
  this.oscill.start();
  var playNextNote = function(song) {
    this.oscill.frequency.value = song[0].freq;
    if(song[1]) {
      setTimeout(playNextNote.bind(this, song.slice(1)), song[0].length);
    }
    else {
      setTimeout(function() {
        this.gain.gain.value = 0;
      }.bind(this), song[0].length);
    }
  }.bind(this);
  playNextNote(song);
};

var AudioChannel = function(args) {
  this.context = AudioContext ? new AudioContext() : new webkitAudioContext();
  this.oscill = this.context.createOscillator();
  this.gain = this.context.createGain();

  var args = args ? args : {};

  this.frequency = args.freq ? args.freq : 220;
  this.wave = args.wave ? args.wave : "triangle";
  this.volume = args.gain ? args.gain : 0.05;
}
AudioChannel.prototype.setNodes = function() {
  this.oscill = this.context.createOscillator();
  this.gain = this.context.createGain();

  this.oscill.connect(this.gain);
  this.gain.connect(this.context.destination);

  this.oscill.frequency.value = this.frequency;
  this.oscill.type = this.wave;
  this.gain.gain.value = this.volume;
};
AudioChannel.prototype.playSong = function(song) {
  this.setNodes();
  this.oscill.start();
  var playNextNote = function(song) {
    this.oscill.frequency.value = noteToFreq(song[0].note, song[0].octave);
    if(song[1]) {
      setTimeout(playNextNote.bind(this, song.slice(1)), song[0].length);
    }
    else {
      setTimeout(function() {
        this.gain.gain.value = 0;
      }.bind(this), song[0].length);
    }
  }.bind(this);
  playNextNote(song);
};

Update AudioChannel.playSong to use noteToFreq


/**
 * Image.js
 *
 * @description :: This represents a product image with file paths for different variations (original, thumb, ...).
 * @docs        :: http://sailsjs.org/documentation/concepts/models-and-orm/models
 */

module.exports = {

  attributes: {

    width: {
      type: 'integer',
      min: 0
    },

    height: {
      type: 'integer',
      min: 0
    },

    thumb: {
      type: 'string'
    },

    medium: {
      type: 'string'
    },

    large: {
      type: 'string'
    },

    original: {
      type: 'string',
      required: true
    },

    toJSON: function() {

      var obj = this.toObject()
        , baseUrl = sails.config.app.baseUrl;

      if (obj.thumb) {
        obj.thumb = baseUrl + obj.thumb;
      }

      if (obj.medium) {
        obj.medium = baseUrl + obj.medium;
      }

      if (obj.large) {
        obj.large = baseUrl + obj.large;
      }

      obj.original = baseUrl + obj.original;

      return obj;

    }

  },

  beforeUpdate: function (values, next) {

    // Prevent user from overriding these attributes
    delete values.thumb;
    delete values.medium;
    delete values.large;
    delete values.original;
    delete values.createdAt;
    delete values.updatedAt;

    next();

  }

};

/**
 * Image.js
 *
 * @description :: This represents a product image with file paths for different variations (original, thumb, ...).
 * @docs        :: http://sailsjs.org/documentation/concepts/models-and-orm/models
 */

module.exports = {

  attributes: {

    width: {
      type: 'integer',
      min: 0
    },

    height: {
      type: 'integer',
      min: 0
    },

    thumb: {
      type: 'string'
    },

    medium: {
      type: 'string'
    },

    large: {
      type: 'string'
    },

    original: {
      type: 'string',
      required: true
    },

    toJSON: function() {

      var obj = this.toObject()
        , baseUrl = sails.config.app.baseUrl;

      if (obj.thumb) {
        obj.thumb = baseUrl + obj.thumb;
      }

      if (obj.medium) {
        obj.medium = baseUrl + obj.medium;
      }

      if (obj.large) {
        obj.large = baseUrl + obj.large;
      }

      obj.original = baseUrl + obj.original;

      return obj;

    }

  },

  beforeUpdate: function (values, next) {

    if (obj.thumb && obj.thumb.indexOf('http') === 0) {
      delete obj.thumb;
    }

    if (obj.medium && obj.medium.indexOf('http') === 0) {
      delete obj.medium;
    }

    if (obj.large && obj.large.indexOf('http') === 0) {
      delete obj.large;
    }

    // Prevent user from overriding these attributes
    delete values.original;
    delete values.createdAt;
    delete values.updatedAt;

    next();

  }

};

Fix bug where images could not be created


"use strict";

function createDefaultFormatter() {
  return function defaultFormatter(ctx, errors) {
    ctx.body = {};
    if (errors && errors.length) {
      ctx.status = 500;
      if (errors.length === 1) {
        ctx.status = errors[0].status;
      }
      ctx.body['ok'] = 0;
      ctx.body['status'] = ctx.status;
      ctx.body['errors'] = errors.map((error) => {
        return error.message;
      });
    } else {
      ctx.body['ok'] = 1;
    }
    ctx.body['status'] = ctx.status;
    if (ctx.result != null) {
      ctx.body['result'] = ctx.result;
    }
  }
}

module.exports = function (options) {
  options = options || {};
  const fn = options.formatter || createDefaultFormatter();
  return function formatter(ctx, next) {
    const self = this;
    return next().then(function () {
      fn(ctx);
    }).catch(function (err) {
      var errors;
      if (Array.isArray(err)) {
        errors = err;
      } else {
        errors = [ err ];
      }
      fn(ctx, errors);
      for (var i = 0; i < errors.length; i++) {
        ctx.app.emit('error', errors[i], self);
      }
    });
  }

};

module.exports.defaultFormatter = createDefaultFormatter;

"use strict";

function createDefaultFormatter() {
  return function defaultFormatter(ctx, errors) {
    ctx.body = {};
    if (errors && errors.length) {
      ctx.status = 500;
      if (errors.length === 1) {
        ctx.status = errors[0].status || ctx.status;
      }
      ctx.body['ok'] = 0;
      ctx.body['status'] = ctx.status;
      ctx.body['errors'] = errors.map((error) => {
        return error.message;
      });
    } else {
      ctx.body['ok'] = 1;
    }
    ctx.body['status'] = ctx.status;
    if (ctx.result != null) {
      ctx.body['result'] = ctx.result;
    }
  }
}

module.exports = function (options) {
  options = options || {};
  const fn = options.formatter || createDefaultFormatter();
  return function formatter(ctx, next) {
    const self = this;
    return next().then(function () {
      fn(ctx);
    }).catch(function (err) {
      var errors;
      if (Array.isArray(err)) {
        errors = err;
      } else {
        errors = [ err ];
      }
      fn(ctx, errors);
      for (var i = 0; i < errors.length; i++) {
        ctx.app.emit('error', errors[i], self);
      }
    });
  }

};

module.exports.defaultFormatter = createDefaultFormatter;

Add status fallback when an error does not expose one


"use strict";

var util = require("util");

var AbstractError = require("./AbstractError.js"),
    defaultRenderer = require("./defaultRenderer.js");

/**
 * generate Error-classes based on AbstractError
 *
 * @param error
 * @returns {Function}
 */
function erroz(error) {

    var errorFn = function (data) {

        //add per instance properties
        this.data = data;
        this.message = this.message || erroz.options.renderMessage(error.template, data);

        errorFn.super_.call(this, this.constructor);
    };

    util.inherits(errorFn, AbstractError);

    //add static error properties (name, status, etc.)
    for (var errKey in error) {
        if (error.hasOwnProperty(errKey)) {
            errorFn.prototype[errKey] = error[errKey];
        }
    }

    errorFn.prototype.toJSON = function() {

        var data = this.data;

        if(erroz.options.includeStack) {
            data.stack = this.stack;
        }

        return {
            status: this.status,
            code: this.code,
            message: this.message,
            data: data
        };
    };

    return errorFn;
}

erroz.options = {
    /**
     * overwrite this function for custom rendered messages
     *
     * @param {Object} data
     * @param {String=} template
     * @returns {String}
     */
    renderMessage: defaultRenderer,
    includeStack: true
};

module.exports = erroz;

"use strict";

var util = require("util");

var AbstractError = require("./AbstractError.js"),
    defaultRenderer = require("./defaultRenderer.js");

/**
 * generate Error-classes based on AbstractError
 *
 * @param error
 * @returns {Function}
 */
function erroz(error) {

    var errorFn = function (data) {

        //add per instance properties
        this.data = data;
        this.message = this.message || erroz.options.renderMessage(error.template, data);

        errorFn.super_.call(this, this.constructor);
    };

    util.inherits(errorFn, AbstractError);

    //add static error properties (name, status, etc.)
    for (var errKey in error) {
        if (error.hasOwnProperty(errKey)) {
            errorFn.prototype[errKey] = error[errKey];
        }
    }

    errorFn.prototype.toJSON = function() {

        var data = this.data || {};

        if(erroz.options.includeStack) {
            data.stack = this.stack;
        }

        return {
            status: this.status,
            code: this.code,
            message: this.message,
            data: data
        };
    };

    return errorFn;
}

erroz.options = {
    /**
     * overwrite this function for custom rendered messages
     *
     * @param {Object} data
     * @param {String=} template
     * @returns {String}
     */
    renderMessage: defaultRenderer,
    includeStack: true
};

module.exports = erroz;

Handle toJSON call with missing this.data


const fm = require('gray-matter');

// makes mdx in next.js suck less by injecting necessary exports so that
// the docs are still readable on github
// (Shamelessly stolen from Expo.io docs)
// @see https://github.com/expo/expo/blob/master/docs/common/md-loader.js
module.exports = async function (src) {
  const callback = this.async();
  const { content, data } = fm(src);
  const layout = data.layout || 'Docs';
  const code =
    `import { Layout${layout} } from 'components/Layout${layout}';
export const meta = ${JSON.stringify(data)};
export default ({ children, ...props }) => (
  <Layout${layout} meta={meta} {...props}>{children}</Layout${layout}>
);

` + content;

  return callback(null, code);
};

const fm = require('gray-matter');

// makes mdx in next.js suck less by injecting necessary exports so that
// the docs are still readable on github
// (Shamelessly stolen from Expo.io docs)
// @see https://github.com/expo/expo/blob/master/docs/common/md-loader.js
module.exports = async function (src) {
  const callback = this.async();
  const { content, data } = fm(src);
  const layout = data.layout || 'Docs';
  const code =
    `import { Layout${layout} } from 'components/Layout${layout}';

export default function Wrapper ({ children, ...props }) { return (
  <Layout${layout} meta={${JSON.stringify(
      data
    )}} {...props}>{children}</Layout${layout}>
);
}

` + content;

  return callback(null, code);
};

Enable fast refresh on mdx pages


"use strict";

$(document).ready(function() {
    $("#link_play").click(function (event) {
        $.cookie("user_name", $("#credentials").find("input#username").val());
        return true;
    });
});

"use strict";

$(document).ready(function() {
    $("#link_play").click(function (event) {
        $.cookie(
            "user_name",
            $("#credentials").find("input#username").val(),
            {path: "/page/"}
        );
        return true;
    });
});

Set user name cookie only for the /page/ path where it is used.


var program = require('commander');
var pkg = require('../package.json');
var GitterBot = require('../lib/GitterBot');

program
  .version(pkg.version)
  .description('Gitter bot for evaluating expressions')
  .usage('[options]')
  .option('-k, --key <key>', 'Set API key')
  .option('-r, --room <room>', 'Set room')
  .parse(process.argv);

var bot = new GitterBot({apiKey: program.key, roomName: program.room});
process.on('exit', bot.destroy.bind(bot));

var program = require('commander');
var pkg = require('../package.json');
var GitterBot = require('../lib/GitterBot');

program
  .version(pkg.version)
  .description('Gitter bot for evaluating expressions')
  .usage('[options]')
  .option('-k, --key <key>', 'Set API key')
  .option('-r, --room <room>', 'Set room')
  .option('-p, --pattern <pattern>', 'Set execution pattern')
  .parse(process.argv);

var bot = new GitterBot({apiKey: program.key, roomName: program.room, execPattern: program.pattern});
process.on('exit', bot.destroy.bind(bot));

Add overriding pattern from CLI


import echoRidge from './echo-ridge';
import fireflies from './fireflies';

export default [
  echoRidge,
  fireflies
];

export default [
  require('./echo-ridge').default,
  require('./fireflies').default
];

Clean up the portfolio imports


"use strict";

module.exports = {
    rules: {
        "sort-object-props": function(context) {
            var caseSensitive = context.options[0].caseSensitive;
            var ignoreMethods = context.options[0].ignoreMethods;
            var ignorePrivate = context.options[0].ignorePrivate;

            var MSG = "Property names in object literals should be sorted";
            return {
                "ObjectExpression": function(node) {
                    node.properties.reduce(function(lastProp, prop) {
                        if (ignoreMethods &&
                                prop.value.type === "FunctionExpression") {
                            return prop;
                        }
                        var lastPropId, propId;
                        if (prop.key.type === "Identifier") {
                            lastPropId = lastProp.key.name;
                            propId = prop.key.name;
                        } else if (prop.key.type === "Literal") {
                            lastPropId = lastProp.key.value;
                            propId = prop.key.value;
                        }
                        if (caseSensitive) {
                            lastPropId = lastPropId.toLowerCase();
                            propId = propId.toLowerCase();
                        }

                        if (ignorePrivate && /^_/.test(propId)) {
                          return prop;
                        }

                        if (propId < lastPropId) {
                            context.report(prop, MSG);
                        }
                        return prop;
                    }, node.properties[0]);
                }
            };
        }
    },
    rulesConfig: {
        "sort-object-props": [ 1, { caseSensitive: false, ignoreMethods: false } ]
    }
};

"use strict";

module.exports = {
    rules: {
        "sort-object-props": function(context) {
            var caseSensitive = context.options[0].caseSensitive;
            var ignoreMethods = context.options[0].ignoreMethods;
            var ignorePrivate = context.options[0].ignorePrivate;

            var MSG = "Property names in object literals should be sorted";
            return {
                "ObjectExpression": function(node) {
                    node.properties.reduce(function(lastProp, prop) {
                        if (ignoreMethods &&
                                prop.value.type === "FunctionExpression") {
                            return prop;
                        }
                        var lastPropId, propId;
                        if (prop.key.type === "Identifier") {
                            lastPropId = lastProp.key.name;
                            propId = prop.key.name;
                        } else if (prop.key.type === "Literal") {
                            lastPropId = lastProp.key.value;
                            propId = prop.key.value;
                        }
                        if ((caseSensitive) && (lastPropId !== undefined)) {
                            lastPropId = lastPropId.toLowerCase();
                            propId = propId.toLowerCase();
                        }

                        if (ignorePrivate && /^_/.test(propId)) {
                          return prop;
                        }

                        if (propId < lastPropId) {
                            context.report(prop, MSG);
                        }
                        return prop;
                    }, node.properties[0]);
                }
            };
        }
    },
    rulesConfig: {
        "sort-object-props": [ 1, { caseSensitive: false, ignoreMethods: false } ]
    }
};

Add checking if lastPropId is undefined


module.exports = function (app) {
  // Default conf.
  app.conf.add({
    vhosts: {
      match: 'hostname',
      notFound: true
    }
  });

  // Depends on cantina-web.
  app.require('cantina-web');

  // Load stuff.
  app.load('plugins');
  app.load('middleware');
};

module.exports = function (app) {
  // Default conf.
  app.conf.add({
    vhosts: {
      match: 'hostname',
      middleware: true,
      notFound: true
    }
  });

  // Depends on cantina-web.
  app.require('cantina-web');

  // Load stuff.
  app.load('plugins');
  if (app.conf.get('vhosts:middleware')) {
    app.load('middleware');
  }
};

Allow middleware to be disabled.


/*
 * redbloom
 * Copyright(c) 2016 Benjamin Bartolome
 * Apache 2.0  Licensed
 */

'use strict';

module.exports = redbloom;

var ee = require('event-emitter');

var Immutable = require('immutable');
var Rx = require('rx');

function redbloom(initialState, options) {
	var state = Immutable.Map(initialState || {}); // eslint-disable-line new-cap
	var instance = ee({});

	var bloomrun = require('bloomrun')(options);

	bloomrun.default((action, currentState) => {
		return currentState;
	});

	var observable = Rx.Observable
		.fromEvent(instance, 'dispatch')
		.concatMap(action => {
			var listActions = () => {
				var listActions = bloomrun.list(action);
				if (listActions.length == 0) {
					listActions.push(bloomrun.lookup(action))
				}
				return listActions;
			}
			return Rx.Observable
				.from(listActions())
				.map(reducer =>	reducer.bind(observable, action));
		})
		.scan((currentState, reducer) => reducer(currentState), state);

	observable.handle = (action, reducer) => bloomrun.add(action, reducer);
	observable.dispatch = action => instance.emit('dispatch', action);

	return observable;
}

/*
 * redbloom
 * Copyright(c) 2016 Benjamin Bartolome
 * Apache 2.0  Licensed
 */

'use strict';

module.exports = redbloom;

var ee = require('event-emitter');

var Immutable = require('immutable');
var Rx = require('rx');

function redbloom(initialState, options) {
	var state = Immutable.Map(initialState || {}); // eslint-disable-line new-cap
	var instance = ee({});

	var bloomrun = require('bloomrun')(options);
	bloomrun.default((action, currentState) => {
		return currentState;
	});
	var observable = Rx.Observable
		.fromEvent(instance, 'dispatch')
		.concatMap(action => {
			var listActions = () => {
				var listActions = bloomrun.list(action);
				if (listActions.length == 0) {
					listActions.push(bloomrun.lookup(action))
				}
				return listActions;
			}
			return Rx.Observable
				.from(listActions())
				.map(reducer =>	reducer.bind(observable, action));
		})
		.scan((currentState, reducer) => {
			return reducer(currentState);
		}, state);

		observable.handle = (action, reducer) => bloomrun.add(action, reducer);
		observable.dispatch = action => instance.emit('dispatch', action);

		return observable;
}

Handle the default pattern with the last state when the command is not mathcing.


'use strict';
const net = require('net');

const isAvailable = options => new Promise((resolve, reject) => {
	const server = net.createServer();
	server.unref();
	server.on('error', reject);
	server.listen(options, () => {
		const {port} = server.address();
		server.close(() => {
			resolve(port);
		});
	});
});

const getPort = (options = {}) => {
	if (typeof options.port === 'number') {
		options.port = [options.port];
	}

	return (options.port || []).reduce(
		(seq, port) => seq.catch(
			() => isAvailable(Object.assign({}, options, {port}))
		),
		Promise.reject()
	);
};

module.exports = options => options ?
	getPort(options).catch(() => getPort({port: 0})) :
	getPort({port: 0});

'use strict';
const net = require('net');

const isAvailable = options => new Promise((resolve, reject) => {
	const server = net.createServer();
	server.unref();
	server.on('error', reject);
	server.listen(options, () => {
		const {port} = server.address();
		server.close(() => {
			resolve(port);
		});
	});
});

const getPort = (options = {}) => {
	if (typeof options.port === 'number') {
		options.port = [options.port];
	}

	return (options.port || []).reduce(
		(seq, port) => seq.catch(
			() => isAvailable(Object.assign({}, options, {port}))
		),
		Promise.reject()
	);
};

module.exports = options => options ?
	getPort(options).catch(() => getPort(Object.assign(options, {port: 0}))) :
	getPort({port: 0});

Use the correct `host` when falling back


/* jshint node: true */
'use strict';

module.exports = {
  name: 'telling-stories',

  included: function(app) {
    if (!this.shouldIncludeFiles()) {
      return;
    }

    this._super.included.apply(this, arguments);

    app.import('vendor/telling-stories/qunit-configuration.js', { type: 'test' });
    app.import('vendor/telling-stories/player-mode.css', { type: 'test' });
  },

  treeFor: function() {
    if (!this.shouldIncludeFiles()) {
      return;
    }

    return this._super.treeFor.apply(this, arguments);
  },

  isDevelopingAddon: function() {
    return true;
  },

  shouldIncludeFiles: function() {
    return this.app.env !== 'production';
  }
};

/* jshint node: true */
'use strict';

module.exports = {
  name: 'telling-stories',

  included: function(app) {
    if (!this.shouldIncludeFiles()) {
      return;
    }

    this._super.included.apply(this, arguments);

    app.import('vendor/telling-stories/qunit-configuration.js', { type: 'test' });
    app.import('vendor/telling-stories/player-mode.css', { type: 'test' });
  },

  treeFor: function() {
    if (!this.shouldIncludeFiles()) {
      return;
    }

    return this._super.treeFor.apply(this, arguments);
  },

  isDevelopingAddon: function() {
    return true;
  },

  shouldIncludeFiles: function() {
    return !!this.app.tests;
  }
};

Validate if app.tests are available


#!/usr/bin/env node

global.__base = __dirname + '/src/';

// Commands
var cli = require('commander');

cli
  .version('0.0.1')
  .option('-p, --port <port>'            , 'Change static server port [8000]', 8000)
  .option('-P, --livereload-port <port>' , 'Change livereload port [35729]', 35729)
  .option('-d, --directory <path>'       , 'Change the default directory for serving files [.]', __dirname)
  .parse(process.argv);

// Start Asset server
var AssetServer = require(__base + 'assets_server');
var assetServer = new AssetServer({
  port: cli.port,
  directory: cli.directory,
  livereloadPort: cli.livereloadPort
});

assetServer.start();

// Start Livereload server
var LivereloadServer = require(__base + 'livereload_server');
var livereloadServer = new LivereloadServer({
  port: cli.livereloadPort
});

livereloadServer.start();

// Start Monitor
var Monitor = require(__base + 'monitor');
var monitor = new Monitor({
  directory: cli.directory,
  livereloadPort: cli.livereloadPort
})

monitor.start();

#!/usr/bin/env node

global.__base = __dirname + '/src/';

// Commands
var cli = require('commander');

cli
  .version('0.0.1')
  .option('-p, --port <port>'            , 'Change static server port [8000]', 8000)
  .option('-P, --livereload-port <port>' , 'Change livereload port [35729]', 35729)
  .option('-d, --directory <path>'       , 'Change the default directory for serving files [.]', process.cwd())
  .parse(process.argv);

// Start Asset server
var AssetServer = require(__base + 'assets_server');
var assetServer = new AssetServer({
  port: cli.port,
  directory: cli.directory,
  livereloadPort: cli.livereloadPort
});

assetServer.start();

// Start Livereload server
var LivereloadServer = require(__base + 'livereload_server');
var livereloadServer = new LivereloadServer({
  port: cli.livereloadPort
});

livereloadServer.start();

// Start Monitor
var Monitor = require(__base + 'monitor');
var monitor = new Monitor({
  directory: cli.directory,
  livereloadPort: cli.livereloadPort
})

monitor.start();

Fix error if trying to do slr in current dir


export class Serializable {

    constructor(props) {
        this.properties = props || {};
    }

    toObject() {
        return this.properties;
    }

    toString() {
        return JSON.stringify(this.toObject());
    }

    toJSON() {
        return JSON.stringify(this.properties);
    }

    toQueryString() {
        var str = [];
        var obj = this.toObject();
        for (var p in obj) {
            if (obj.hasOwnProperty(p) && obj[p]) {
                str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
            }
        }
        return str.join('&');
    }
}

class Hit extends Serializable {

    sent = false

    constructor(props){
        super(props);
    }
}

export class PageHit extends Hit {
    constructor(screenName) {
        super({ dp: screenName, t: 'pageview' });
    }
}

export class ScreenHit extends Hit {
    constructor(screenName) {
        super({ dp: screenName, t: 'screenview' });
    }
}

export class Event extends Hit {
    constructor(category, action, label, value) {
        super({ ec: category, ea: action, el: label, ev: value, t: 'event' });
    }
}

export class Serializable {

    constructor(props) {
        this.properties = props || {};
    }

    toObject() {
        return this.properties;
    }

    toString() {
        return JSON.stringify(this.toObject());
    }

    toJSON() {
        return JSON.stringify(this.properties);
    }

    toQueryString() {
        var str = [];
        var obj = this.toObject();
        for (var p in obj) {
            if (obj.hasOwnProperty(p) && obj[p]) {
                str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
            }
        }
        return str.join('&');
    }
}

class Hit extends Serializable {

    sent = false

    constructor(props){
        super(props);
    }
}

export class PageHit extends Hit {
    constructor(screenName) {
        super({ dp: screenName, t: 'pageview' });
    }
}

export class ScreenHit extends Hit {
    constructor(screenName) {
        super({ cd: screenName, t: 'screenview' });
    }
}

export class Event extends Hit {
    constructor(category, action, label, value) {
        super({ ec: category, ea: action, el: label, ev: value, t: 'event' });
    }
}

Fix screenName parameter in ScreenHit class


'use strict';

var p4 = require('node-perforce');
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

var PLUGIN_NAME = 'gulp-p4';

module.exports = function (p4cmd, options) {
  if (!p4cmd) throw new PluginError(PLUGIN_NAME, 'Missing p4 command');
  if (!p4[p4cmd]) throw new PluginError(PLUGIN_NAME, 'Invalid command');

  return through.obj(function (file, enc, callback) {
    options = options || {};
    options.files = [file.history];
    p4[p4cmd](options, function(err) {
      if (err) throw new PluginError(PLUGIN_NAME, err);
      callback();
    });
  });
};

'use strict';

var p4 = require('node-perforce');
var through = require('through2');
var gutil = require('gulp-util');
var PluginError = gutil.PluginError;

var PLUGIN_NAME = 'gulp-p4';

module.exports = function (p4cmd, options) {
  if (!p4cmd) throw new PluginError(PLUGIN_NAME, 'Missing p4 command');
  if (!p4[p4cmd]) throw new PluginError(PLUGIN_NAME, 'Invalid command');

  return through.obj(function (file, enc, callback) {
    options = options || {};
    options.files = [file.history];
    p4[p4cmd](options, function(err) {
      if (err) throw new PluginError(PLUGIN_NAME, err);
      callback(null, file);
    });
  });
};

Fix to work with trail pipes


#!/usr/bin/env node

"use strict";

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const exec = require("child_process").exec;

process.argv.splice(0, 2);
if (process.argv.length > 0) {

  // Attempt to parse the date
  let date = process.argv.join(" ");
  let parsedDate = new sugar.Date.create(date);

  if (parsedDate != "Invalid Date") {

    // Date could be parsed, parse the date to git date format
    let dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");

    // Actually modify the dates
    let command = "GIT_COMMITTER_DATE=\"" + dateString + "\" git commit --amend --date=\"" + dateString + "\" --no-edit";
    exec(command, (err, stdout, stderr) => {
      if (err) {
        console.log("fatal: Could not change the previous commit");
      } else {
        console.log("\nModified previous commit:\n    AUTHOR_DATE " + chalk.grey(dateString) + "\n    COMMITTER_DATE " + chalk.grey(dateString) + "\n\nCommand executed:\n    " + chalk.bgWhite.black(command) + "\n");
      }
    });

  } else {
    console.log("fatal: Could not parse \"" + date + "\" into a valid date");
  }

} else {
  console.log("fatal: No date string given");
}

#!/usr/bin/env node

"use strict";

const moment = require("moment");
const sugar = require("sugar");
const chalk = require("chalk");
const exec = require("child_process").exec;

// Throw a fatal error
const fatal = err => {
  console.error(`fatal: ${err}`);
}

process.argv.splice(0, 2);
if (process.argv.length > 0) {

  // Attempt to parse the date
  let date = process.argv.join(" ");
  let parsedDate = new sugar.Date.create(date);

  if (parsedDate != "Invalid Date") {

    // Date could be parsed, parse the date to git date format
    let dateString = moment(parsedDate).format("ddd MMM DD HH:mm:ss YYYY ZZ");

    // Actually modify the dates
    let command = "GIT_COMMITTER_DATE=\"" + dateString + "\" git commit --amend --date=\"" + dateString + "\" --no-edit";
    exec(command, (err, stdout, stderr) => {
      if (err) {
        fatal("Could not change the previous commit");
      } else {
        console.log("\nModified previous commit:\n    AUTHOR_DATE " + chalk.grey(dateString) + "\n    COMMITTER_DATE " + chalk.grey(dateString) + "\n\nCommand executed:\n    " + chalk.bgWhite.black(command) + "\n");
      }
    });

  } else {
    fatal("Could not parse \"" + date + "\" into a valid date");
  }

} else {
  fatal("No date string given");
}

Move fatal throw to separate function


/**
 * Module dependencies.
 */
var reduceCSSCalc = require("reduce-css-calc")

/**
 * Expose `plugin`.
 */

module.exports = plugin

/**
 * Plugin to convert all function calls.
 *
 * @param {Object} stylesheet
 */

function plugin() {
  return function(style) {
    style.eachDecl(function declaration(dec) {
      if (!dec.value) {
        return
      }

      try {
        dec.value = convert(dec.value)
      }
      catch (err) {
        err.position = dec.position
        throw err
      }
    })
  }
}

/**
 * Reduce CSS calc()
 *
 * @param {String} string
 * @return {String}
 */

function convert(string) {
  if (string.indexOf("calc(") === -1) {
    return string
  }

  return reduceCSSCalc(string)
}

/**
 * Module dependencies.
 */
var reduceCSSCalc = require("reduce-css-calc")

/**
 * Expose plugin & helper
 */
module.exports = plugin
module.exports.transformDecl = transformDecl

/**
 * PostCSS plugin to reduce calc() function calls.
 */
function plugin() {
  return function(style) {
    style.eachDecl(transformDecl)
  }
}

/**
 * Reduce CSS calc on a declaration object
 *
 * @param {object} dec [description]
 */
function transformDecl(dec) {
  if (!dec.value) {
    return
  }

  try {
    dec.value = transform(dec.value)
  }
  catch (err) {
    err.position = dec.position
    throw err
  }
}

/**
 * Reduce CSS calc() on a declaration value
 *
 * @param {String} string
 * @return {String}
 */
function transform(string) {
  if (string.indexOf("calc(") === -1) {
    return string
  }

  return reduceCSSCalc(string)
}

Update comment & expose transformDecl


var os = require('os')
var path = require('path')
var homedir = require('os-homedir')

function linux (id) {
  var cacheHome = process.env.XDG_CACHE_HOME || path.join(homedir(), '.cache')
  return path.join(cacheHome, id)
}

function darwin (id) {
  return path.join(homedir(), 'Library', 'Caches', id)
}

function win32 (id) {
  var appData = process.env.LOCALAPPDATA || path.join(homedir(), 'AppData', 'Local')
  return path.join(appData, id, 'Cache')
}

var implementation = (function () {
  switch (os.platform()) {
    case 'android':
    case 'linux': return linux
    case 'darwin': return darwin
    case 'win32': return win32
    default: throw new Error('Your OS is currently not supported by node-cachedir.')
  }
}())

module.exports = function (id) {
  if (typeof id !== 'string') {
    throw new TypeError('id is not a string')
  }
  if (id.length === 0) {
    throw new Error('id cannot be empty')
  }
  if (/[^0-9a-zA-Z-]/.test(id)) {
    throw new Error('id cannot contain special characters')
  }

  return implementation(id)
}

var os = require('os')
var path = require('path')
var homedir = require('os-homedir')

function posix (id) {
  var cacheHome = process.env.XDG_CACHE_HOME || path.join(homedir(), '.cache')
  return path.join(cacheHome, id)
}

function darwin (id) {
  return path.join(homedir(), 'Library', 'Caches', id)
}

function win32 (id) {
  var appData = process.env.LOCALAPPDATA || path.join(homedir(), 'AppData', 'Local')
  return path.join(appData, id, 'Cache')
}

var implementation = (function () {
  switch (os.platform()) {
    case 'android': return posix
    case 'darwin': return darwin
    case 'linux': return posix
    case 'win32': return win32
    default: throw new Error('Your OS "' + os.platform() + '" is currently not supported by node-cachedir.')
  }
}())

module.exports = function (id) {
  if (typeof id !== 'string') {
    throw new TypeError('id is not a string')
  }
  if (id.length === 0) {
    throw new Error('id cannot be empty')
  }
  if (/[^0-9a-zA-Z-]/.test(id)) {
    throw new Error('id cannot contain special characters')
  }

  return implementation(id)
}

Clean up existing OS handling a little


var stati = [
    'irritable',
    'gassy',
    'diuretic',
    'constipated',
    'twisted',
    'cramped'
    // Have another idea? Submit a pull request or issue
    // https://github.com/itsananderson/gut-status/issues
];

function getStatus() {
    var index = Math.floor(Math.random() * stati.length);
    return stati[index];
}

module.exports = {
    stati: stati,
    getStatus: getStatus
};

var stati = [
    'irritable',
    'gassy',
    'diuretic',
    'constipated',
    'twisted',
    'cramped',
    'surly',
    'churlish',
    'hungry',
    'famished'
    // Have another idea? Submit a pull request or issue
    // https://github.com/itsananderson/gut-status/issues
];

function getStatus() {
    var index = Math.floor(Math.random() * stati.length);
    return stati[index];
}

module.exports = {
    stati: stati,
    getStatus: getStatus
};

Add surly, churlish, hungry, and famished


'use strict';

var tape = require('tape');
var through = require('through2');
var PluginError = require('gulp-util').PluginError;
var requireUncached = require('require-uncached');

var PLUGIN_NAME = 'gulp-tape';

var gulpTape = function(opts) {
  opts = opts || {};

  var outputStream = opts.outputStream || process.stdout;
  var reporter     = opts.reporter     || through.obj();
  var files        = [];

  var transform = function(file, encoding, cb) {
    if (file.isNull()) {
      return cb(null, file);
    }
    if (file.isStream()) {
      return cb(new PluginError(PLUGIN_NAME, 'Streaming is not supported'));
    }
    files.push(file.path);
    cb(null, file);
  };

  var flush = function(cb) {
    try {
      tape.createStream().pipe(reporter).pipe(outputStream);
      files.forEach(function(file) {
        requireUncached(file);
      });
      var tests = tape.getHarness()._tests;
      var pending = tests.length;
      tests.forEach(function(test) {
        test.once('end', function() {
          if (--pending === 0) {
            cb();
          }
        });
      });
    } catch (err) {
      cb(new PluginError(PLUGIN_NAME, err));
    }
  };

  return through.obj(transform, flush);
};

module.exports = gulpTape;

'use strict';

var tape = require('tape');
var through = require('through2');
var PluginError = require('gulp-util').PluginError;
var requireUncached = require('require-uncached');

var PLUGIN_NAME = 'gulp-tape';

var gulpTape = function(opts) {
  opts = opts || {};

  var outputStream = opts.outputStream || process.stdout;
  var reporter     = opts.reporter     || through.obj();
  var files        = [];

  var transform = function(file, encoding, cb) {
    if (file.isNull()) {
      return cb(null, file);
    }
    if (file.isStream()) {
      return cb(new PluginError(PLUGIN_NAME, 'Streaming is not supported'));
    }
    files.push(file.path);
    cb(null, file);
  };

  var flush = function(cb) {
    try {
      tape.createStream().pipe(reporter).pipe(outputStream);
      files.forEach(function(file) {
        requireUncached(file);
      });
      var tests = tape.getHarness()._tests;
      var pending = tests.length;
      if (pending === 0) {
        return cb();
      }
      tests.forEach(function(test) {
        test.once('end', function() {
          if (--pending === 0) {
            cb();
          }
        });
      });
    } catch (err) {
      cb(new PluginError(PLUGIN_NAME, err));
    }
  };

  return through.obj(transform, flush);
};

module.exports = gulpTape;

Call `cb` immediately if `pending` is zero


'use strict';
const appPath = require('app-path');
const bundleId = require('bundle-id');
const osxAppVersion = require('osx-app-version');
const appSize = require('app-size');

module.exports = app => {
	if (process.platform !== 'darwin') {
		return Promise.reject(new Error('Only OS X is supported'));
	}

	if (typeof app !== 'string') {
		return Promise.reject(new Error('Application is required'));
	}

	return Promise.all([osxAppVersion(app), bundleId(app), appPath(app), appSize(app)]).then(res => {
		return {
			version: res[0],
			bundle: res[1],
			path: res[2],
			size: res[3]
		};
	});
};

'use strict';
const appPath = require('app-path');
const bundleId = require('bundle-id');
const osxAppVersion = require('osx-app-version');
const appSize = require('app-size');

module.exports = app => {
	if (process.platform !== 'darwin') {
		return Promise.reject(new Error('Only OS X is supported'));
	}

	if (typeof app !== 'string') {
		return Promise.reject(new Error('Application is required'));
	}

	return Promise.all([osxAppVersion(app), bundleId(app), appPath(app), appSize(app)]).then(res => {
		return {
			path: res[2],
			version: res[0],
			bundle: res[1],
			size: res[3]
		};
	});
};

Reorder object to make more sense


'use strict';
/**
 * Helper to avoid:
 * var DatasetEditController = require('../../../app/hello/dataset/edit/DatasetEditController');
 * Just use rrequire('DatasetEditController') instead!
 */
var path = require('path');
var rrequire = function (filename) {
  var absPath = __dirname;
  var projectRoot = process.cwd();
  var projectRelativePath = absPath.replace(projectRoot, '').replace('test', 'app');
  var absSrcPath = path.join(projectRoot, projectRelativePath, filename);
  return require(absSrcPath);
};

module.exports = rrequire;

'use strict';
/**
 * Helper to avoid:
 * var DatasetEditController = require('../../../app/hello/dataset/edit/DatasetEditController');
 * Just use rrequire('DatasetEditController') instead!
 */
var path = require('path');
var callsite = require('callsite');
var rrequire = function (filename) {
  var absPath = path.dirname(callsite()[1].getFileName());
  var projectRoot = process.cwd();
  var projectRelativePath = absPath.replace(projectRoot, '').replace('test', 'app');
  var absSrcPath = path.join(projectRoot, projectRelativePath, filename);
  return require(absSrcPath);
};

module.exports = rrequire;

Use callsite to get path of caller


/*!
 * days <https://github.com/jonschlinkert/days>
 *
 * Copyright (c) 2014 Jon Schlinkert, contributors.
 * Licensed under the MIT license.
 */

module.exports = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
module.exports.abbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
module.exports.short = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

/*!
 * days <https://github.com/jonschlinkert/days>
 *
 * Copyright (c) 2014 Jon Schlinkert, contributors.
 * Licensed under the MIT license.
 */

// English
module.exports.en = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
module.exports.en.abbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
module.exports.en.short = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

// French translation
module.exports.fr = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'];
module.exports.fr.abbr = ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'];
module.exports.fr.short = ['di', 'lu', 'ma', 'me', 'je', 've', 'sa'];

// In order not to break compatibility
module.exports = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
module.exports.abbr = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
module.exports.short = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];

Update to include multi-language support


var postcss = require('postcss'),
    color = require('color');

module.exports = postcss.plugin('postcss-lowvision', function () {
    return function (css) {
        css.walkDecls('color', function (decl) {
            var val = decl.value;
            var rgb = color(val);
            rgb.rgb();
            decl.value = rgb;
            decl.cloneAfter({ prop: 'text-shadow',
                              value: '0 0 5px rgba(0,0,0,0.5)' });
        });
    };
});

var postcss = require('postcss'),
    color = require('color');

module.exports = postcss.plugin('postcss-lowvision', function () {
    return function (css) {
        css.walkDecls('color', function (decl) {
            var val = decl.value;
            var rgb = color(val);
            rgb = rgb.rgbArray();
            decl.value = transparent;
            decl.cloneAfter({ prop: 'text-shadow',
                              value: '0 0 5px rgba(' + rgb[0] + ', ' + rgb[1] + ', '+ rgb[2] + ', ' + '0.5)' });
        });
    };
});

Add text-shadow with used color rgb value


module.exports = function (options) {
  options = options || {}
  options.property = options.property || 'body'
  options.stringify = options.stringify || JSON.stringify

  return function (req, res, next) {
    req.removeAllListeners('data')
    req.removeAllListeners('end')
    if(req.headers['content-length'] !== undefined){
      req.headers['content-length'] = options.stringify(req[options.property]).length
    }
    next()
    process.nextTick(function () {
      if(req[options.property]) {
        if('function' === typeof options.modify)
          req[options.property] = options.modify(req[options.property])
        req.emit('data', options.stringify(req[options.property]))
      }
      req.emit('end')
    })
  }
}

module.exports = function (options) {
  options = options || {}
  options.property = options.property || 'body'
  options.stringify = options.stringify || JSON.stringify

  return function (req, res, next) {
    req.removeAllListeners('data')
    req.removeAllListeners('end')
    if(req.headers['content-length'] !== undefined){
      req.headers['content-length'] = Buffer.byteLength(options.stringify(req[options.property]), 'utf8')
    }
    next()
    process.nextTick(function () {
      if(req[options.property]) {
        if('function' === typeof options.modify)
          req[options.property] = options.modify(req[options.property])
        req.emit('data', options.stringify(req[options.property]))
      }
      req.emit('end')
    })
  }
}

Set content-length in bytes instead of characters


import React from 'react';
import ReactDOM from 'react-dom';
import { shallow } from 'enzyme';
import TimeTable from './../TimeTable.js';
import ErrorMsg from './../ErrorMsg';
import LoadingMsg from './../LoadingMsg';

describe('TimeTable', () => {
	it('renders without crashing', () => {
		const div = document.createElement('div');
		ReactDOM.render(<TimeTable />, div);
	});
	it('shows error when created with invalid props.', () => {
		const component = shallow(<TimeTable lat={16.5} />);
		expect(component.find(ErrorMsg)).toHaveLength(1);
	});
	it('shows loading when created.', () => {
		const component = shallow(<TimeTable lat={16.5} lon={28.5}/>);
		expect(component.find(LoadingMsg)).toHaveLength(1);
	});
});

import React from 'react';
import ReactDOM from 'react-dom';
import { shallow } from 'enzyme';
import TimeTable from './../TimeTable.js';
import ErrorMsg from './../ErrorMsg';
import LoadingMsg from './../LoadingMsg';
import DepartureInfo from './../DepartureInfo.js';

jest.mock('../APIQuery');

describe('TimeTable', () => {
	it('renders without crashing', () => {
		const div = document.createElement('div');
		ReactDOM.render(<TimeTable />, div);
	});
	it('shows error when created with invalid props.', () => {
		const component = shallow(<TimeTable lat={16.5} />);
		expect(component.find(ErrorMsg)).toHaveLength(1);
	});
	it('shows loading when created.', () => {
		const component = shallow(<TimeTable lat={16.5} lon={28.5}/>);
		expect(component.find(LoadingMsg)).toHaveLength(1);
	});
	it('shows nearest departure infos after succesfull API query.', async () => {
		const component = shallow(<TimeTable lat={16.5} lon={28.5}/>);
		await component.instance().sendQuery();
		component.update();
		expect(component.find(LoadingMsg)).toHaveLength(0);
		expect(component.find(DepartureInfo)).not.toHaveLength(0);
	});
	it('shows stop departure infos after succesfull API query.', async () => {
		const component = shallow(<TimeTable stopCode='E2036'/>);
		await component.instance().sendQuery();
		component.update();
		expect(component.find(LoadingMsg)).toHaveLength(0);
		expect(component.find(DepartureInfo)).not.toHaveLength(0);
	});
});

Test that departure infos are rendered.


'use strict';
module.exports = function (scope) {
	var rc = require('rc')('npm');
	return rc[scope + ':registry'] ||
		rc.registry || 'https://registry.npmjs.org/';
};

'use strict';
module.exports = function (scope) {
	var rc = require('rc')('npm', {registry: 'https://registry.npmjs.org/'});
	return rc[scope + ':registry'] || rc.registry;
};

Make it work in browsers


import React from 'react'
import Range from '../Range'
import RefinementList from '../RefinementList'
import SidebarSection from '../SidebarSection'
import './style.scss'

function Facets () {
  return (
    <div data-app='facets-wrapper'>
      <RefinementList title='category' attributeName='category' />
      <RefinementList title='provider' attributeName='provider' />
      <RefinementList title='type' attributeName='type' />
      <RefinementList title='brand' attributeName='brand' />
      <RefinementList title='model' attributeName='model' />
      <RefinementList title='diameter' attributeName='diameter' />
      <RefinementList title='box' attributeName='box' />

      <SidebarSection title='carbon' item={<Range attributeName='carbon' />} />
      <SidebarSection title='price' item={<Range attributeName='price' />} />
      <SidebarSection title='sail size' item={<Range attributeName='sail.size' />} />
      <SidebarSection title='board size' item={<Range attributeName='board.size' />} />
      <SidebarSection title='mast size' item={<Range attributeName='mast.size' />} />
      <SidebarSection title='fin size' item={<Range attributeName='fin.size' />} />
    </div>
  )
}

export default Facets

import React from 'react'
import Range from '../Range'
import RefinementList from '../RefinementList'
import SidebarSection from '../SidebarSection'
import './style.scss'

function Facets () {
  return (
    <div data-app='facets-wrapper'>
      <RefinementList title='category' attributeName='category' />
      <RefinementList title='provider' attributeName='provider' />
      <RefinementList title='type' attributeName='type' />
      <RefinementList title='brand' attributeName='brand' />
      <RefinementList title='model' attributeName='model' />
      <RefinementList title='diameter' attributeName='diameter' />
      <RefinementList title='box' attributeName='box' />

      <SidebarSection title='carbon' item={<Range attributeName='carbon' />} />
      <SidebarSection title='price' item={<Range attributeName='price' />} />
      <SidebarSection title='sail size' item={<Range attributeName='sail.size' />} />
      <SidebarSection title='board size' item={<Range attributeName='board.size' />} />
      <RefinementList title='mast size' attributeName='mast.size' />
      <RefinementList title='fin size' attributeName='fin.size' />
    </div>
  )
}

export default Facets

Improve mast and fin size facets


'use strict';
var gutil = require('gulp-util');
var through = require('through2');
var assign = require('object-assign');
var nunjucks = require('nunjucks');

module.exports = function (opts) {
	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			cb(null, file);
			return;
		}

		if (file.isStream()) {
			cb(new gutil.PluginError('gulp-nunjucks', 'Streaming not supported'));
			return;
		}

		opts = assign({}, opts);

		var filePath = file.path;

		try {
			opts.name = typeof opts.name === 'function' && opts.name(file) || file.relative;
			file.contents = new Buffer(nunjucks.precompileString(file.contents.toString(), opts));
			file.path = gutil.replaceExtension(file.path, '.js');
			this.push(file);
		} catch (err) {
			this.emit('error', new gutil.PluginError('gulp-nunjucks', err, {fileName: filePath}));
		}

		cb();
	});
};

'use strict';
var gutil = require('gulp-util');
var through = require('through2');
var assign = require('object-assign');
var nunjucks = require('nunjucks');

module.exports = function (opts) {
	return through.obj(function (file, enc, cb) {
		if (file.isNull()) {
			cb(null, file);
			return;
		}

		if (file.isStream()) {
			cb(new gutil.PluginError('gulp-nunjucks', 'Streaming not supported'));
			return;
		}

		var options = assign({}, opts);

		var filePath = file.path;

		try {
			options.name = typeof options.name === 'function' && options.name(file) || file.relative;
			file.contents = new Buffer(nunjucks.precompileString(file.contents.toString(), options));
			file.path = gutil.replaceExtension(file.path, '.js');
			this.push(file);
		} catch (err) {
			this.emit('error', new gutil.PluginError('gulp-nunjucks', err, {fileName: filePath}));
		}

		cb();
	});
};

Fix wrong options variable assignment


const path = require('path');
const execa = require('execa');
const errorHandler = require('./errorHandler');

module.exports = function runGulp() {
  execa('gulp',
    [
      '--cwd', process.cwd(),
      '--gulpfile', path.join(__dirname, '../gulpfile.js'),
    ],
    { stdio: 'inherit' },
  )
    .catch(err => errorHandler); // eslint-disable-line no-unused-vars
};

const path = require('path');
const execa = require('execa');
const errorHandler = require('./errorHandler');

module.exports = function runGulp() {
  execa('node',
    [
      path.join(__dirname, '../../node_modules/.bin/gulp'),
      '--cwd', process.cwd(),
      '--gulpfile', path.join(__dirname, '../gulpfile.js'),
    ],
    { stdio: 'inherit' },
  )
    .catch(err => errorHandler); // eslint-disable-line no-unused-vars
};

Use bundled gulp instead of global


'use strict';

var bind = require('function-bind');
var define = require('define-properties');
var replace = bind.call(Function.call, String.prototype.replace);

var rightWhitespace = /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]*$/;

var trimRight = function trimRight() {
	return replace(this, rightWhitespace, '');
};

var boundTrimRight = bind.call(Function.call, trimRight);
define(boundTrimRight, {
	shim: function shimTrimRight() {
		if (!String.prototype.trimRight) {
			define(String.prototype, { trimRight: trimRight });
		}
		return String.prototype.trimRight;
	}
});

module.exports = boundTrimRight;

'use strict';

var bind = require('function-bind');
var define = require('define-properties');
var replace = bind.call(Function.call, String.prototype.replace);

var rightWhitespace = /[\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF]*$/;

var trimRight = function trimRight() {
	return replace(this, rightWhitespace, '');
};

var boundTrimRight = bind.call(Function.call, trimRight);
define(boundTrimRight, {
	shim: function shimTrimRight() {
		var zeroWidthSpace = '\u200b';
		define(String.prototype, { trimRight: trimRight }, {
			trimRight: function () {
				return zeroWidthSpace.trimRight() !== zeroWidthSpace;
			}
		});
		return String.prototype.trimRight;
	}
});

module.exports = boundTrimRight;

Fix a bug in node 0.10 (and presumably other browsers) where the zero-width space is erroneously trimmed.


'use babel';
import editorconfig from 'editorconfig';
import generateConfig from './commands/generate';

function init(editor) {
	generateConfig();

	if (!editor) {
		return;
	}

	const file = editor.getURI();

	if (!file) {
		return;
	}

	editorconfig.parse(file).then(config => {
		if (Object.keys(config).length === 0) {
			return;
		}

		const indentStyle = config.indent_style || editor.getSoftTabs() ? 'space' : 'tab';

		if (indentStyle === 'tab') {
			editor.setSoftTabs(false);

			if (config.tab_width) {
				editor.setTabLength(config.tab_width);
			}
		} else if (indentStyle === 'space') {
			editor.setSoftTabs(true);

			if (config.indent_size) {
				editor.setTabLength(config.indent_size);
			}
		}

		if (config.charset) {
			// EditorConfig charset names matches iconv charset names.
			// Which is used by Atom. So no charset name convertion is needed.
			editor.setEncoding(config.charset);
		}
	});
}

export const activate = () => {
	atom.workspace.observeTextEditors(init);
};

'use babel';
import editorconfig from 'editorconfig';
import generateConfig from './commands/generate';

function init(editor) {
	generateConfig();

	if (!editor) {
		return;
	}

	const file = editor.getURI();

	if (!file) {
		return;
	}

	editorconfig.parse(file).then(config => {
		if (Object.keys(config).length === 0) {
			return;
		}

		const indentStyle = config.indent_style || (editor.getSoftTabs() ? 'space' : 'tab');

		if (indentStyle === 'tab') {
			editor.setSoftTabs(false);

			if (config.tab_width) {
				editor.setTabLength(config.tab_width);
			}
		} else if (indentStyle === 'space') {
			editor.setSoftTabs(true);

			if (config.indent_size) {
				editor.setTabLength(config.indent_size);
			}
		}

		if (config.charset) {
			// EditorConfig charset names matches iconv charset names.
			// Which is used by Atom. So no charset name convertion is needed.
			editor.setEncoding(config.charset);
		}
	});
}

export const activate = () => {
	atom.workspace.observeTextEditors(init);
};

Fix error with operator precedence


/**
 * @typedef {import('unist').Node} Node
 * @typedef {import('unist').Parent} Parent
 */

import {modifyChildren} from 'unist-util-modify-children'

export const affixEmoticonModifier = modifyChildren(mergeAffixEmoticon)

/**
 * Merge emoticons into an `EmoticonNode`.
 *
 * @param {Node} child
 * @param {number} index
 * @param {Parent} parent
 */
function mergeAffixEmoticon(child, index, parent) {
  var siblings = parent.children
  /** @type {Array.<Node>} */
  // @ts-ignore looks like a parent.
  var children = child.children
  var childIndex = -1

  if (children && children.length > 0 && index) {
    while (++childIndex < children.length) {
      if (children[childIndex].type === 'EmoticonNode') {
        siblings[index - 1].children = [].concat(
          siblings[index - 1].children,
          children.slice(0, childIndex + 1)
        )
        child.children = children.slice(childIndex + 1)

        if (
          children[childIndex].position &&
          child.position &&
          siblings[index - 1].position
        ) {
          siblings[index - 1].position.end = children[childIndex].position.end
          child.position.start = children[childIndex].position.end
        }

        // Next, iterate over the node again.
        return index
      }

      if (children[childIndex].type !== 'WhiteSpaceNode') {
        break
      }
    }
  }
}

/**
 * @typedef {import('unist').Node} Node
 * @typedef {import('unist').Parent} Parent
 */

import {modifyChildren} from 'unist-util-modify-children'

export const affixEmoticonModifier = modifyChildren(mergeAffixEmoticon)

/**
 * Merge emoticons into an `EmoticonNode`.
 *
 * @param {Node} node
 * @param {number} index
 * @param {Parent} ancestor
 */
function mergeAffixEmoticon(node, index, ancestor) {
  const previous = ancestor.children[index - 1]
  var childIndex = -1

  if (index && parent(previous) && parent(node)) {
    var children = node.children

    while (++childIndex < children.length) {
      const child = children[childIndex]

      if (child.type === 'EmoticonNode') {
        previous.children = [].concat(
          previous.children,
          children.slice(0, childIndex + 1)
        )
        node.children = children.slice(childIndex + 1)

        if (child.position && node.position && previous.position) {
          previous.position.end = child.position.end
          node.position.start = child.position.end
        }

        // Next, iterate over the node again.
        return index
      }

      if (child.type !== 'WhiteSpaceNode') {
        break
      }
    }
  }
}

/**
 * @param {Node} node
 * @returns {node is Parent}
 */
function parent(node) {
  return 'children' in node
}

Fix tests for changes in `@types/unist`


import React, { PropTypes } from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import styles from './Incident.css';
import Map from './Map';
import GridTile from 'material-ui/lib/grid-list/grid-tile';

const Incident = ({ incident }) => (
  <ReactCSSTransitionGroup
    transitionName={styles}
    transitionEnterTimeout={500}
    transitionLeaveTimeout={300}
    transitionAppear
    transitionAppearTimeout={500}
  >
    <div className={styles.incident}>
      <GridTile
        key={incident.id}
        title={incident.description}
        subtitle={incident.address}
      >
        <Map address={incident.address} />
      </GridTile>
    </div>
  </ReactCSSTransitionGroup>
);

Incident.propTypes = {
  incident: PropTypes.object.isRequired
};

export default Incident;

import React, { PropTypes } from 'react';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import styles from './Incident.css';
import Map from './Map';
import GridTile from 'material-ui/lib/grid-list/grid-tile';
import Paper from 'material-ui/lib/paper';

const Incident = ({ incident }) => (
  <ReactCSSTransitionGroup
    transitionName={styles}
    transitionEnterTimeout={500}
    transitionLeaveTimeout={300}
    transitionAppear
    transitionAppearTimeout={500}
  >
    <div className={styles.incident}>
      <Paper zDepth={2}>
        <GridTile
          key={incident.id}
          title={incident.description}
          subtitle={incident.address}
        >
          <Map address={incident.address} />
        </GridTile>
      </Paper>
    </div>
  </ReactCSSTransitionGroup>
);

Incident.propTypes = {
  incident: PropTypes.object.isRequired
};

export default Incident;

Add paper for neat effect on incidents


$(document).ready(function() {
    $('#ballot_response').submit(function(event) {
        confirm("Are you sure you want to submit your ballot?");

        var sortableList = $("#candidates");
        var listElements = sortableList.children();
        var listValues = [];
        for (var i = 0; i < listElements.length; i++) {
            listValues.push(listElements[i].id);
        }

        var formData = {
            'ballot'               : listValues,
            '_csrf'                : $('input[name=_csrf]').val()
        };

        var formsub = $.ajax({
            type        : 'POST',
            url         : '/endpoints/process_ballot.php',
            data        : formData,
            dataType    : 'json',
            encode      : true
        });

        formsub.done(function(data) {
            if (data.success) {
              setTimeout(function() { window.location.href = "/vote"; }, 100);
            }
        });

        event.preventDefault();
    });
});

$(document).ready(function() {
    $('#ballot_response').submit(function(event) {
        if(confirm("Are you sure you want to submit your ballot?")) {
            var sortableList = $("#candidates");
            var listElements = sortableList.children();
            var listValues = [];
            for (var i = 0; i < listElements.length; i++) {
                listValues.push(listElements[i].id);
            }

            var formData = {
                'ballot'               : listValues,
                '_csrf'                : $('input[name=_csrf]').val()
            };

            var formsub = $.ajax({
                type        : 'POST',
                url         : '/endpoints/process_ballot.php',
                data        : formData,
                dataType    : 'json',
                encode      : true
            });

            formsub.done(function(data) {
                if (data.success) {
                  setTimeout(function() { window.location.href = "/vote"; }, 100);
                }
            });
        }
        event.preventDefault();
    });
});

Update confirm to be if


module.exports = {
  init
}

var electron = require('electron')
var get = require('simple-get')

var config = require('../config')
var log = require('./log')

var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL +
  '?version=' + config.APP_VERSION +
  '&platform=' + process.platform

function init () {
  get.concat(ANNOUNCEMENT_URL, function (err, res, data) {
    if (err) return log('failed to retrieve remote message')
    if (res.statusCode !== 200) return log('no remote message')

    electron.dialog.showMessageBox({
      type: 'info',
      buttons: ['OK'],
      title: 'WebTorrent Desktop Announcement',
      message: data.toString()
    })
  })
}

module.exports = {
  init
}

var electron = require('electron')
var get = require('simple-get')

var config = require('../config')
var log = require('./log')

var ANNOUNCEMENT_URL = config.ANNOUNCEMENT_URL +
  '?version=' + config.APP_VERSION +
  '&platform=' + process.platform

function init () {
  get.concat(ANNOUNCEMENT_URL, function (err, res, data) {
    if (err) return log('failed to retrieve remote message')
    if (res.statusCode !== 200) return log('no remote message')

    try {
      data = JSON.parse(data.toString())
    } catch (err) {
      data = {
        title: 'WebTorrent Desktop Announcement',
        message: 'WebTorrent Desktop Announcement',
        detail: data.toString()
      }
    }

    electron.dialog.showMessageBox({
      type: 'info',
      buttons: ['OK'],
      title: data.title,
      message: data.message,
      detail: data.detail
    })
  })
}

Support custom window title, main message, details


//make sure all dependencies are loaded
require([
	'es5shim',
	'angular',
	'json!data/config.json',
    'angular-ui-router',
    'angular-flash',
    'angular-moment',
    'angular-sanitize',
    'emoji',
    'socketio',
    'socket',
	'jquery',
	'jquery-filedrop',
	'app',
	'services/services',
	'controllers/controllers',
	'filters/filters',
	'directives/directives',
	'config/flash',
	'config/http',
	'config/routes',
	'config/finalize',
	'config/socket'
], function (es5shim, angular, config) {

	'use strict';

	console.log('Dependencies loaded');

	//kick off!
	angular.element(document).ready(function () {
		console.log('Document ready, bootstrapping app');
		angular.bootstrap(document, [config.appName]);
	});
});

//make sure all dependencies are loaded
require([
	'es5shim',
	'angular',
	'json!data/config.json',
    'angular-ui-router',
    'angular-flash',
    'angular-moment',
    'angular-sanitize',
    'emoji',
    'socketio',
    'socket',
	'jquery',
	'jquery-filedrop',
	'app',
	'services/services',
	'controllers/controllers',
	'filters/filters',
	'directives/directives',
	'config/flash',
	'config/http',
	'config/routes',
	'config/finalize',
	'config/socket'
], function (es5shim, angular, config) {

	'use strict';

	console.log('Dependencies loaded');

	//kick off!
	angular.element(document).ready(function () {
		console.log('Document ready, bootstrapping app');

		// Get user state before bootstrap so we can route correctly
		var $http = angular.bootstrap().get('$http');
		$http.get("/api/users/session").success(function(user) {
			sessionStorage.setItem("user", user.id);
			angular.bootstrap(document, [config.appName]);
		}).error(function(data, status, headers, config) {
			console.log('Error accessing api');
		});
	});
});

Check for active session before bootstrapping


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

function PropertyValue(xml) {
  this.Annotations = {};

  this.validElements = {
  };
  this.validAttributes = {
    'Bool': {bool: true},
    'String': {},
    'Path': {},
    'Property': {alreadyHandeled: true}
  };

  var init = ParserCommon.initEntity.bind(this);
  init(xml, 'PropertyValue', 'Property');

  return this;
}

module.exports = PropertyValue;
/* vim: set tabstop=2 shiftwidth=2 expandtab: */

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

function PropertyValue(xml) {
  this.Annotations = {};

  this.validElements = {
  };
  this.validAttributes = {
    'Bool': {bool: true},
    'String': {},
    'Path': {},
    'Property': {alreadyHandeled: true},
    'EnumMember': {}
  };

  var init = ParserCommon.initEntity.bind(this);
  init(xml, 'PropertyValue', 'Property');

  return this;
}

module.exports = PropertyValue;
/* vim: set tabstop=2 shiftwidth=2 expandtab: */

Add EnumMember as a valid expression


var crypto = require('crypto'),
  util = require('util'),
  Transform = require('stream').Transform;

function DecryptStream(options) {
  if (!(this instanceof DecryptStream))
    return new DecryptStream(options);

  Transform.call(this, options);

  this.key = options.key;

  this._decipher = crypto.createDecipheriv('aes-128-ecb', this.key, '');
  this._decipher.setAutoPadding(true);
};

util.inherits(DecryptStream, Transform);

DecryptStream.prototype._transform = function(chunk, encoding, done) {
  this.push(this._decipher.update(chunk));
  done();
};

module.exports = DecryptStream;

var crypto = require('crypto'),
  util = require('util'),
  Transform = require('stream').Transform;

function DecryptStream(options) {
  if (!(this instanceof DecryptStream))
    return new DecryptStream(options);

  Transform.call(this, options);

  this.key = options.key;

  this._decipher = crypto.createDecipheriv('aes-128-ecb', this.key, '');
  this._decipher.setAutoPadding(true);
};

util.inherits(DecryptStream, Transform);

DecryptStream.prototype._transform = function(chunk, encoding, callback) {
  this.push(this._decipher.update(chunk));
  callback();
};

DecryptStream.prototype._flush = function(callback) {
  this.push(this._decipher.final());
  callback();
}

module.exports = DecryptStream;

Call final() on stream flush.


/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

// <![CDATA[
$(document).ready(function() {
$.ajaxSetup({ cache: false }); // This part addresses an IE bug. without it, IE will only load the first number and will never refresh
setInterval(function() {
$('#pjax_total').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_total');
$('#pjax_green').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_green');
$('#pjax_status').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_status');
$('#pjax_person').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_person');
$('#pjax_last6').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_last6');
$('#pjax_today').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_today');
$('#pjax_today2').load('https://reserv.solusi-integral.co.id/index.php/pajax/pjax_today');
}, 1234); // the "3000" here refers to the time to refresh the div. it is in milliseconds.
});
// ]]>

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

// <![CDATA[
$(document).ready(function() {
$.ajaxSetup({ cache: false }); // This part addresses an IE bug. without it, IE will only load the first number and will never refresh
setInterval(function() {
$('#pjax_total').load('https://reserv.solusi-integral.co.id/pajax/pjax_total');
$('#pjax_green').load('https://reserv.solusi-integral.co.id/pajax/pjax_green');
$('#pjax_status').load('https://reserv.solusi-integral.co.id/pajax/pjax_status');
$('#pjax_person').load('https://reserv.solusi-integral.co.id/pajax/pjax_person');
$('#pjax_last6').load('https://reserv.solusi-integral.co.id/pajax/pjax_last6');
$('#pjax_today').load('https://reserv.solusi-integral.co.id/pajax/pjax_today');
$('#pjax_today2').load('https://reserv.solusi-integral.co.id/pajax/pjax_today');
}, 1234); // the "3000" here refers to the time to refresh the div. it is in milliseconds.
});
// ]]>

Change cache-control from 60s expired to 86.400 (1 day)