export default class Api {
  static fetchJKF() {
    return fetch('/jkf')
      .then(response => response.json());
  }
  static storeJKF(jkf) {
    const body = JSON.stringify(jkf, null, '  ');

    return new Promise((resolve, reject) => {
      fetch('/jkf', { method: 'PUT', body: body })
        .then((response) => {
          if (response.ok) {
            resolve();
          } else {
            console.error(response);
            console.log(body);  // to preserve data
            reject(response);
          }
        })
        .catch((e) => {
          console.error(e);
          console.log(body);  // to preserve data
          reject(e);
        });
    });
  }
}

export default class Api {
  static fetchJKF() {
    return fetch('/jkf')
      .then(response => response.json());
  }
  static storeJKF(jkf) {
    const body = JSON.stringify(jkf, null, '  ');

    function preserveFailedData(e) {
      console.error(e);
      window.sessionStorage.setItem('lastFailedJKF', body);
      console.log('Failed to save. You can get the last JKF by: console.log(sessionStorage.getItem("lastFailedJKF"))');
    }

    return new Promise((resolve, reject) => {
      fetch('/jkf', { method: 'PUT', body: body })
        .then((response) => {
          if (response.ok) {
            resolve();
          } else {
            preserveFailedData(response);
            reject(response);
          }
        })
        .catch((e) => {
          preserveFailedData(e);
          reject(e);
        });
    });
  }
}

Store failed JKF to the sessionStorage instead of console.log


const STARWARS = {
  'star wars': '/img/search-chewie.gif',
  'darth vader': '/img/search-darth-vader.gif',
  r2d2: '/img/search-r2d2.gif',
  chewie: '/img/search-chewie.gif',
  'luke skywalker': '/img/search-luke.gif',
  yoda: '/img/search-yoda.gif',
};

export default STARWARS;

const STARWARS = {
  'star wars': '/docs/img/search-chewie.gif',
  'darth vader': '/img/search-darth-vader.gif',
  r2d2: '/docs/img/search-r2d2.gif',
  chewie: '/docs/img/search-chewie.gif',
  'luke skywalker': '/docs/img/search-luke.gif',
  yoda: '/docs/img/search-yoda.gif',
};

export default STARWARS;

Update to correct path for stage & prod


import _ from "lodash";
import Feed from "../feed";
import Narou from "../../sites/narou";
import { translate } from "../../util/chrome-util";

/**
 * Feed fetcher of received reviews in Narou
 *
 * @implements FeedFetcher
 */
export default class FetcherNarouReviews {
  isLoginRequired() {
    return true;
  }

  fetchFeed() {
    return this._fetchItems().then(items => {
      return new Feed({
        title: translate("narouReviewsFeed"),
        url: Narou.URL.getMyReceivedReviewsURL(),
        siteName: translate(Narou.name),
        siteId: Narou.name,
        items,
      });
    });
  }

  _fetchItems() {
    return Narou.API.listMyReceivedReviews().then(reviews => {
      return _.map(reviews, review => ({
        id: review.id,
        title: review.title,
        url: this.pageUrl,
        body: review.body,
        type: "review",
        authorName: review.userName,
        authorUrl: review.userUrl,
        sourceTitle: review.novelTitle,
        sourceUrl: review.novelUrl,
        sourceType: "novel",
        createdAt: review.createdAt,
      }));
    });
  }
}

import _ from "lodash";
import Feed from "../feed";
import Narou from "../../sites/narou";
import { translate } from "../../util/chrome-util";

/**
 * Feed fetcher of received reviews in Narou
 *
 * @implements FeedFetcher
 */
export default class FetcherNarouReviews {
  isLoginRequired() {
    return true;
  }

  fetchFeed() {
    return this._fetchItems().then(items => {
      return new Feed({
        title: translate("narouReviewsFeed"),
        url: Narou.URL.getMyReceivedReviewsURL(),
        siteName: translate(Narou.name),
        siteId: Narou.name,
        items,
      });
    });
  }

  _fetchItems() {
    return Narou.API.listMyReceivedReviews().then(reviews => {
      return _.map(reviews, review => ({
        id: review.id,
        title: review.title,
        url: Narou.URL.getMyReceivedReviewsURL(),
        body: review.body,
        type: "review",
        authorName: review.userName,
        authorUrl: review.userUrl,
        sourceTitle: review.novelTitle,
        sourceUrl: review.novelUrl,
        sourceType: "novel",
        createdAt: review.createdAt,
      }));
    });
  }
}

Fix items in review feed were not linked


#!/usr/bin/env node

import yargs from 'yargs';
import path from 'path';
import fs from 'fs';
import * as pose from '.';
import actions from './actions';

const opts = yargs
.usage('$ pose <action> [options]')
.help('help')
.epilog(actions.trim())
.options({
  name: {
    alias: ['n', 'as'],
    default: path.basename(process.cwd()),
    desc: 'Name of template',
  },

  entry: {
    alias: ['e'],
    default: process.cwd(),
    defaultDescription: 'cwd',
    desc: 'Entry of template',
  },

  help: {
    alias: ['h'],
  },
}).argv;
const action = opts._[0];

if (!action) {
  console.log('Type "pose help" to get started.');
  process.exit();
}

[
  opts._pose = path.join(process.env.HOME, '.pose'),
  opts._templates = path.join(opts._pose, 'templates'),
].forEach(dir => {
  fs.mkdir(dir, () => null);
});

if (typeof pose[action] === 'function') {
  pose[action](opts);
} else {
  console.error(`Unknown action "${action}"`);
}
export { action, opts };

#!/usr/bin/env node

import yargs from 'yargs';
import path from 'path';
import fs from 'fs';
import * as pose from '.';
import actions from './actions';

const opts = yargs
.usage('$ pose <action> [options]')
.help('help')
.epilog(actions.trim())
.options({
  name: {
    alias: ['as'],
    default: path.basename(process.cwd()),
    desc: 'Name of template',
  },

  entry: {
    alias: ['e'],
    default: process.cwd(),
    defaultDescription: 'cwd',
    desc: 'Entry of template',
  },

  help: {
    alias: ['h'],
  },
}).argv;
const action = opts._[0];

if (!action) {
  console.log('Type "pose help" to get started.');
  process.exit();
}

[
  opts._pose = path.join(process.env.HOME, '.pose'),
  opts._templates = path.join(opts._pose, 'templates'),
].forEach(dir => {
  fs.mkdir(dir, () => null);
});

if (typeof pose[action] === 'function') {
  pose[action](opts);
} else {
  console.error(`Unknown action "${action}"`);
}
export { action, opts };

Remove -n in favor of --as


(function (Flow, FustyFlow, window) {
  'use strict';

  var FustyFlowFactory = function (opts) {
    var flow = new Flow(opts);
    if (flow.support) {
      return flow;
    }
    return new FustyFlow(opts);
  }

  window.FustyFlowFactory = FustyFlowFactory;

})(window.Flow, window.FustyFlow, window);

(function (Flow, FustyFlow, window) {
  'use strict';

  var fustyFlowFactory = function (opts) {
    var flow = new Flow(opts);
    if (flow.support) {
      return flow;
    }
    return new FustyFlow(opts);
  }

  window.fustyFlowFactory = fustyFlowFactory;

})(window.Flow, window.FustyFlow, window);

Revert factory name to fustyFlowFactory case for backward compatibility reasons


'use strict';
var fs = require('fs');
var path = require('path');
var marked = require('marked');
var setCase = require('case')
var Renderer = require('./JsxRenderer');

marked.setOptions({
  xhtml: true,
  highlight: function(code, lang) {
    let prism = require('./prism-jsx');
    lang = lang && lang.indexOf('language-') === 0 ? lang.replace('language-', '') : lang;
    return prism.highlight(code, prism.languages[lang]);
  }
});

function defaultRender(contents, resourcePath, options) {
  let prefix = setCase.pascal(path.basename(resourcePath, '.md').toLowerCase() + '/');

  return `
var React = require('react');
${options.preamble || ''}

module.exports = React.createClass({
  displayName: '${prefix}',
  render: function() {
    return (
      <div {...this.props}>
        ${contents}
      </div>
    )
 }
});

${options.postamble || ''}
`;
}

module.exports = function(contents) {
  var options = this.options.markdownJsxLoader || {}

  this.cacheable();

  Renderer = options.renderer || this.options.renderer || Renderer;

  var render = options.render || defaultRender

  return render(marked(contents, {
    renderer: new Renderer()
  }), this.resourcePath, options)
}

module.exports.Renderer = Renderer

'use strict';

const setCase = require('case');
const fs = require('fs');
const loaderUtils = require('loader-utils');
const marked = require('marked');
const path = require('path');
const Renderer = require('./JsxRenderer');

marked.setOptions({
  highlight: function(code, lang) {
    const prism = require('./prism-jsx');
    lang = lang && lang.indexOf('language-') === 0 ? lang.replace('language-', '') : lang;
    return prism.highlight(code, prism.languages[lang]);
  }
});

function defaultRender(contents, resourcePath, options) {
  const prefix = setCase.pascal(path.basename(resourcePath, '.md').toLowerCase() + '/');

  return `
var React = require('react');
${options.preamble || ''}

module.exports = function () {
  return (<div>${contents}</div>)
});

module.exports.displayName = '${prefix}';

${options.postamble || ''}
`;
}

module.exports = function(contents) {
  const options = loaderUtils.getOptions(this) || {};

  this.cacheable();

  const renderer = options.renderer || new Renderer();
  const render = options.render || defaultRender;

  return render(marked(contents, { renderer }), this.resourcePath, options)
}

module.exports.Renderer = Renderer

Use functional JSX component. Update to `loaderUtils` to support options.


import {createFilter} from 'rollup-pluginutils'
import Compiler from './compiler'
import objectAssign from 'object-assign'
import path from 'path'

export default function plugin (options = {}) {
  options = objectAssign({}, options, {extensions: ['.vue'] })
  let filter = createFilter(options.include, options.exclude)
  const extensions = options.extensions
  delete options.extensions
  delete options.include
  delete options.exclude

  const compiler = new Compiler(options)

  return {
    transform (code, id) {
      if (!filter(id)) return null
      if (extensions.indexOf(path.extname(id)) === -1) return null

      return new Promise((resolve) => {
        compiler
            .compile(code, id)
            .then((compiled) => resolve(compiled))
      })
    }
  }
}

import {createFilter} from 'rollup-pluginutils'
import Compiler from './compiler'
import objectAssign from 'object-assign'
import path from 'path'

export default function plugin (options = {}) {
  options = objectAssign({}, options, {extensions: ['.vue'] })
  let filter = createFilter(options.include, options.exclude)
  const extensions = options.extensions
  delete options.extensions
  delete options.include
  delete options.exclude

  const compiler = new Compiler(options)

  return {
    transform (code, id) {
      if (!filter(id)) { return null }
      if (extensions.indexOf(path.extname(id)) === -1) { return null }

      return new Promise((resolve) => {
        compiler
            .compile(code, id)
            .then((compiled) => resolve(compiled))
      })
    }
  }
}

Add { after 'if' condition


// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const processTree = require("../lib/process-tree");

let treeSpy = function(logTree, runningProcess) {
  let spy = { };

  spy.tree = logTree;
  spy.process = runningProcess;

  spy.messages = [ ];
  spy.log = function(message) {
    spy.messages.push(message)
  };

  return spy;
};

let spy;
let spyOnTree = async function(done, setup) {
  spy = await processTree(treeSpy, setup)
  done();
};

describe("a processTree with no children", () => {
  beforeEach(done => {
    spyOnTree(done, function(o) { });
  });

  it("returns a spy", () => {
    expect(spy.tree).toBeDefined();
  });
});

// Copyright (c) 2017 The Regents of the University of Michigan.
// All Rights Reserved. Licensed according to the terms of the Revised
// BSD License. See LICENSE.txt for details.

const processTree = require("../lib/process-tree");

let treeSpy = function(logTree, runningProcess) {
  let spy = { };

  spy.tree = logTree;
  spy.process = runningProcess;

  spy.messages = [ ];
  spy.log = function(message) {
    spy.messages.push(message)
  };

  return spy;
};

let spy;
let spyOnTree = async (done, setup) => {
  spy = await processTree(treeSpy, setup)
  done();
};

describe("a processTree with no children", () => {
  beforeEach(done => {
    spyOnTree(done, function(o) { });
  });

  it("returns a spy", () => {
    expect(spy.tree).toBeDefined();
  });
});

Make spyOnTree() an arrow function


var https = require("https");

var options = {
  host: 'www.haloapi.com' ,
  path: '',
  method: 'GET',
  headers: {"Ocp-Apim-Subscription-Key": ""}
};

function httpWrapper(API_KEY){
  options.headers["Ocp-Apim-Subscription-Key"] = API_KEY;
}

httpWrapper.prototype.queryAPI = function(path) {
  return new Promise((resolve, reject) => {
    let _options = options;
    _options.path = path;
    let responseText = '';
    let request = https.request(_options, (response) => {
      response.on('data', (data) => {
        responseText += data;
      });
      response.on('end', () => {
        resolve(JSON.parse(responseText));
      })
    });
    request.on('error', (e) => {reject(e)});
    request.end();
  });
}

module.exports = httpWrapper;

var https = require("https");

var options = {
  host: 'www.haloapi.com' ,
  path: '',
  method: 'GET',
  headers: {"Ocp-Apim-Subscription-Key": ""}
};

function httpWrapper(API_KEY){
  options.headers["Ocp-Apim-Subscription-Key"] = API_KEY;
}

httpWrapper.prototype.queryAPI = function(path) {
  return new Promise((resolve, reject) => {
    let _options = options;
    _options.path = encodeURI(path);
    let responseText = '';
    let request = https.request(_options, (response) => {
      response.on('data', (data) => {
        responseText += data;
      });
      response.on('end', () => {
        resolve(JSON.parse(responseText));
      })
    });
    request.on('error', (e) => {reject(e)});
    request.end();
  });
}

module.exports = httpWrapper;

Fix error with gamertags that contain spaces


import {
  cssStatementHasBlock,
  cssStatementHasEmptyBlock,
  report,
  ruleMessages
} from "../../utils"

export const ruleName = "block-no-empty"

export const messages = ruleMessages(ruleName, {
  rejected: `Unexpected empty block`,
})

export default function () {
  return (root, result) => {

    // Check both kinds of statements: rules and at-rules
    root.eachRule(check)
    root.eachAtRule(check)

    function check(statement) {
      if (cssStatementHasBlock(statement) && cssStatementHasEmptyBlock(statement)) {
        report({
          message: messages.rejected,
          node: statement,
          result,
          ruleName,
        })
      }
    }
  }
}

import {
  cssStatementHasBlock,
  cssStatementHasEmptyBlock,
  report,
  ruleMessages
} from "../../utils"

export const ruleName = "block-no-empty"

export const messages = ruleMessages(ruleName, {
  rejected: `Unexpected empty block`,
})

export default function () {
  return (root, result) => {

    // Check both kinds of statements: rules and at-rules
    root.eachRule(check)
    root.eachAtRule(check)

    function check(statement) {
      if (cssStatementHasEmptyBlock(statement)) {
        report({
          message: messages.rejected,
          node: statement,
          result,
          ruleName,
        })
      }
    }
  }
}

Remove unnecessary check from block-no-empty


/*renders control panel with associated buttons and display*/
import React from 'react';
import CountDisplay from 'CountDisplay';
import StrictButton from 'StrictButton';
import OnOffButton from 'OnOffButton';

class Control extends React.Component{
  render(){
    return (

Simon(tm)

            <CountDisplay countDisplayText={ this.props.countDisplayText } isOn={ this.props.isOn }/>

              <button id="start-btn" onClick={ this.props.onStartClick }></button>
              START

            <StrictButton onStrictClick={ this.props.onStrictClick } strictOn={ this.props.strictOn } />

            <OnOffButton onOnClick={ this.props.onOnClick } isOn={ this.props.isOn }/>

    );
  }
}

export default Control;

/*renders control panel with associated buttons and display*/
import React from 'react';
import CountDisplay from 'CountDisplay';
import StrictButton from 'StrictButton';
import OnOffButton from 'OnOffButton';

class Control extends React.Component{
  render(){
    return (

Simon™

            <CountDisplay countDisplayText={ this.props.countDisplayText } isOn={ this.props.isOn }/>

              <button id="start-btn" onClick={ this.props.onStartClick }></button>
              START

            <StrictButton onStrictClick={ this.props.onStrictClick } strictOn={ this.props.strictOn } />

            <OnOffButton onOnClick={ this.props.onOnClick } isOn={ this.props.isOn }/>

    );
  }
}

export default Control;

Add trademark symbol to control component


(function(){
  'use strict';

  define([
      'app',
      'utils/chartHelpers',
      'utils/duration',
      'utils/escapeHtml'], function(app, chartHelpers, duration, escapeHtml) {
    app.controller('projectTestDetailsCtrl', [
        '$scope', '$rootScope', 'initialProject', 'initialTest',
        function($scope, $rootScope, initialProject, initialTest) {
      var chart_options = {
            tooltipFormatter: function(item) {
              var content = '';

              content += '
';
              content += escapeHtml(item.build.name);
              content += '
';
              content += escapeHtml(item.build.target);
              if (item.author) {
                content += ' — ' + item.author.name;
              }
              content += '';
              content += '
';
              content += '
Test ' + item.result.name;
              if (item.duration) {
                content += ' in ' + duration(item.duration);
              }
              content += ' (Build ' + item.build.result.name + ')
';

              return content;
            }
          };

      $scope.project = initialProject.data;
      $scope.test = initialTest.data.test;
      $scope.childTests = initialTest.data.childTests;
      $scope.context = initialTest.data.context;
      $scope.previousRuns = initialTest.data.previousRuns;
      $rootScope.activeProject = $scope.project;
      $scope.chartData = chartHelpers.getChartData($scope.previousRuns, null, chart_options);

    }]);
  });
})();

(function(){
  'use strict';

  define([
      'app',
      'utils/chartHelpers',
      'utils/duration',
      'utils/escapeHtml'], function(app, chartHelpers, duration, escapeHtml) {
    app.controller('projectTestDetailsCtrl', [
        '$scope', '$rootScope', 'initialProject', 'initialTest',
        function($scope, $rootScope, initialProject, initialTest) {
      var chart_options = {
            tooltipFormatter: function(item) {
              var content = '';
              var build = item.job.build;

              content += '
';
              content += escapeHtml(build.name);
              content += '
';
              content += escapeHtml(build.target);
              if (build.author) {
                content += ' — ' + build.author.name;
              }
              content += '';
              content += '
';
              content += '
Test ' + item.result.name;
              if (item.duration) {
                content += ' in ' + duration(item.duration);
              }
              content += ' (Build ' + build.result.name + ')
';

              return content;
            }
          };

      $scope.project = initialProject.data;
      $scope.test = initialTest.data.test;
      $scope.childTests = initialTest.data.childTests;
      $scope.context = initialTest.data.context;
      $scope.previousRuns = initialTest.data.previousRuns;
      $rootScope.activeProject = $scope.project;
      $scope.chartData = chartHelpers.getChartData($scope.previousRuns, null, chart_options);

    }]);
  });
})();

Update references to build in chart tooltips


function(doc) {
  if ('type' in doc && doc.type !== 'Notebook' && doc.type !== 'object') {
    emit([doc.type, doc.name], 1);
  }
}

function(doc) {
  emit([doc.type, doc.name], 1);
}

Allow anything to be edited via Types list


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

import style from './../../../styles/organisms/ThermostatForm.scss'

class ThermostatForm extends Component {

  getLastRemoteCheckin() {
    return moment().diff(this.props.lastCheckin, 'minutes')
  }

  render() {

    const minutesSinceLastCheckin = this.getLastRemoteCheckin.call(this)

    return (
      <form className={style.form} method="post" action={`/thermostat/${this.props.id}`}>

        <fieldset className={style.temperature}>
          <legend>Target Temperature</legend>
          <input type="hidden" name="_method" value="put" />
          <input name="temperature" type="number" required value={this.props.temperature} max="99" min="68" />
          °
        </fieldset>

        <input className={style.name} type="text" name="name" value={this.props.name} required />

        <button className="pure-button pure-button-primary">Update</button>

        {
          minutesSinceLastCheckin > 5 &&

            {"The remote hasn\'t checked in recently."}

        }

      </form>
    )

  }

}

ThermostatForm.propTypes = {
  id: PropTypes.number,
  temperature: PropTypes.string,
  name: PropTypes.string,
  lastCheckin: PropTypes.string
}

export default ThermostatForm

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

import style from './../../../styles/organisms/ThermostatForm.scss'

class ThermostatForm extends Component {

  getLastRemoteCheckin() {
    return moment().diff(this.props.lastCheckin, 'minutes')
  }

  render() {

    const minutesSinceLastCheckin = this.getLastRemoteCheckin.call(this)

    return (
      <form className={style.form} method="post" action={`/thermostat/${this.props.id}`}>

        <fieldset className={style.temperature}>
          <legend>Target Temperature</legend>
          <input type="hidden" name="_method" value="put" />
          <input name="temperature" type="number" required value={this.props.temperature} max="99" min="68" />
          °
        </fieldset>

        <input className={style.name} type="text" name="name" value={this.props.name} required />

        <button className="pure-button pure-button-primary">Update</button>

        {
          minutesSinceLastCheckin > 15 &&

            {"The remote hasn\'t checked in recently."}

        }

      </form>
    )

  }

}

ThermostatForm.propTypes = {
  id: PropTypes.number,
  temperature: PropTypes.string,
  name: PropTypes.string,
  lastCheckin: PropTypes.string
}

export default ThermostatForm

Increase timeout warning to 15 minutes.


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

function Translator(domain) {
  this.domain = domain;
  this.initialize();
}

Translator.prototype = {
  TYPE_ADD: 'add',
  MAPPED_FIELDS: {
    'id': '_key'
  },

  initialize: function() {
    this.tableName = resolver.getTableNameFromDomain(this.domain);
  },
  translate: function(batches) {
    var commands = batches.map(function(batch) {
          return this.translateOne(batch);
        }, this);
    return commands.join('\n');
  },
  translateOne: function(batch) {
    switch (batch.type) {
      case this.TYPE_ADD:
        return this.addToLoad(batch);
      default:
        throw new Error('batch type "' + batch.type + '" is not acceptable');
    }
  },
  addToLoad: function(batch) {
    var line = {
          _key: batch.id
        };
    for (var field in batch.fields) {
      if (!batch.fields.hasOwnProperty(field))
        continue;
      line[field] = resolver.getColumnNameFromField(batch.fields[field]);
    }
    var command = 'load --table ' + this.tableName + ' ' + JSON.stringify([line]);
    return command;
  }
};

exports.Translator = Translator;

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

function Translator(domain) {
  this.domain = domain;
  this.initialize();
}

Translator.prototype = {
  TYPE_ADD: 'add',
  MAPPED_FIELDS: {
    'id': '_key'
  },

  initialize: function() {
    this.tableName = resolver.getTableNameFromDomain(this.domain);
  },
  translate: function(batches) {
    var commands = batches.map(function(batch) {
          return this.translateOne(batch);
        }, this);
    return commands.join('\n');
  },
  translateOne: function(batch) {
    switch (batch.type) {
      case this.TYPE_ADD:
        return this.addToLoad(batch);
      default:
        throw new Error('batch type "' + batch.type + '" is not acceptable');
    }
  },
  addToLoad: function(batch) {
    var line = {
          _key: batch.id
        };
    for (var field in batch.fields) {
      if (!batch.fields.hasOwnProperty(field))
        continue;
      line[resolver.getColumnNameFromField(field)] = batch.fields[field];
    }
    var command = 'load --table ' + this.tableName + ' ' + JSON.stringify([line]);
    return command;
  }
};

exports.Translator = Translator;

Fix wrong validation (values are wrongly validated as the column name)


/* Really simple events dispatcher using Websockets.
 * We expect socket.io lib to be on the server side.
 *
 * Usage:
 *  events_dispatcher.bind('EventName', callback(jsondata));
 */
events_dispatcher = (function() {

  if (!('WebSocket' in window)) {
    $('body').prepend('
' +
                      'Your browser does not support WebSockets! ' +
                      'You won\'t have any live events!
');
    return {bind: function(){}};
  }
  var mapper = {};

  var ws_url = 'ws://' + window.location.host + '/socket.io/websocket';
  var socket = new WebSocket(ws_url);

  socket.onmessage = function (msg) {
    var messages = JSON.parse(msg.data).messages;
    messages.forEach(function(message) {
      var callback = message.event && mapper[message.event];
      callback && callback(message.data);
    });
  };

  return {
    bind: function(name, fct) {
      mapper[name] = fct;
    }
  }

})();

/* Really simple events dispatcher using Websockets.
 * We expect socket.io lib to be on the server side.
 *
 * Usage:
 *  events_dispatcher.bind('EventName', callback(jsondata));
 */
events_dispatcher = (function() {

  if (!('WebSocket' in window)) {
    $('body').prepend('
' +
                      'Your browser does not support WebSockets! ' +
                      'You won\'t have any live events!
');
    return {bind: function(){}};
  }
  var mapper = {};

  var ws_url = 'ws://' + window.location.host + '/socket.io/websocket';
  var socket;

  (function init_socket() {
    socket = new WebSocket(ws_url);

    socket.onmessage = function (msg) {
      var messages = JSON.parse(msg.data).messages;
      messages.forEach(function(message) {
        var callback = message.event && mapper[message.event];
        callback && callback(message.data);
      });
    };

    socket.onclose = function() {
      // The connection has been closed, try to reconnect in 0.5 seconds:
      setTimeout(init_socket, 500);
    };
  })();

  return {
    bind: function(name, fct) {
      mapper[name] = fct;
    }
  }

})();

Reconnect websocket when connection is lost.


import Ember from 'ember';
import layout from '../templates/components/resize-detector';

const {
  inject: { service },
  run: { scheduleOnce, bind }
} = Ember;

export default Ember.Component.extend({
  layout,
  tagName: '',
  resizeDetector: service(),

  didInsertElement() {
    this._super(...arguments);

    scheduleOnce('afterRender', this, this.setup);
  },

  setup() {
    this.callback = bind(this, this.onResize);
    this.get('resizeDetector').setup(this.get('selector'), this.callback);
  },

  teardown() {
    this.get('resizeDetector').teardown(this.get('selector'), this.callback);
  },

  onResize(element) {
    let $el = Ember.$(element);
    this.sendAction('on-resize', {
      width: $el.width(),
      height: $el.height()
    }, element);
  },

  willDestroyElement() {
    this.teardown();

    this._super(...arguments);
  }
}).reopenClass({
  positionalParams: ['selector']
});

import Ember from 'ember';
import layout from '../templates/components/resize-detector';

const {
  inject: { service },
  run: { scheduleOnce, bind }
} = Ember;

export default Ember.Component.extend({
  layout,
  tagName: '',
  resizeDetector: service(),

  didInsertElement() {
    this._super(...arguments);

    scheduleOnce('afterRender', this, this.setup);
  },

  setup() {
    this.callback = bind(this, this.onResize);
    this.get('resizeDetector').setup(this.get('selector'), this.callback);
  },

  teardown() {
    this.get('resizeDetector').teardown(this.get('selector'), this.callback);
  },

  onResize(element) {
    if (this.get('isDestroyed') || this.get('isDestroying')) {
      return;
    }
    let $el = Ember.$(element);
    this.sendAction('on-resize', {
      width: $el.width(),
      height: $el.height()
    }, element);
  },

  willDestroyElement() {
    this.teardown();

    this._super(...arguments);
  }
}).reopenClass({
  positionalParams: ['selector']
});

Fix calling sendAction on destroyed object error


import compose from './compose'
import curry from './curry'
import either from './either'
import map from './map'
import merge from './merge'
import partial from './partial'
import prop from './prop'
import reduce from './reduce'
import sequence from './sequence'
import update from './update'

export {
  compose,
  curry,
  either,
  map,
  merge,
  partial,
  prop,
  reduce,
  sequence,
  update,
}

import compose from './compose'
import curry from './curry'
import Either from './either'
import map from './map'
import merge from './merge'
import partial from './partial'
import prop from './prop'
import reduce from './reduce'
import sequence from './sequence'
import update from './update'

export {
  compose,
  curry,
  Either,
  map,
  merge,
  partial,
  prop,
  reduce,
  sequence,
  update,
}

Rename from either to Either


import React, { PropTypes } from 'react'

export default function Counter({
  increment,
  incrementIfOdd,
  decrement,
  counter,
}) {
  return (

        To get started, edit src/routes/index.js
        and save to reload.

        Clicked: {counter} times
        {' '}
        <button onClick={increment}>+</button>
        {' '}
        <button onClick={decrement}>-</button>
        {' '}
        <button onClick={incrementIfOdd}>Increment if odd</button>

  )
}

Counter.propTypes = {
  increment: PropTypes.func.isRequired,
  incrementIfOdd: PropTypes.func.isRequired,
  decrement: PropTypes.func.isRequired,
  counter: PropTypes.number.isRequired,
}

Add space character after code element


window.onload = function() {

    var tabs = function() {
        var args = models.application.arguments;
        var current = document.getElementById(args[0]);
        var sections = document.getElementsByClassName("section");
        for(i = 0; i < sections.length; i++) {
            sections[i].style.display = "none";
        }
        current.style.display = "block";
    }

    sp = getSpotifyApi(1);
    var models = sp.require("sp://import/scripts/api/models");
    models.application.observe(models.EVENT.ARGUMENTSCHANGED, tabs);
}

window.onload = function() {

    var tabs = function() {
        var args = models.application.arguments;
        var current = $("#"+args[0]);
        var sections = $(".section");
        sections.hide();
        current.show();
    }

    sp = getSpotifyApi(1);
    var models = sp.require("sp://import/scripts/api/models");
    models.application.observe(models.EVENT.ARGUMENTSCHANGED, tabs);
}

Rewrite tab switching with jQuery


export function ClassDeclaration(node) {
    this.ensure("class");
    this.ensureSpace();

    if (node.id) {
        this.print(node.id);
        this.ensureSpace();
    }

    if (node.superClass) {
        this.ensure("extends");
        this.ensureSpace();
        this.print(node.superClass);
        this.ensureSpace();
    }

    if (node.implements) this._printList(node.implements);

    this.print(node.body);
}

export { ClassDeclaration as ClassExpression };

export function ClassBody() {
    this.BlockStatement.apply(this, arguments);
}

export function ClassProperty(node) {
    if (node.decorators) {
        this._printList(node.decorators, { newlines: true, separator: "" });
    }

    if (node.static) {
        this.ensure("static");
        this.ensureSpace();
    }

    this.print(node.key);

    if (node.value) {
        this.ensureSpace();
        this.ensure("=");
        this.ensureSpace();
        this.print(node.value);
    }
    this.ensureVoid();
    this.ensure(";");
}

export function MethodDefinition(node) {
    if (node.static) {
        this.ensure("static");
        this.ensureSpace();
    }

    this._method(node);
}

export function ClassDeclaration(node) {
    this.ensure("class");
    this.ensureSpace();

    if (node.id) {
        this.print(node.id);
        this.ensureSpace();
    }

    if (node.superClass) {
        this.ensure("extends");
        this.ensureSpace();
        this.print(node.superClass);
        this.ensureSpace();
    }

    if (node.implements) this._printList(node.implements);

    this.print(node.body);
}

export { ClassDeclaration as ClassExpression };

export function ClassBody() {
    this.BlockStatement.apply(this, arguments);
}

export function ClassProperty(node) {
    if (node.decorators) {
        this._printList(node.decorators, { newlines: true, separator: "" });
    }

    if (node.static) {
        this.ensure("static");
        this.ensureSpace();
    }

    this.print(node.key);

    if (node.value) {
        this.ensureSpace();
        this.ensure("=");
        this.ensureSpace();
        this.print(node.value);
    }
    this.ensureVoid();
    this.ensure(";");
}

export function Super(node) {
    this.ensure("super");
}

export function MethodDefinition(node) {
    if (node.static) {
        this.ensure("static");
        this.ensureSpace();
    }

    this._method(node);
}

Add Super to the printable types.


$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    // alert("Hi, I am data id: " + commentId)
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId }
    }).done( function (response) {
      // var selector = "span[data-id=" + responseId + "]";
      // $(selector).html(response);
      alert("Success! Here is your response: " + response);
    }).fail( function (response) {
        console.log(response);
      // console.log("Failed");
    })
  })
})

$(document).ready( function () {
  $("button.upvote").click( function() {
    var commentId = $(".upvote").data("id");
    event.preventDefault();
    $.ajax({
      url: '/response/up_vote',
      method: 'POST',
      data: { id: commentId },
      dataType: 'JSON'
    }).done( function (response) {
    }).fail( function (response) {
        console.log(response);
    })
  })
})

Clean up comments and console.logs.


'use strict';

var namespace = require( './../lib' );

// Assign all modules to the GLOBAL namespace:
var ns = namespace( GLOBAL );

var bool = ( typeof ns.erf === 'function' );
console.log( bool );
// => true

bool = ( ns.erf === GLOBAL.erf );
console.log( bool );
// => true

console.log( erf( 5.0 ) ); // TODO: eslint
// => <number>

'use strict';

var namespace = require( './../lib' );

// Assign all modules to the global namespace:
var ns = namespace( global );

var bool = ( typeof ns.erf === 'function' );
console.log( bool );
// => true

bool = ( ns.erf === global.erf );
console.log( bool );
// => true

console.log( erf( 5.0 ) ); // TODO: eslint
// => <number>

Fix use of deprecated GLOBAL


angular
  .module('lnPatterns')
  .directive('lnOGravityForm', lnOGravityForm);

/**
 * TODO:
 *    - Expand the list of supported input types (see comments in form parser)
 *    - Add in support for confirmation types other than just 'message'
 *    - Add in support for input masks on the client side
 *    - Finish implementing paged support
 */

lnOGravityForm.$inject = ['$compile'];

function lnOGravityForm($compile) {
  return {
    restrict: 'A',
    transclude: true,
    templateUrl: 'lnPatterns/organisms/gravity-form/template.html',
    scope: {},
    controller: 'lnOGravityFormController',
    controllerAs: 'vm',
    bindToController: {
      id: '@lnOGravityForm',
      onSubmit: '&lnSubmit',
      onError: '&lnError',
      loadFromAPI: '=lnLoadFromApi'
    },
    link: function link(scope, element) {
      var unbind = scope.$watch('formHTML', function (newHTML) {
        if (angular.isDefined(newHTML)) {
          var template = angular.element(newHTML);
          element.html(template[0]);
          $compile(element.contents())(scope);
        }
      });

      scope.$on('$destroy', function () {
        unbind();
      });
    }
  };
}

angular
  .module('lnPatterns')
  .directive('lnOGravityForm', lnOGravityForm);

/**
 * TODO:
 *    - Expand the list of supported input types (see comments in form parser)
 *    - Add in support for confirmation types other than just 'message'
 *    - Add in support for input masks on the client side
 *    - Finish implementing paged support
 */

lnOGravityForm.$inject = ['$compile'];

function lnOGravityForm($compile) {
  return {
    restrict: 'A',
    transclude: true,
    templateUrl: 'lnPatterns/organisms/gravity-form/template.html',
    scope: {},
    controller: 'lnOGravityFormController',
    controllerAs: 'vm',
    bindToController: {
      id: '@lnOGravityForm',
      onSubmit: '&lnSubmit',
      onError: '&lnError',
      loadFromAPI: '=lnLoadFromApi'
    },
    link: function link(scope, element) {
      var unbind = scope.$watch('formHTML', function (newHTML) {
        if (angular.isDefined(newHTML)) {
          var template = angular.element(newHTML);

          // If we are using jQuery as a global, we need to unrwap the HTML.
          if (window.$) {
            template = angular.element(newHTML.$$unwrapTrustedValue());
          }
          element.html(template[0]);
          $compile(element.contents())(scope);
        }
      });

      scope.$on('$destroy', function () {
        unbind();
      });
    }
  };
}

Add if to check if $ is globally used


Dropzone.autoDiscover = false;

document.addEventListener("turbolinks:load", function() {
  //Only work at words form page
  if ($('#word_body').length == 0) { return; }

  //Dropzone.js
  var de =  $("#upload-dropzone");
  de.dropzone(
    {
      url: de.attr('url'),
      paramName: 'attachment[file]',
      previewTemplate: '

',
      init: function(){
          this.on('sending', function(file, xhr, formData){
            formData.append('authenticity_token', de.attr('authenticity-token'));
          }),
          this.on('addedfile', function(file, json) {
            console.log(file);
            simplemde.codemirror.replaceSelection("")
          }),
          this.on('success', function(file, json) {
            var code = "![" + json.file.url + "](" + json.file.url + ")"
            var text = simplemde.value();
            simplemde.value(text.replace("", code));
          });
      }
    });
});

Dropzone.autoDiscover = false;

document.addEventListener("turbolinks:load", function() {
  //Only work at words form page
  if ($('#word_body').length == 0) { return; }

  //Dropzone.js
  var myDropzone;
  var de =  $("#upload-dropzone");

  de.dropzone(
    {
      url: de.attr('url'),
      paramName: 'attachment[file]',
      previewTemplate: '

',
      init: function(){
          this.on('sending', function(file, xhr, formData){
            formData.append('authenticity_token', de.attr('authenticity-token'));
          }),
          this.on('addedfile', function(file, json) {
            console.log(file);
            simplemde.codemirror.replaceSelection("")
          }),
          this.on('success', function(file, json) {
            var code = "![" + json.file.url + "](" + json.file.url + ")"
            var text = simplemde.value();
            simplemde.value(text.replace("", code));
          });
          myDropzone = this;
      }
    });

  document.onpaste = function(event){
    var items = (event.clipboardData || event.originalEvent.clipboardData).items;
    for (index in items) {
      var item = items[index];
      if (item.kind === 'file') {
        myDropzone.addFile(item.getAsFile())
      }
    }
  }
});

Enable to upload image by paste


'use strict';

function DefaultPartitioner() {
    this.getPartition = function () {
        return 0;
    }
}

function RandomPartitioner() {
    this.getPartition = function (partitions) {
        return partitions[Math.floor(Math.random() * partitions.length)];
    }
}

function KeyedPartitioner() {
    // Taken from oid package (Dan Bornstein)
    // Copyright The Obvious Corporation.
    function hashCode(string) {
        var hash = 0;
        var length = string.length;

        for (var i = 0; i < length; i++) {
            hash = ((hash * 31) + string.charCodeAt(i)) & 0x7fffffff;
        }

        return (hash === 0) ? 1 : hash;
    }

    this.getPartition = function (partitions, key) {
        key = key || ''

        var index = hashCode(key) % partitions.length;
        return partitions[index];
    }
}

exports.DefaultPartitioner = DefaultPartitioner;
exports.RandomPartitioner = RandomPartitioner;
exports.KeyedPartitioner = KeyedPartitioner;

var _ = require('lodash');

'use strict';

function DefaultPartitioner() {
    this.getPartition = function (partitions) {
        if (partitions && _.isArray(partitions) && partitions.length > 0) {
            return partitions[0];
        } else {
            return 0;
        }
    }
}

function RandomPartitioner() {
    this.getPartition = function (partitions) {
        return partitions[Math.floor(Math.random() * partitions.length)];
    }
}

function KeyedPartitioner() {
    // Taken from oid package (Dan Bornstein)
    // Copyright The Obvious Corporation.
    function hashCode(string) {
        var hash = 0;
        var length = string.length;

        for (var i = 0; i < length; i++) {
            hash = ((hash * 31) + string.charCodeAt(i)) & 0x7fffffff;
        }

        return (hash === 0) ? 1 : hash;
    }

    this.getPartition = function (partitions, key) {
        key = key || ''

        var index = hashCode(key) % partitions.length;
        return partitions[index];
    }
}

exports.DefaultPartitioner = DefaultPartitioner;
exports.RandomPartitioner = RandomPartitioner;
exports.KeyedPartitioner = KeyedPartitioner;

Correct bug in producer; producer always writes to partition 0 even if a specific partition is set in the payload.


const userController = require('../controllers/user');
const authenticationMiddleware = require('../middleware/authentication');
const express = require('express');

const router = express.Router();

// GET all users
router.get(
  '/',  // route
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.getUsers  // the controller
);
// GET a specific user
router.get(
  '/:id',
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.getUserById
);
// CREATE a new user
router.post('/', userController.registerNewUser);
// DELETE a user
router.delete(
  '/:id',
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.deleteUserById
);
router.patch(
  '/:id/roles',
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  authenticationMiddleware.verifyAdministrator,     // verifyAdministrator middleware
  userController.setRoles
);

module.exports = router;

const userController = require('../controllers/user');
const authenticationMiddleware = require('../middleware/authentication');
const express = require('express');

const router = express.Router();

// GET all users
router.get(
  '/',  // route
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.getUsers  // the controller
);
// GET a specific user
router.get(
  '/:id',
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.getUserById
);
// CREATE a new user
router.post('/', userController.registerNewUser);
// DELETE a user
router.delete(
  '/:id',
  authenticationMiddleware.validateAuthentication,  // isAuthenticated middleware
  userController.deleteUserById
);
router.patch(
  '/:id/roles',
  authenticationMiddleware.validateAuthenticationAttachUser, // verify token and attach user to res
  authenticationMiddleware.verifyAdministrator,              // verifyAdministrator middleware
  userController.setRoles
);

module.exports = router;

Use AttachUser middleware before verifyAdmin.


'use strict';

// To make id smaller we get microseconds count from more recent date
var start = Date.UTC(2012, 12, 21, 12, 0, 0, 0) * 1000

// Prefix with number, it reduces chances of collision with variable names
// (helpful if used as property names on objects)
  , prefix = String(Math.floor(Math.random() * 10))

// Make it more unique
  , postfix = Math.floor(Math.random() * 36).toString(36);

module.exports = function (time) {
	return prefix + (time - start).toString(36) + postfix;
};

'use strict';

// To make id smaller we get microseconds count from more recent date
var start = Date.UTC(2012, 12, 21, 12, 0, 0, 0) * 1000

// Prefix with number, it reduces chances of collision with variable names
// (helpful if used as property names on objects)
  , prefix = String(Math.floor(Math.random() * 10))

// Make it more unique
  , postfix = Math.floor(Math.random() * 36).toString(36)

  , abs = Math.abs;

module.exports = function (time) {
	return prefix + abs(time - start).toString(36) + postfix;
};

Make sure number is positive, in case of wrong setting of local time


var historyFallback = require('connect-history-api-fallback');
var log = require('connect-logger');
var yargs = require('yargs');
var sync = require('browser-sync').create();
var defaultOpenPath = '';

yargs.option('files', {
  describe: 'array of file paths to watch',
  type: 'array'
});

var argv = yargs.argv;
var openPath = getOpenPath();
var indexFile = argv.indexFile || 'index.html'
var options =
  {
    openPath: openPath,
    files: argv.files ? argv.files : [
      openPath + '/**/*.html',
      openPath + '/**/*.css',
      openPath + '/**/*.js'
    ],
    baseDir: argv.baseDir || './',
    fallback: '/' + openPath + '/' + indexFile
  };

if (argv.verbose) {
  console.log('options', options);
}

function getOpenPath() {
  var src = argv.open || defaultOpenPath;
  if (!src) {
    return '.'
  }
  return src;
}

sync.init({
  port: argv.port || 3000,
  server: {
    baseDir: options.baseDir,
    middleware: [
      log(),
      historyFallback({ index: options.fallback })
    ]
  },
  files: options.files,
});

'use strict';

var historyFallback = require('connect-history-api-fallback');
var log = require('connect-logger');
var yargs = require('yargs');
var sync = require('browser-sync').create();
var path = require('path');

// Load optional browser-sync config file
var bsConfigPath = path.resolve('bs-config');
var options = {};
try {
  options = require(bsConfigPath);
} catch (err) { } // silent error

// Process CLI arguments
yargs.option('files', {
  describe: 'array of file paths to watch',
  type: 'array'
});
var argv = yargs.argv;
setArgOverrides(options, argv);

function setArgOverrides(o, argv) {
  o.port = argv.port || o.port || 3000;
  o.openPath = argv.open || o.openPath || '.';
  o.files = argv.files || o.files || [
    o.openPath + '/**/*.html',
    o.openPath + '/**/*.css',
    o.openPath + '/**/*.js'
  ];
  o.server = o.server || {};
  o.server.baseDir = argv.baseDir || o.server.baseDir || './';
  o.server.middleware = o.server.middleware || [
    log(),
    historyFallback({ index: '/' + o.openPath + '/' + (argv.indexFile || 'index.html') })
  ]
}

if (argv.verbose) {
  console.log('options', options);
}

// Run browser-sync
sync.init(options);

Add support for browsersync configuration in external rc file


/**
 * @author Martin Giger
 * @module tank-treads
 * @license MIT
 */

var HALF_PI = Math.PI / 2;
var THREE_HALF_PI = Math.PI + HALF_PI;

/**
 * Calculates the speed of the left and right treads for a tank-like vehicle,
 * based on an angle to go to relative to where the vehicle's currently headed.
 * @class
 */
function TankTreads() {
}
/**
 * @type {number}
 * @default
 */
TankTreads.prototype.leftSpeed = 0;
/**
 * @type {number}
 * @default
 */
TankTreads.prototype.rightSpeed = 0;

/**
 * Updates the leftSpeed and rightSpeed attributes.
 * @argument {number} angle - The angle to head into relative to the current
 *                            direction.
 */
TankTreads.prototype.setInput = function(angle) {
    var shp = angle <= HALF_PI;
    var sp = angle <= Math.PI;
    if(shp || (!sp && angle < THREE_HALF_PI)) {
        if(shp)
            this.rightSpeed = -Math.cos(angle * 2);
        else
            this.rightSpeed = Math.cos(angle * 2);
        this.leftSpeed = shp ? 1 : -1;
    }
    else {
        this.rightSpeed = sp ? 1 : -1;
        if(sp)
            this.leftSpeed = Math.cos(angle * 2 + Math.PI);
        else
            this.leftSpeed = -Math.cos(angle * 2 + Math.PI);
    }
}

module.exports = TankTreads;

/**
 * @author Martin Giger
 * @module tank-treads
 * @license MIT
 */

var HALF_PI = Math.PI / 2;
var THREE_HALF_PI = Math.PI + HALF_PI;

/**
 * Calculates the speed of the left and right treads for a tank-like vehicle,
 * based on an angle to go to relative to where the vehicle's currently headed.
 * @class
 */
function TankTreads() {
}
/**
 * @type {number}
 * @default
 */
TankTreads.prototype.leftSpeed = 0;
/**
 * @type {number}
 * @default
 */
TankTreads.prototype.rightSpeed = 0;

/**
 * Updates the leftSpeed and rightSpeed attributes.
 * @argument {number} angle - The angle to head into relative to the current
 *                            direction.
 */
TankTreads.prototype.setInput = function(angle) {
    var shp = angle <= HALF_PI;
    var sp = angle <= Math.PI;
    if(shp || (!sp && angle < THREE_HALF_PI)) {
        this.leftSpeed = shp ? 1 : -1;
        this.rightSpeed = -this.leftSpeed * Math.cos(angle * 2);
    }
    else {
        this.rightSpeed = sp ? 1 : -1;
        this.leftSpeed = this.rightSpeed * Math.cos(angle * 2 + Math.PI);
    }
}

module.exports = TankTreads;

Simplify the calculation by removing one conditional


let fs = require('fs');
let objLoc = require('../src/ObjectLocator');
var expect = require('chai').expect;

describe('Object Locator Tests', () => {
    it('Should be constructed and return the correct order', () => {
        let obj = new objLoc(fs, "Item");
        let json = obj.run();
        expect(JSON.stringify(json)).to.contain('Item');
        expect(JSON.stringify(json)).to.contain('Cart');
        expect(JSON.stringify(json)).to.contain('Customer');
    });

    it('should return error on json file not existing', () => {
        let obj = new objLoc(fs, "BadItem");
        expect(obj.run).to.throw(Error);
    });

    it('should return error on dependencies not existing', () => {
        let obj = new objLoc(fs, "BadCustomer");
        expect(() => {
            obj.run()
        }).to.throw("Json for the file BadCustomer must have a dependency array, if none provide a blank array");
    });

    it('should return error on dependencies not being an array', () => {
        let obj = new objLoc(fs, "BadCart");
        expect(() => {
            obj.run()
        }).to.throw("Dependencies must be an array! object BadCart file" +
            " dependencies is not an array");
    });

});

let fs = require('fs');
let objLoc = require('../src/ObjectLocator');
var expect = require('chai').expect;

describe('Object Locator Tests', () => {
    it('Should be constructed and return the correct order', () => {
        let obj = new objLoc(fs, "Item");
        let json = obj.run();
        expect(JSON.stringify(json)).to.contain('Item');
        expect(JSON.stringify(json)).to.contain('Cart');
        expect(JSON.stringify(json)).to.contain('Customer');
    });

    it('should locate object with no dependencies', () => {
        let obj = new objLoc(fs, "Customer");
        let json = obj.run();
        expect(json[0].metadata.dependencies).to.be.instanceof(Array);
        expect(json[0].metadata.dependencies).to.be.empty;
    });

    it('should return error on json file not existing', () => {
        let obj = new objLoc(fs, "BadItem");
        expect(obj.run).to.throw(Error);
    });

    it('should return error on dependencies not existing', () => {
        let obj = new objLoc(fs, "BadCustomer");
        expect(() => {
            obj.run()
        }).to.throw("Json for the file BadCustomer must have a dependency array, if none provide a blank array");
    });

    it('should return error on dependencies not being an array', () => {
        let obj = new objLoc(fs, "BadCart");
        expect(() => {
            obj.run()
        }).to.throw("Dependencies must be an array! object BadCart file" +
            " dependencies is not an array");
    });

});

Add ObjectLocator test for case where object has no dependencies


import { Paginator } from '../../utils';
import template from './alerts-list.html';

const stateClass = {
  ok: 'label label-success',
  triggered: 'label label-danger',
  unknown: 'label label-warning',
};

class AlertsListCtrl {
  constructor(Events, Alert) {
    Events.record('view', 'page', 'alerts');

    this.alerts = new Paginator([], { itemsPerPage: 20 });
    Alert.query((alerts) => {
      this.alerts.updateRows(alerts.map(alert => ({
        name: alert.name,
        state: alert.state,
        class: stateClass[alert.state],
        created_by: alert.user.name,
        created_at: alert.created_at,
        updated_at: alert.updated_at,
      })));
    });
  }
}

export default function (ngModule) {
  ngModule.component('alertsListPage', {
    template,
    controller: AlertsListCtrl,
  });

  return {
    '/alerts': {
      template: '<alerts-list-page></alerts-list-page>',
      title: 'Alerts',
    },
  };
}

import { Paginator } from '../../utils';
import template from './alerts-list.html';

const stateClass = {
  ok: 'label label-success',
  triggered: 'label label-danger',
  unknown: 'label label-warning',
};

class AlertsListCtrl {
  constructor(Events, Alert) {
    Events.record('view', 'page', 'alerts');

    this.alerts = new Paginator([], { itemsPerPage: 20 });
    Alert.query((alerts) => {
      this.alerts.updateRows(alerts.map(alert => ({
        id: alert.id,
        name: alert.name,
        state: alert.state,
        class: stateClass[alert.state],
        created_by: alert.user.name,
        created_at: alert.created_at,
        updated_at: alert.updated_at,
      })));
    });
  }
}

export default function (ngModule) {
  ngModule.component('alertsListPage', {
    template,
    controller: AlertsListCtrl,
  });

  return {
    '/alerts': {
      template: '<alerts-list-page></alerts-list-page>',
      title: 'Alerts',
    },
  };
}

Send alert ID to UI


app.controller('myCtrl', function($scope, corporations) {
  $scope.apps = corporations.information();
  $scope.selectedFactions = shuffle($scope.apps).slice(0,3)
  $scope.growthFaction = prepareInitialStats($scope.selectedFactions[0], 1)
  $scope.valueFaction = prepareInitialStats($scope.selectedFactions[1], 2)
  $scope.stableFaction = prepareInitialStats($scope.selectedFactions[2], 3)
});

app.controller('CorporateController', ['$scope', '$routeParams', 'corporations', function($scope, $routeParams, corporations) {
  $scope.faction = corporations.information()[$routeParams.id - 1];
}]);

app.controller('PlayerController', ['$scope', 'localStorageService', function($scope, localStorageService) {
  $scope.name = localStorageService.get("name");
  $scope.changeName = function(name) {
    localStorageService.set("name", name);
    $scope.name = name;
  }
}]);

app.controller('myCtrl', ['$scope', 'corporations', 'localStorageService', function($scope, corporations, localStorageService) {
  $scope.apps = corporations.information();
  $scope.selectedFactions = function()
  {
    var data = localStorageService.get("corporations")
    if (data == undefined ) {
      var data = shuffle($scope.apps).slice(0,3)
      localStorageService.set("corporations", data)
      return data
    }
    else
    {
      return data
    }
  }();

  $scope.growthFaction = prepareInitialStats($scope.selectedFactions[0], 1)
  $scope.valueFaction = prepareInitialStats($scope.selectedFactions[1], 2)
  $scope.stableFaction = prepareInitialStats($scope.selectedFactions[2], 3)

  $scope.attackTarget = function(faction) {
    console.log("You pressed a button!")
  }
}]);

app.controller('CorporateController', ['$scope', '$routeParams', 'corporations', function($scope, $routeParams, corporations) {
  $scope.faction = corporations.information()[$routeParams.id - 1];
}]);

app.controller('PlayerController', ['$scope', 'localStorageService', function($scope, localStorageService) {
  $scope.name = localStorageService.get("name");
  $scope.changeName = function(name) {
    localStorageService.set("name", name);
    $scope.name = name;
  }
  $scope.attackTarget = function(faction) {
    console.log("You pressed a button!")
  }
}]);

Save and load data about corporations using LocalStorageService


'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
const { maybeEmbroider } = require('@embroider/test-setup');

process.env.buildTarget = EmberAddon.env();

module.exports = function (defaults) {
  const app = new EmberAddon(defaults, {
    minifyCSS: {
      enabled: false
    }
  });

  // This build file specifies the options for the dummy test app of this
  // addon, located in `/tests/dummy`
  // This build file does *not* influence how the addon or the app using it
  // behave. You most likely want to be modifying `./index.js` or app's build file

  return maybeEmbroider(app, {
    packageRules: [
      {
        package: 'dummy',
        components: {
          '{{foo-select-box}}': {
            safeToIgnore: true
          }
        }
      }
    ]
  });
};

'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
const { maybeEmbroider } = require('@embroider/test-setup');

process.env.buildTarget = EmberAddon.env();

module.exports = function (defaults) {
  const app = new EmberAddon(defaults, {
    minifyCSS: {
      enabled: false
    }
  });

  // This build file specifies the options for the dummy test app of this
  // addon, located in `/tests/dummy`
  // This build file does *not* influence how the addon or the app using it
  // behave. You most likely want to be modifying `./index.js` or app's build file

  return maybeEmbroider(app, {
    // Needed for IE11 https://github.com/embroider-build/embroider/issues/731
    skipBabel: [
      {
        package: 'qunit',
      },
    ],
    packageRules: [
      {
        package: 'dummy',
        components: {
          '{{foo-select-box}}': {
            safeToIgnore: true
          }
        }
      }
    ]
  });
};

Fix embroider build in CI


var gulp = require("gulp");
var usemin = require("gulp-usemin");
var ngmin = require("gulp-ngmin");
var uglify = require("gulp-uglify");
var minifyHtml = require("gulp-minify-html");
var minifyCss = require("gulp-minify-css");
var rev = require("gulp-rev");

gulp.task('partials', function() {
    var stream = gulp.src("app/**/*.html")
            .pipe(gulp.dest("prod/"));
    return stream;
});

gulp.task('other', function() {
    var stream = gulp.src(["app/assets/fonts/**/*", "app/assets/ico/**/*", "app/assets/img/**/*"], {
        base: "app"
    }).pipe(gulp.dest("prod/"));
    return stream;
});

gulp.task('default', ['partials', 'other'], function() {
    return gulp.src("./app/index.html")
        .pipe(usemin({
            css: ['concat'],
            //html: [minifyHtml({empty: true})],
            js: [ngmin(), uglify(), 'concat']
        }))
        .pipe(gulp.dest("prod/"));
});

var gulp = require("gulp");
var usemin = require("gulp-usemin");
var ngmin = require("gulp-ngmin");
var uglify = require("gulp-uglify");
var minifyHtml = require("gulp-minify-html");
var minifyCss = require("gulp-minify-css");
var rev = require("gulp-rev");
var clean = require("gulp-clean");
var gulpSequence = require("gulp-sequence");

// Brings over the angular html partials.
gulp.task('partials', function() {
    var stream = gulp.src("app/**/*.html")
            .pipe(gulp.dest("prod/"));
    return stream;
});

// Brings over other assets such as fonts and images,
// and the application style sheet.
gulp.task('other', function() {
    var stream = gulp.src([
        "app/assets/fonts/**/*",
        "app/assets/ico/**/*",
        "app/assets/css/select2/*",
        "app/assets/css/images/*",
        "app/assets/img/**/*",
        "app/style-3.css"], {
            base: "app"
        }).pipe(gulp.dest("prod/"));
    return stream;
});

// Cleans the destination directory.
gulp.task('clean', function() {
    var stream = gulp.src("prod/").pipe(clean({read: false, force: true}));
    return stream;
});

// Builds the new index.html, concats and minimizes
// the files.
gulp.task('min', function() {
    return gulp.src("./app/index.html")
        .pipe(usemin({
            css: ['concat'],
            //html: [minifyHtml({empty: true})],
            js: [ngmin(), uglify(), 'concat']
        }))
        .pipe(gulp.dest("prod/"));
});

gulp.task('default', gulpSequence('clean', 'partials', 'other', 'min'));

Update gulp file to build a clean version of prod. Sequence the tasks and update them to include needed assets.


/**
 *
 * Delay jobs to make the page remain responsive during expensive jobs.
 *
 * Usage:
 *
 *  require(["work_queue"], function(_work_queue) {
 *    _.each(ids, function(id) {
 *      _work_queue.add(function() {
 *        someExpensiveOperation(id);
 *      });
 *    }):
 *  });
 *
 *  The queue run is started after all events currently queue are processed.
 *
 *  You can pass a second argument to `_work_queue.add` as the `this` context.
 *
 *  var foo = "The Swiftest";
 *  _work_queue.add(function() {
 *    console.log(this);
 *  }, foo);
 *
 */
// TODO(jlfwong): Add async support?
define(['ext/underscore'], function(_) {
  var running = false;
  var queue = [];
  var INTERJOB_DELAY_MS = 10;

  var runNextJob = function() {
    if (queue.length === 0) {
      running = false;
      return;
    }

    var job = queue.shift();

    job.fn.apply(job.context);

    setTimeout(function() {
      runNextJob();
    }, INTERJOB_DELAY_MS);
  };

  var start = function() {
    if (running) {
      return;
    }
    running = true;
    runNextJob();
  };

  return {
    add: function(fn, context) {
      queue.push({
        fn: fn,
        context: context
      });

      setTimeout(start, INTERJOB_DELAY_MS);
    }
  };
});

/**
 *
 * Delay jobs to make the page remain responsive during expensive jobs.
 *
 * Usage:
 *
 *  require(["work_queue"], function(_work_queue) {
 *    _.each(ids, function(id) {
 *      _work_queue.add(function() {
 *        someExpensiveOperation(id);
 *      });
 *    }):
 *  });
 *
 *  The queue run is started after all events currently queue are processed.
 *
 *  You can pass a second argument to `_work_queue.add` as the `this` context.
 *
 *  var foo = "The Swiftest";
 *  _work_queue.add(function() {
 *    console.log(this);
 *  }, foo);
 *
 */
// TODO(jlfwong): Add async support?
define(['ext/underscore'], function(_) {
  var running = false;
  var queue = [];

  var runNextJob = function() {
    if (queue.length === 0) {
      running = false;
      return;
    }

    var job = queue.shift();

    job.fn.apply(job.context);

    setTimeout(function() {
      runNextJob();
    }, 0);
  };

  var start = function() {
    if (running) {
      return;
    }
    running = true;
    runNextJob();
  };

  return {
    add: function(fn, context) {
      queue.push({
        fn: fn,
        context: context
      });

      setTimeout(start, 0);
    }
  };
});

Use an intejob delay of 0 for work queue


var through          =  require('through');
module.exports = function (file, opts) {
  if (file === require.resolve('../index')) return through();
  if (/\.json$/.test(file)) return through();
  var data = '';

  return through(write, end);

  function write (buf) { data += buf; }
  function end() {
    if (data.match(/mockquire/g)) {
      this.queue('/* automatic insertion of the mockquire variable */ var mockquire = require("browsyquire")(require); mockquire.noCallThru(); /* end */');
    }
    //var deps = requireDependencies(data);
    //this.queue(deps);
    this.queue(data);
    this.queue(null);
  }
}

var through          =  require('through');
module.exports = function (file, opts) {
  if (file === require.resolve('../index')) return through();
  if (/\.json$/.test(file)) return through();
  var data = '';

  return through(write, end);

  function write (buf) { data += buf; }
  function end() {
    if (data.match(/mockquire/g)) {
      this.queue('/* automatic insertion of the mockquire variable */ var mockquire = require("browsyquire")(require); mockquire.reset(); mockquire.noCallThru(); /* end */');
    }
    //var deps = requireDependencies(data);
    //this.queue(deps);
    this.queue(data);
    this.queue(null);
  }
}

Add a reset call before noCallThru to prevent reusing stale modules in normal requires


/**
 * Home controller definition
 * @scope Controllers
 */
define(['./module', 'jquery', './home-directives'], function(controllers, $) {
    'use strict';

    controllers.controller('HomeController', ['$scope', 'fireRef',
        function HomeController($scope, fireRef) {
            $scope.newLink = '';

            $scope.$watch('links', function() {
                // Count the number of links
                var numberOfLinks = $('.category-block').length + 1,
                    totalLength = numberOfLinks * 9;

                // Resize the list width, fits to the content size.
                $('ul').css('width', totalLength + "px");
            }, true);

            $scope.addLink = function() {
                var newLink = $scope.newLink.trim();

                if (!newLink.length) {
                    return;
                }

                $scope.links.$add({
                    url: newLink,
                    nbClick: 0
                });

                $scope.newLink = '';
            };

            $scope.incrementClick = function(id) {
                // Check if the attribute exists. Default value is 0.
                if ($scope.links[id].nbClick === undefined) {
                    $scope.links[id].nbClick = 0;
                }

                $scope.links[id].nbClick++;

                $scope.links.$save();
            };

            $scope.links = fireRef.links();
        }
    ]);
});

/**
 * Home controller definition
 * @scope Controllers
 */
define(['./module', 'jquery', './home-directives'], function(controllers, $) {
    'use strict';

    controllers.controller('HomeController', ['$scope', 'fireRef',
        function HomeController($scope, fireRef) {
            $scope.newLink = '';
            $scope.nbLinks = 0;

            $scope.$watch('links', function() {
                $scope.nbLinks = $scope.links.$getIndex().length;

                // Resize the list width, fits to the content size.
                $('.link-list').css('width', $scope.nbLinks * 9 + 'px');
            }, true);

            $scope.addLink = function() {
                var newLink = $scope.newLink.trim();

                if (!newLink.length) {
                    return;
                }

                $scope.links.$add({
                    url: newLink,
                    nbClick: 0
                });

                $scope.newLink = '';
            };

            $scope.incrementClick = function(id) {
                // Check if the attribute exists. Default value is 0.
                if ($scope.links[id].nbClick === undefined) {
                    $scope.links[id].nbClick = 0;
                }

                $scope.links[id].nbClick++;

                $scope.links.$save();
            };

            $scope.links = fireRef.links();
        }
    ]);
});

Switch to array length for link number


'use strict';

var expect = require('chai').expect
  , twilioCaller = require('../../lib/twilio-caller')
  , sinon = require('sinon')
  , mockery = require('mockery');

describe('twilio-caller', function () {
  describe('#call', function () {
    var twilio = require('twilio');

    var twilioStub = function(accountSid, authToken) {
      return {
        calls:
          new TwilioClientStub()
      }
    };

    var TwilioClientStub = sinon.stub();
    var createSpy = sinon.spy();

    TwilioClientStub.prototype.create = createSpy;

    before(function (done) {
      mockery.enable();
      mockery.warnOnUnregistered(false);
      mockery.registerMock('twilio', twilioStub);
      done();
    });

    after(function (done) {
      mockery.deregisterMock('twilio');
      mockery.disable();
      done();
    });

    it('makes a call to client:agent3', function () {
      twilioCaller.call('agent3', 'callback-url');

      expect(createSpy.calledWith({
        from: 'my-twilio-number',
        to: 'client:agent3',
        url: 'callback-url'
      })).to.be.true;
    });
  });
});

'use strict';

var expect = require('chai').expect
  , twilioCaller = require('../../lib/twilio-caller')
  , sinon = require('sinon')
  , mockery = require('mockery');

describe('twilio-caller', function () {
  describe('#call', function () {
    var twilio = require('twilio');

    var twilioStub = () => ({ calls: new TwilioClientStub() });

    var TwilioClientStub = sinon.stub();
    var createSpy = sinon.spy();

    TwilioClientStub.prototype.create = createSpy;

    before(function (done) {
      mockery.enable();
      mockery.warnOnUnregistered(false);
      mockery.registerMock('twilio', twilioStub);
      done();
    });

    after(function (done) {
      mockery.deregisterMock('twilio');
      mockery.disable();
      done();
    });

    it('makes a call to client:agent3', function () {
      twilioCaller.call('agent3', 'callback-url');

      expect(createSpy.calledWith({
        from: 'my-twilio-number',
        to: 'client:agent3',
        url: 'callback-url'
      })).to.be.true;
    });
  });
});

Make stub creation more concise


/*global _, Backbone, lumbarLoader */
(function() {
  lumbarLoader.initEvents = function() {
    // Needs to be defered until we know that backbone has been loaded
    _.extend(lumbarLoader, Backbone.Events);
  };
  if (window.Backbone) {
    lumbarLoader.initEvents();
  }

  var baseLoadModule = lumbarLoader.loadModule;
  lumbarLoader.loadModule = function(moduleName, callback, options) {
    options = options || {};

    var loaded = lumbarLoader.isLoaded(moduleName);
    if (!options.silent && !loaded) {
      lumbarLoader.trigger && lumbarLoader.trigger('load:start', moduleName, undefined, lumbarLoader);
    }
    baseLoadModule(moduleName, function(error) {
      if (!options.silent && !loaded) {
        lumbarLoader.trigger && lumbarLoader.trigger('load:end', lumbarLoader);
      }
      callback(error);
    }, options);
  };
}());

/*global _, Backbone, lumbarLoader */
(function() {
  lumbarLoader.initEvents = function() {
    // Needs to be defered until we know that backbone has been loaded
    _.extend(lumbarLoader, Backbone.Events);
  };
  if (window.Backbone) {
    lumbarLoader.initEvents();
  }

  var baseLoadModule = lumbarLoader.loadModule;
  lumbarLoader.loadModule = function(moduleName, callback, options) {
    options = options || {};

    var loaded = lumbarLoader.isLoaded(moduleName);
    if (!options.silent && !loaded) {
      lumbarLoader.trigger && lumbarLoader.trigger('load:start', moduleName, undefined, lumbarLoader);
    }
    baseLoadModule(moduleName, function(error) {
      if (!options.silent && !loaded) {
        lumbarLoader.trigger && lumbarLoader.trigger('load:end', lumbarLoader);
      }
      callback && callback(error);
    }, options);
  };
}());

Allow loading without a callback


import request from 'supertest';
import test    from 'tape';

import app     from '../server';

test('Should leftpad correctly', t => {
    request(app)
        .get('?str=paddin%27%20oswalt&len=68&ch=@')
        .expect(200)
        .expect('Content-Type', /json/)
        .end((err, res) => {
            if (err) throw err;
            t.equal(res.body.str, `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@paddin' oswalt`)
            t.end();
        });
});

test('Should handle missing paddable string correctly', t => {
    request(app)
        .get('?len=68&ch=@')
        .expect(200)
        .expect('Content-Type', /json/)
        .end((err, res) => {
            if (err) throw err;
            t.equal(res.body.str, `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@`)
            t.end();
        });
});

Add test for missing str parameter


// Sloppy mock for component.install in tests

var
  utils   = require('../lib/utils'),
  fs      = require('fs-extra'),
  Emitter = require('events').EventEmitter;

function Package (repo, version, options) {
  this.repo = repo;
  this.version = version;
  this.options = options;
}

Package.prototype.__proto__ = Emitter.prototype;

Package.prototype.install = function () {
  var options = {
    src : '../mocks/components/' + this.repo.replace('/', '-'),
    dest : utils.getInstallDir(this.repo)
  };
  fs.copy(options, function (err) {
    this.emit('end');
  });
}

module.exports = {
  install : function (repo, version, options) {
    return new Package(repo, version, options);
  }
};

// Sloppy mock for component.install in tests

var
  utils   = require('../lib/utils'),
  fs      = require('fs-extra'),
  Emitter = require('events').EventEmitter;

function Package (repo, version, options) {
  this.repo = repo;
  this.version = version;
  this.options = options;
}

Package.prototype.__proto__ = Emitter.prototype;

Package.prototype.install = function () {
  var options = {
    src : __dirname + '/components/' + this.repo.replace('/', '-'),
    dest : utils.getInstallDir(this.repo)
  };
  fs.copy(options, function (err) {
    this.emit('end');
  });
}

module.exports = {
  install : function (repo, version, options) {
    return new Package(repo, version, options);
  }
};

Use proper path when copying manifests to test install


/**
 * @title Open - cordova.plugins.bridge.open
 * @overview Open documents with compatible apps.
 * @copyright © 2014 cordova-bridge
 * @license GPLv2
 * @author Carlos Antonio
 * @version 0.1.0
*/

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

/**
 * open
 *
 * @param {String} args File URI
 * @param {Function} success Call on success
 * @param {Function} error Call on error
 */
exports.open = function(args, success, error) {
  if (!args || arguments.length === 0) return;

  function onSuccess() {
    var args = (arguments.length === 1) ? arguments[0] : arguments;
    if (typeof success === 'function') success(args);
  }

  function onError(error) {
    if (typeof error === 'function') error(error);
  }
  exec(onSuccess, onError, "Open", "open", [args]);
};

/**
 * @title Open - cordova.plugins.bridge.open
 * @overview Open documents with compatible apps.
 * @copyright © 2014 cordova-bridge
 * @license GPLv2
 * @author Carlos Antonio
 * @version 0.1.0
*/

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

/**
 * open
 *
 * @param {String} args File URI
 * @param {Function} success Call on success
 * @param {Function} error Call on error
 */
exports.open = function(args, success, error) {
  if (!args || arguments.length === 0) return;

  function onSuccess() {
    var args = (arguments.length === 1) ? arguments[0] : arguments;
    if (typeof success === 'function') success(args);
  }

  function onError(code) {
    if (typeof error === 'function') error(code);
  }
  exec(onSuccess, onError, "Open", "open", [args]);
};

Rename parameter to not interfere with cb func


/**
 * Created by nkmathew on 23/06/2016.
 */

$(document).ready(function () {
    var source   = $("#email-list-template").html();
    var template = Handlebars.compile(source);

    var html = template({email: 'ngetich.kipkoech@students.jkuat.ac.ke'});
    $('#email-list-section').append(html);

    $("#email-input-box").keyup(function (e) {
        if (e.keyCode == 13) {
            var email = $('#email-input-box').val() + '@students.jkuat.ac.ke';
            var html  = template({email: email});
            $('#email-list-section').append(html);

            $('.email-delete-btn').click(function () {
                $(this).closest('.email-line').remove();
            });
            $(this).val('');
        }
    });

    $("#invite-button").click(function () {
        var emailList = [];
        $('.email-address').each(function () {
            emailList.push($(this).html());
        });
        $.ajax({
            type: 'POST',
            url: '/site/send-signup-links',
            data: {
                'email-list': JSON.stringify(emailList),
            },
            error: function (msg) {
                alert('Problem occurred while trying to send email...');
            },
        });
    });
});

/**
 * Created by nkmathew on 23/06/2016.
 */

$(document).ready(function () {
    var source   = $("#email-list-template").html();
    var template = Handlebars.compile(source);

    var html = template({email: 'ngetich.kipkoech@students.jkuat.ac.ke'});
    $('#email-list-section').append(html);

    $("#email-input-box").keyup(function (e) {
        if (e.keyCode == 13) {
            var email = $('#email-input-box').val() + '@students.jkuat.ac.ke';
            var html  = template({email: email});
            $('#email-list-section').append(html);

            $('.email-delete-btn').click(function () {
                $(this).closest('.email-line').remove();
            });
            $(this).val('');
        }
    });

    $("#invite-button").click(function () {
        var emailList = [];
        $('.email-address').each(function () {
            emailList.push($(this).html());
        });
        $.ajax({
            type: 'POST',
            url: '/site/send-signup-links',
            data: {
                'email-list': JSON.stringify(emailList),
            },
            success: function () {
                $('.alert-box .msg').html('Signup links sent successfully');
                $('.alert-box').addClass('alert-success fade in');
                $('.alert-box').css('display', 'block');

                // Clear list
                console.log('Emails sent!!!')
                $('.email-line').remove();
            },
            error: function (xhr, status, error) {
                $('.alert-box .msg').html('
' + error + '

' + xhr.responseText);
                $('.alert-box').addClass('alert-danger fade in');
                $('.alert-box').css('display', 'block');
            },
        });
    });
});

Add ajax calls for sending emails


/* $This file is distributed under the terms of the license in /doc/license.txt$ */

$(document).ready(function(){

    // login form is hidden by default; use JavaScript to reveal
    $("#loginFormAndLinks").show();

    // focus on email or newpassword field
    $('.focus').focus();

});

// fade out error alerts
$('#errorAlert').css('display', 'none');
$('#errorAlert').fadeIn(2000);

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

$(document).ready(function(){

    // login form is hidden by default; use JavaScript to reveal
    $("#loginFormAndLinks").show();

    // focus on email or newpassword field
    $('.focus').focus();

    // fade out error alerts
    $('#errorAlert').css('display', 'none');
    $('#errorAlert').fadeIn(500);

});

Add less time for fading in alert messages.


import classNames from 'classnames/dedupe';
import React from 'react';

import TabButtonList from './TabButtonList';

class Tabs extends React.Component {
  getChildren() {
    const {props} = this;

    return React.Children.map(props.children, (tabElement) => {
      const newTabProps = {activeTab: props.activeTab};

      if (tabElement.type === TabButtonList) {
        newTabProps.onChange = props.handleTabChange;
        newTabProps.vertical = props.vertical;
      }

      return React.cloneElement(tabElement, newTabProps);
    });
  }

  render() {
    let classes = classNames('menu-tabbed-container', {
      'menu-tabbed-container-vertical': this.props.vertical
    });

    return (
      <div className={classes}>
        {this.getChildren()}
      </div>
    );
  }
}

Tabs.propTypes = {
  // Optional variable to set active tab from owner component
  activeTab: React.PropTypes.string,
  children: React.PropTypes.node.isRequired,
  className: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object,
    React.PropTypes.string
  ]),
  handleTabChange: React.PropTypes.func.isRequired,
  vertical: React.PropTypes.bool
};

module.exports = Tabs;

import classNames from 'classnames/dedupe';
import React from 'react';

import TabButtonList from './TabButtonList';

class Tabs extends React.Component {
  getChildren() {
    const {props} = this;

    return React.Children.map(props.children, (tabElement) => {
      const newTabProps = {activeTab: props.activeTab};

      if (tabElement.type === TabButtonList) {
        newTabProps.onChange = props.handleTabChange;
        newTabProps.vertical = props.vertical;
      }

      return React.cloneElement(tabElement, newTabProps);
    });
  }

  render() {
    let classes = classNames('menu-tabbed-container', this.props.className, {
      'menu-tabbed-container-vertical': this.props.vertical
    });

    return (
      <div className={classes}>
        {this.getChildren()}
      </div>
    );
  }
}

Tabs.propTypes = {
  // Optional variable to set active tab from owner component
  activeTab: React.PropTypes.string,
  children: React.PropTypes.node.isRequired,
  className: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object,
    React.PropTypes.string
  ]),
  handleTabChange: React.PropTypes.func.isRequired,
  vertical: React.PropTypes.bool
};

module.exports = Tabs;

Add prop classnames to the component


import path from 'path';
import fs from 'fs';

const getViewBoxDimensions = dir => file => {
  const fileContent = fs.readFileSync(path.join(dir, file), 'utf-8');
  const matches = fileContent.match(/viewBox=\"0 0 (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)\"/);
  if ( ! matches) return;
  return {
    width: parseFloat(matches[1]),
    height: parseFloat(matches[2])
  }
};

const walkSync = function(dir) {
  const isDirectory = dir => file => fs.statSync(path.join(dir, file)).isDirectory();
  const filter = dir => file => file.match(/\.svg$/) || isDirectory(dir)(file);
  return fs.readdirSync(dir).filter(filter(dir)).map(function(file) {
    if (isDirectory(dir)(file)) {
      return {
        isFile: false,
        id: file,
        colors: walkSync(path.join(dir, file))
      };
    } else {
      return {
        isFile: true,
        id: file,
        style: getViewBoxDimensions(dir)(file)
      };
    }
  });
};

export const getFiles = () => {
  return walkSync('public/svg/');
};

import path from 'path';
import fs from 'fs';

const getViewBoxDimensions = dir => file => {
  const fileContent = fs.readFileSync(path.join(dir, file), 'utf-8');
  const matches = fileContent.match(/viewBox=\"(\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?) (\d+(?:\.\d+)?)\"/);
  if ( ! matches) return;
  return {
    width: parseFloat(matches[3]),
    height: parseFloat(matches[4])
  }
};

const walkSync = function(dir) {
  const isDirectory = dir => file => fs.statSync(path.join(dir, file)).isDirectory();
  const filter = dir => file => file.match(/\.svg$/) || isDirectory(dir)(file);
  return fs.readdirSync(dir).filter(filter(dir)).map(function(file) {
    if (isDirectory(dir)(file)) {
      return {
        isFile: false,
        id: file,
        colors: walkSync(path.join(dir, file))
      };
    } else {
      return {
        isFile: true,
        id: file,
        style: getViewBoxDimensions(dir)(file)
      };
    }
  });
};

export const getFiles = () => {
  return walkSync('public/svg/');
};

Update how we parse svg


/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const NativeModules = require('../BatchedBridge/NativeModules');
import type {TurboModule} from './RCTExport';
import invariant from 'invariant';

const turboModuleProxy = global.__turboModuleProxy;

export function get<T: TurboModule>(name: string): ?T {
  // Backward compatibility layer during migration.
  const legacyModule = NativeModules[name];
  if (legacyModule != null) {
    return ((legacyModule: any): T);
  }

  if (turboModuleProxy != null) {
    const module: ?T = turboModuleProxy(name);
    return module;
  }

  return null;
}

export function getEnforcing<T: TurboModule>(name: string): T {
  const module = get(name);
  invariant(
    module != null,
    `TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` +
      'Verify that a module by this name is registered in the native binary.',
  );
  return module;
}

/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 * @format
 */

'use strict';

const NativeModules = require('../BatchedBridge/NativeModules');
import type {TurboModule} from './RCTExport';
import invariant from 'invariant';

const turboModuleProxy = global.__turboModuleProxy;

export function get<T: TurboModule>(name: string): ?T {
  // Bridgeless mode requires TurboModules
  if (!global.RN$Bridgeless) {
    // Backward compatibility layer during migration.
    const legacyModule = NativeModules[name];
    if (legacyModule != null) {
      return ((legacyModule: any): T);
    }
  }

  if (turboModuleProxy != null) {
    const module: ?T = turboModuleProxy(name);
    return module;
  }

  return null;
}

export function getEnforcing<T: TurboModule>(name: string): T {
  const module = get(name);
  invariant(
    module != null,
    `TurboModuleRegistry.getEnforcing(...): '${name}' could not be found. ` +
      'Verify that a module by this name is registered in the native binary.',
  );
  return module;
}

Disable legacy native modules in bridgeless mode


const path = require('path');
module.exports = {
  entry: './build/index.js',
  devtool: 'source-map',
  mode: 'production',
  output: {
    path: path.resolve('./build/legacy'),
    filename: 'ol.js',
    library: 'ol',
    libraryTarget: 'umd',
    libraryExport: 'default',
  },
};

const path = require('path');
module.exports = {
  entry: './build/index.js',
  devtool: 'source-map',
  mode: 'production',
  resolve: {
    alias: {
      ol: path.resolve('./src/ol'),
    },
  },
  output: {
    path: path.resolve('./build/legacy'),
    filename: 'ol.js',
    library: 'ol',
    libraryTarget: 'umd',
    libraryExport: 'default',
  },
};

Fix legacy build by defining ol alias


var path 		= require('path');
var rootPath 	= path.normalize(__dirname + '/../../');

module.exports 	= {
    local: {
        baseUrl: 'http://localhost:3051',
        db: 'mongodb://localhost/rp_local',
        rootPath: rootPath,
        port: process.env.PORT || 3051
    },
    staging : {
        baseUrl: 'http://dev.resourceprojects.org',
        //db: '@aws-us-east-1-portal.14.dblayer.com:10669/rp_dev?ssl=true',
        db: '@aws-us-east-1-portal.14.dblayer.com:10669,aws-us-east-1-portal.13.dblayer.com:10499/rp_dev?ssl=true',
        rootPath: rootPath,
        port: process.env.PORT || 80
    }
};

var path 		= require('path');
var rootPath 	= path.normalize(__dirname + '/../../');

module.exports 	= {
    local: {
        baseUrl: 'http://localhost:3030',
        db: 'mongodb://localhost/rp_local',
        rootPath: rootPath,
        port: process.env.PORT || 3030
    },
    staging : {
        baseUrl: 'http://dev.resourceprojects.org',
        //db: '@aws-us-east-1-portal.14.dblayer.com:10669/rp_dev?ssl=true',
        db: '@aws-us-east-1-portal.14.dblayer.com:10669,aws-us-east-1-portal.13.dblayer.com:10499/rp_dev?ssl=true',
        rootPath: rootPath,
        port: process.env.PORT || 80
    }
};

Add to download links ng-csv


/**
 * RequireJS configuration
 * @description Pass in options for RequireJS like paths, shims or the baseUrl
 */
require.config({
	paths: {
		"mainModule" : "Modules/Main"
	},

	// Append a date on each requested script to prevent caching issues.
	urlArgs: "bust=" + Date.now()
});

/**
 * RequireJS calls
 * @description Require and fire off the main/initial file of the application.
 */
require(["mainModule"], function(MainFn) {
	"use strict";

	new MainFn();
});

/**
 * RequireJS configuration
 * @description Pass in options for RequireJS like paths, shims or the baseUrl
 */
require.config({
	shim: {},
	paths: {
		"mainModule" : "Modules/Main"
	},

	// Append a date on each requested script to prevent caching issues.
	urlArgs: "bust=" + Date.now()
});

/**
 * RequireJS calls
 * @description Require and fire off the main/initial file of the application.
 */
require(["mainModule"], function(MainFn) {
	"use strict";

	new MainFn();
});

Add an empty shim obj to the requireJS config


import React, { Component } from 'react';
import { Link } from "react-router-dom";

import './Home.css';

class Home extends Component {
  render() {
    return (

PICTOPHONE

          <Link to="/dashboard"><button className="login-button">Login</button></Link>

    );
  }
}

export default Home;

import React, { Component } from 'react';
import { Link } from "react-router-dom";
import { Button } from 'react-bootstrap';
import 'bootstrap/dist/css/bootstrap.css';
import './Home.css';

class Home extends Component {
  render() {
    return (

PICTOPHONE

          <Link to="/dashboard"><Button variant="info" size="lg">Login</Button></Link>

    );
  }
}

export default Home;

Replace button with Bootstrap button for better styling.


// Copyright © 2014 Intel Corporation. All rights reserved.
// Use  of this  source  code is  governed by  an Apache v2
// license that can be found in the LICENSE-APACHE-V2 file.

/**
 * Console output interface.
 * @constructor
 * @protected
 */
function ConsoleIface() {}

/**
 * Log error message.
 * @param {String} message
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.error =
function(message) {

    throw new Error("ConsoleIface.error() not implemented.");
};

/**
 * Log message.
 * @param {String} message
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.log =
function(message) {

    throw new Error("ConsoleIface.log() not implemented.");
};

/**
 * Output string without trailing newline.
 * @param {String} message
 * @param {Boolean|undefined} stderr Optional, whether to write on stderr, default is stdout.
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.put =
function(message, stderr) {

    throw new Error("ConsoleIface.put() not implemented.");
};

module.exports = ConsoleIface;

// Copyright © 2014 Intel Corporation. All rights reserved.
// Use  of this  source  code is  governed by  an Apache v2
// license that can be found in the LICENSE-APACHE-V2 file.

/**
 * Console output interface.
 * @constructor
 * @protected
 */
function ConsoleIface() {}

/**
 * Log error message.
 * @param {String} message
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.error =
function(message) {

    throw new Error("ConsoleIface.error() not implemented.");
};

/**
 * Log message.
 * @param {String} message
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.log =
function(message) {

    throw new Error("ConsoleIface.log() not implemented.");
};

/**
 * Output string without trailing newline.
 * @param {String} message
 * @param {Boolean} [toStderr] Optional, whether to write on stderr, default is stdout.
 * @memberOf ConsoleIface
 */
ConsoleIface.prototype.put =
function(message, toStderr) {

    throw new Error("ConsoleIface.put() not implemented.");
};

module.exports = ConsoleIface;

Use correct syntax for optional parameter in Console.put()


'use strict';

// MODULES //

var Readable = require( 'readable-stream' ).Readable;

// STREAM //

/**
* Readable stream.
*
* @private
* @constructor
* @returns {Stream} Stream instance
*/
function Stream() {
	if ( !(this instanceof Stream) ) {
		return new Stream();
	}
	Readable.call( this );
	this.isTTY = false;
	return this;
}

// Create a prototype which inherits from the parent prototype:
Stream.prototype = Object.create( Readable.prototype );

// Set the constructor:
Stream.prototype.constructor = Stream;

/**
* Implements the `_read` method.
*
* @private
*/
Stream.prototype._read = function _read() {
	// noop
}; // end METHOD _read()

// EXPORTS //

module.exports = Stream;

'use strict';

// MODULES //

var Readable = require( 'stream' ).Readable;

// STREAM //

/**
* Readable stream.
*
* @private
* @constructor
* @returns {Stream} Stream instance
*/
function Stream() {
	if ( !(this instanceof Stream) ) {
		return new Stream();
	}
	Readable.call( this );
	this.isTTY = false;
	return this;
}

// Create a prototype which inherits from the parent prototype:
Stream.prototype = Object.create( Readable.prototype );

// Set the constructor:
Stream.prototype.constructor = Stream;

/**
* Implements the `_read` method.
*
* @private
*/
Stream.prototype._read = function _read() {
	// noop
}; // end METHOD _read()

// EXPORTS //

module.exports = Stream;

Use the built-in stream module


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

// MAIN //

/**
* Resets the window scroll position to the top of the page.
*
* @private
*/
function resetScroll() {
	window.scrollTo( 0, 0 );
}

// EXPORTS //

export default resetScroll;

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

// MAIN //

/**
* Resets the window scroll position to the top of the page.
*
* @private
*/
function resetScroll() {
	if ( typeof window !== 'undefined' ) {
		window.scrollTo( 0, 0 );
	}
}

// EXPORTS //

export default resetScroll;

Add `window` check for when running server


(function($) {

  /**
   * Downloads data and uses it to dynamically create set of select options.
   * url          - URL used to dynamically obtain select options (using $.ajax).
   * formatResult - function that accepts data and returns an array of objects,
   *                where each object has two attributes: 'val' and 'text', e.g.:
   *                [{val: 'val1', text: 'First option'}, {val: 'val2', 'text': 'Second option'}]
   * callback     - optional function that will be called when AJAX request is completed.
   */
  $.fn.getSelectOptions = function (url, formatResult, callback) {
    $.ajax({
      type: 'get',
      url: url,
      xhrFields: {
        withCredentials: true
      },
      contentType: 'application/json'
    }).done(success.bind(this));

    function success (data) {
      var options = formatResult(data);

      this.filter('select').each(function() {
        var $select = $(this);
        $select.empty();
        options.forEach(function (opt) {
          $select.append($('<option>').attr('value', opt.val).text(opt.text));
        });
        $select.trigger('change');
      });

      if (typeof callback === 'function') {
        callback.bind(this)();
      }
    }

    return this;
  };

}(jQuery));

(function($) {

  /**
   * Downloads data and uses it to dynamically create set of select options.
   * url          - URL used to dynamically obtain select options (using $.ajax).
   * formatResult - function that accepts data and returns an array of objects,
   *                where each object has two attributes: 'val' and 'text', e.g.:
   *                [{val: 'val1', text: 'First option'}, {val: 'val2', 'text': 'Second option'}]
   * callback     - optional function that will be called when AJAX request is completed.
   */
  $.fn.getSelectOptions = function (url, formatResult, callback) {
    var selectElements = this.filter('select');
    // Make sure we don't send AJAX request when there are no target elements available.
    if (selectElements.length < 1) return;

    $.ajax({
      type: 'get',
      url: url,
      xhrFields: {
        withCredentials: true
      },
      contentType: 'application/json'
    }).done(success.bind(this));

    function success (data) {
      var options = formatResult(data);

      selectElements.each(function() {
        var $select = $(this);
        $select.empty();
        options.forEach(function (opt) {
          $select.append($('<option>').attr('value', opt.val).text(opt.text));
        });
        $select.trigger('change');
      });

      if (typeof callback === 'function') {
        callback.bind(this)();
      }
    }

    return this;
  };

}(jQuery));

Fix / optimize ajax form plugin