// Dependencies
var express = require('express');
var methodOverride = require('method-override');
var bodyParser = require('body-parser');
var exphbs = require("express-handlebars");

// Sets up the Express App
var app = express();
var PORT = process.env.PORT || 8080;

// Models to sync
var db = require("./models");

app.use(bodyParser.urlencoded({ extended: false }));
app.use(methodOverride("_method"));
app.engine("handlebars", exphbs({ defaultLayout: "main" }));
app.set("view engine", "handlebars");

// Serve files in 'public' directory
app.use(express.static('public'));

// Load routes
app.use(require('./controllers/guest_controller'));
app.use(require('./controllers/manager_controller'));
app.use(require('./controllers/restaurant_controller'));
app.use(require('./controllers/room_controller'));
app.use(require('./controllers/table_controller'));

// Sync models then start the server to begin listening
db.sequelize.sync().then(function() {
  app.listen(PORT, function() {
    console.log("App listening on PORT " + PORT);
  });
});

// Dependencies
var express = require('express');
var methodOverride = require('method-override');
var bodyParser = require('body-parser');
var exphbs = require("express-handlebars");

// Sets up the Express App
var app = express();
var PORT = process.env.PORT || 8080;

// Models to sync
var db = require("./models");

app.use(bodyParser.urlencoded({ extended: false }));
app.use(methodOverride("_method"));
app.engine("handlebars", exphbs({ defaultLayout: "main" }));
app.set("view engine", "handlebars");

// Serve files in 'public' directory
app.use(express.static('public'));

// Load routes
app.get('/', function(req, res) {
  res.render('index');
});
app.use(require('./controllers/guest_controller'));
app.use(require('./controllers/manager_controller'));
app.use(require('./controllers/restaurant_controller'));
app.use(require('./controllers/room_controller'));
app.use(require('./controllers/table_controller'));

// Sync models then start the server to begin listening
db.sequelize.sync().then(function() {
  app.listen(PORT, function() {
    console.log("App listening on PORT " + PORT);
  });
});

Add get route for /


var path = require('path');
var spawn = require('child_process').spawn;

exports.TGZ = '.tar.gz';
exports.ZIP = '.zip';

function extract(type, archivePath, destDir, cb) {
  var child;
  switch(type) {
    case exports.TGZ:
      child = spawn('tar', ['-xzf', archivePath, '-C', destDir]);
      break;
    case exports.ZIP:
      var subDir = path.basename(archivePath, type);
      destDir = path.join(destDir, subDir);
      child = spawn('unzip', [archivePath, '-d', destDir]);
      break;
    default:
      return cb(new Error('Invalid archive type !'));
  }
  process.stdin.pipe(child.stdin);
  child.stdout.pipe(process.stdout, {end: true});
  child.stderr.pipe(process.stderr, {end: true});
  child.once('close', function(code) {
    if(code !== 0) {
      return cb(new Error('Error while extracting !'));
    }
    return cb(null, archivePath);
  });
}

exports.zip = extract.bind(null, exports.ZIP);
exports.tgz = extract.bind(null, exports.TGZ);

var path = require('path');
var spawn = require('child_process').spawn;

exports.TGZ = '.tar.gz';
exports.ZIP = '.zip';

function extract(type, archivePath, destDir, cb) {
  var child;
  switch(type) {
    case exports.TGZ:
      child = spawn('tar', ['-xzf', archivePath, '-C', destDir]);
      break;
    case exports.ZIP:
      child = spawn('unzip', [archivePath, '-d', destDir]);
      break;
    default:
      return cb(new Error('Invalid archive type !'));
  }
  process.stdin.pipe(child.stdin);
  child.stdout.pipe(process.stdout, {end: true});
  child.stderr.pipe(process.stderr, {end: true});
  child.once('close', function(code) {
    if(code !== 0) {
      return cb(new Error('Error while extracting !'));
    }
    return cb(null, archivePath);
  });
}

exports.zip = extract.bind(null, exports.ZIP);
exports.tgz = extract.bind(null, exports.TGZ);

Fix bugs with unzip command


const getConsumerById = (id, consumers) => consumers.find(x => x._info.id === id) || {};

export default state => {
    const fixPluginAnonymous = ({ name, attributes: { config, ...attributes }, ...plugin }) => {
        if (config && config.anonymous) {
            const { anonymous, ...restOfConfig } = config;
            const { username } = getConsumerById(anonymous, state.consumers);

            return { name, attributes: { ...attributes, config: { anonymous_username: username, ...restOfConfig } }, ...plugin };
        }

        return { name, attributes: { ...attributes, config }, ...plugin };
    }

    const fixPluginUsername = ({ name, attributes: { consumer_id, ...attributes }, ...plugin }) => {
        const { username } = getConsumerById(consumer_id, state.consumers);

        return { name, attributes: { username, ...attributes }, ...plugin };
    };

    const fixApiPluginUsername = api => ({
        ...api,
        plugins: (api.plugins || []).map(fixPluginUsername).map(fixPluginAnonymous),
    });

    return {
        ...state,
        apis: state.apis && state.apis.map(fixApiPluginUsername),
        plugins: state.plugins && state.plugins.map(fixPluginUsername),
    };
};

import invariant from 'invariant';

const getConsumerById = (id, consumers) => {
    const consumer = consumers.find(x => x._info.id === id);

    invariant(consumer, `Unable to find a consumer for ${id}`);

    return consumer;
};

export default state => {
    const fixPluginAnonymous = ({ name, attributes: { config, ...attributes }, ...plugin }) => {
        if (config && config.anonymous) {
            const { anonymous, ...restOfConfig } = config;
            const { username } = getConsumerById(anonymous, state.consumers);

            return { name, attributes: { ...attributes, config: { anonymous_username: username, ...restOfConfig } }, ...plugin };
        }

        return { name, attributes: { ...attributes, config }, ...plugin };
    }

    const fixPluginUsername = ({ name, attributes: { consumer_id, ...attributes }, ...plugin }) => {
        if (!consumer_id) {
            return { name, attributes, ...plugin };
        }

        const { username } = getConsumerById(consumer_id, state.consumers);

        return { name, attributes: { username, ...attributes }, ...plugin };
    };

    const fixApiPluginUsername = api => ({
        ...api,
        plugins: (api.plugins || []).map(fixPluginUsername).map(fixPluginAnonymous),
    });

    return {
        ...state,
        apis: state.apis && state.apis.map(fixApiPluginUsername),
        plugins: state.plugins && state.plugins.map(fixPluginUsername),
    };
};

Change state selector to omit username when no customer is associated


import Ember from 'ember';
import layout from '../templates/components/uni-horizontal-tabs';

const { Component, computed, isEmpty, observer } = Ember;

export default Component.extend({
  layout,
  classNames: ['uni-horizontal-tabs'],

  options: [],
  currentTab: 0,

  /**
   * @public
   * @param {Option} option The option data provided to the component
   *
   * This method can be redefined if you need to create a custom title
   */
  toTitle(option) {
    return option;
  },

  onOptionsChanged: observer('options.[]', function() {
    this.set('currentTab', Math.min(this.get('currentTab'), this.get('options.length') - 1));
  }),

  optionSelected: computed('options.[]', 'currentTab', function() {
    if (isEmpty(this.get('options'))) {
      return;
    }

    return this.get('options')[this.get('currentTab')];
  }),
  titles: computed('options.@each.title', function() {
    return this.get('options').map(this.toTitle);
  }),

  actions: {
    setTab(index) {
      this.set('currentTab', index);
    }
  }
});

import Ember from 'ember';
import layout from '../templates/components/uni-horizontal-tabs';

const { Component, computed, isEmpty, observer } = Ember;

export default Component.extend({
  layout,
  classNames: ['uni-horizontal-tabs'],

  options: [],
  currentTab: 0,

  /**
   * @public
   * @param {Option} option The option data provided to the component
   *
   * This method can be redefined if you need to create a custom title
   */
  toTitle(option) {
    return option;
  },

  onOptionsChanged: observer('options.[]', function() {
    this.set('currentTab', Math.min(this.get('currentTab'), this.get('options.length') - 1));
  }),

  optionSelected: computed('options.[]', 'currentTab', function() {
    if (isEmpty(this.get('options'))) {
      return;
    }

    return this.get('options')[this.get('currentTab')];
  }),
  titles: computed('options.@each.title', function() {
    return this.get('options').map(this.get('toTitle'));
  }),

  actions: {
    setTab(index) {
      this.set('currentTab', index);
    }
  }
});

Fix in toTitle to allow heroku deploy


var feature_flags = (function () {

var exports = {};

exports.mark_read_at_bottom = true;
exports.summarize_read_while_narrowed = true;

exports.twenty_four_hour_time = _.contains([],
                                  page_params.email);
exports.dropbox_integration = page_params.staging || _.contains(['dropbox.com'], page_params.domain);

exports.mandatory_topics = _.contains([
    'customer7.invalid'
    ],
    page_params.domain
);

exports.collapsible = page_params.staging;

exports.propagate_topic_edits = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

exports.fade_users_when_composing = page_params.staging;

exports.alert_words =
  _.contains(['reddit.com', 'mit.edu', 'zulip.com'], page_params.domain);

var zulip_mit_emails = [];

var is_zulip_mit_user = _.contains(zulip_mit_emails, page_params.email);

exports.muting = page_params.staging || is_zulip_mit_user;

exports.left_side_userlist = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

return exports;

}());

var feature_flags = (function () {

var exports = {};

exports.mark_read_at_bottom = true;
exports.summarize_read_while_narrowed = true;

exports.twenty_four_hour_time = _.contains([],
                                  page_params.email);
exports.dropbox_integration = page_params.staging || _.contains(['dropbox.com'], page_params.domain);

exports.mandatory_topics = _.contains([
    'customer7.invalid'
    ],
    page_params.domain
);

exports.collapsible = page_params.staging;

exports.propagate_topic_edits = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

var customer4_realms = [
  'customer4.invalid',
  'users.customer4.invalid'
];
var is_customer4 = _.contains(customer4_realms, page_params.domain);

exports.fade_users_when_composing = page_params.staging || is_customer4;

exports.alert_words =
  _.contains(['reddit.com', 'mit.edu', 'zulip.com'], page_params.domain);

var zulip_mit_emails = [];

var is_zulip_mit_user = _.contains(zulip_mit_emails, page_params.email);

exports.muting = page_params.staging || is_zulip_mit_user;

exports.left_side_userlist = page_params.staging ||
  _.contains(['customer7.invalid'], page_params.domain);

return exports;

}());

Enable compose fading for CUSTOMER4.


import Ember from 'ember';

let getCompendiums = function() {
  let ajaxSettings = {
    url: 'daily-riderships',
    queryData: {sparkline: true}
  }
  return Ember.$.ajax(ajaxSettings).done(function(data) {
    return data;
  })
}

export default Ember.Route.extend({
  model(){
    return Ember.RSVP.hash({
      systemTrends: this.store.peekAll('system-trend'),
      compendiums: getCompendiums()
    })
  }
});

import Ember from 'ember';

let getCompendiums = function() {
  let ajaxSettings = {
    url: 'daily-riderships',
    data: {sparkline: true}
  }
  return Ember.$.ajax(ajaxSettings).done(function(data) {
    return data;
  })
}

export default Ember.Route.extend({
  model(){
    return Ember.RSVP.hash({
      systemTrends: this.store.peekAll('system-trend'),
      compendiums: getCompendiums()
    })
  }
});

Fix jQuery AJAX query string setting.


import React from 'react';

class PostActions extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    return (
      <div className="post-actions">
      </div>
    );
  }
}

PostActions.propTypes = {
  post: React.PropTypes.object.isRequired,
};

export default PostActions;

import React from 'react';

class PostActions extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    return (

            <button type="button" className="post-stat active-hover">
              16 likes
            </button>
            <button type="button" className="post-stat active-hover">
              5 comments
            </button>

            <button type="button" className="post-action icon icon-heart">
              Like
            </button>
            <button type="button" className="post-action icon icon-comment">
              Comment
            </button>

    );
  }
}

PostActions.propTypes = {
  post: React.PropTypes.object.isRequired,
};

export default PostActions;

Write placeholder HTML for post actions component


// a default configuration that is used by the rtc package
module.exports = {
  // simple constraints for defaults
  constraints: {
    video: true,
    audio: true
  },

  // use the public switchboard for signalling
  signaller: 'https://switchboard.rtc.io/',

  // no room is defined by default
  // rtc-quickconnect will autogenerate using a location.hash
  room: undefined,

  // specify ice servers or a generator function to create ice servers
  ice: [],

  // any data channels that we want to create for the conference
  // by default a chat channel is created, but other channels can be added also
  // additionally options can be supplied to customize the data channel config
  // see: <http://w3c.github.io/webrtc-pc/#idl-def-RTCDataChannelInit>
  channels: {},

  // the selector that will be used to identify the localvideo container
  localContainer: '#l-video',

  // the selector that will be used to identify the remotevideo container
  remoteContainer: '#r-video',

  // should we atempt to load any plugins?
  plugins: [],

  // common options overrides that are used across rtc.io packages
  options: {}
};

// a default configuration that is used by the rtc package
module.exports = {
  // simple constraints for defaults
  constraints: {
    video: true,
    audio: true
  },

  // use the public development switchboard for signalling
  signaller: 'https://switchboard.rtc.io/',

  // no room is defined by default
  // rtc-quickconnect will autogenerate using a location.hash
  room: undefined,

  // specify ice servers or a generator function to create ice servers
  ice: [],

  // any data channels that we want to create for the conference
  // by default a chat channel is created, but other channels can be added also
  // additionally options can be supplied to customize the data channel config
  // see: <http://w3c.github.io/webrtc-pc/#idl-def-RTCDataChannelInit>
  channels: {},

  // the selector that will be used to identify the localvideo container
  localContainer: '#l-video',

  // the selector that will be used to identify the remotevideo container
  remoteContainer: '#r-video',

  // should we atempt to load any plugins?
  plugins: [],

  // common options overrides that are used across rtc.io packages
  options: {}
};

Include "development switchboard" comment to flag that switchboard.rtc.io should not be used for production apps


import test from 'ava';
import inView from '../src/in-view';
import { inViewport } from '../src/viewport';

test('inView.is is a proxy for inViewport', t => {
    t.deepEqual(inView.is, inViewport);
});

import test from 'ava';
import inView from '../src/in-view';
import { inViewport } from '../src/viewport';

const stub = {
    getBoundingClientRect() {
        return {
            top: 50,
            right: 50,
            bottom: 50,
            left: 50
        };
    }
};

test('inView.is returns a boolean', t => {
    t.true(typeof inView.is(stub) === 'boolean');
    t.true(inView.is(stub));
});

Update inView.is test to ensure boolean


import ko from "knockout";
import sortBy from "lodash/collection/sortBy";

import api from "../api";
import formatter from "../ko/formatter";
import store from "../store";

export default class Document {
  constructor(data) {
    Object.assign(this, data);

    // replace stub (id-only) objects
    this.lectures = sortBy(data.lectures.map(l => store.lecturesById.get(l.id)), 'name');
    this.examinants = sortBy(data.examinants.map(e => store.examinantsById.get(e.id)), 'name');

    this.date = new Date(data.date);
    this.validation_time = data.validation_time ? new Date(data.validation_time) : null;

    // retain some consistency
    this.numberOfPages = this.number_of_pages;
    this.documentType = this.document_type;
    this.validationTime = this.validation_time;

    ko.track(this, ['validated']);
  }

  get extendedAttributes() {
    return formatter.formatDate(this.date) + ', ' + this.comment;
  }

  get examinantsText() {
    return this.examinants.map(e => e.name).join(', ');
  }

  get previewURL() { return `${api.baseUrl}view/${this.id}`; }
  get PDFjsURL() { return `/pdfjs/web/viewer.html?file=${encodeURIComponent(this.previewURL)}`; }
  get editURL() { return `${api.baseUrl}../admin/document/edit/?id=${this.id}`; }
  get store() { return store; }
}

import ko from "knockout";
import sortBy from "lodash/collection/sortBy";

import api from "../api";
import formatter from "../ko/formatter";
import store from "../store";

export default class Document {
  constructor(data) {
    Object.assign(this, data);

    // replace stub (id-only) objects
    this.lectures = sortBy(data.lectures.map(l => store.lecturesById.get(l.id)), 'name');
    this.examinants = sortBy(data.examinants.map(e => store.examinantsById.get(e.id)), 'name');

    this.date = new Date(data.date);
    this.validation_time = data.validation_time ? new Date(data.validation_time) : null;

    // retain some consistency
    this.numberOfPages = this.number_of_pages;
    this.documentType = this.document_type;
    this.validationTime = this.validation_time;

    ko.track(this, ['validated']);
  }

  get extendedAttributes() {
    return formatter.formatDate(this.date) + ', ' + this.comment;
  }

  get examinantsText() {
    return this.examinants.map(e => e.name).join(', ');
  }

  get previewURL() { return `${api.baseUrl}view/${this.id}`; }
  get PDFjsURL() { return `pdfjs/web/viewer.html?file=${encodeURIComponent(this.previewURL)}`; }
  get editURL() { return `${api.baseUrl}../admin/document/edit/?id=${this.id}`; }
  get store() { return store; }
}

Fix PDFjs links in kiosk mode


module.exports = {
  stylePrefix: 'cv-',

  /*
   * Append external scripts to the `<head>` of the iframe.
   * Be aware that these scripts will not be printed in the export code
   * @example
   * scripts: [ 'https://...1.js', 'https://...2.js' ]
  */
  scripts: [],

  /*
   * Append external styles to the `<head>` of the iframe
   * Be aware that these styles will not be printed in the export code
   * @example
   * styles: [ 'https://...1.css', 'https://...2.css' ]
  */
  styles: [],

  /**
   * Add custom badge naming strategy
   * @example
   * customBadgeLabel: function(component) {
   *  return component.getName();
   * }
   */
  customBadgeLabel: '',

  /**
   * Indicate when to start the auto scroll of the canvas on component/block dragging (value in px )
   */
  autoscrollLimit: 50,

  /**
   * When some textable component is selected and focused (eg. input or text component) the editor
   * stops some commands (eg. disables the copy/paste of components with CTRL+C/V to allow the copy/paste of the text).
   * This option allows to customize, by a selector, which element should not be considered textable
   */
  notTextable: ['button', 'input[type=checkbox]', 'input[type=radio]']
};

module.exports = {
  stylePrefix: 'cv-',

  /*
   * Append external scripts to the `<head>` of the iframe.
   * Be aware that these scripts will not be printed in the export code
   * @example
   * scripts: [ 'https://...1.js', 'https://...2.js' ]
   */
  scripts: [],

  /*
   * Append external styles to the `<head>` of the iframe
   * Be aware that these styles will not be printed in the export code
   * @example
   * styles: [ 'https://...1.css', 'https://...2.css' ]
   */
  styles: [],

  /**
   * Add custom badge naming strategy
   * @example
   * customBadgeLabel: function(component) {
   *  return component.getName();
   * }
   */
  customBadgeLabel: '',

  /**
   * Indicate when to start the auto scroll of the canvas on component/block dragging (value in px )
   */
  autoscrollLimit: 50,

  /**
   * When some textable component is selected and focused (eg. input or text component) the editor
   * stops some commands (eg. disables the copy/paste of components with CTRL+C/V to allow the copy/paste of the text).
   * This option allows to customize, by a selector, which element should not be considered textable
   */
  notTextable: ['button', 'a', 'input[type=checkbox]', 'input[type=radio]']
};

Add `a` to notTextable option in Canvas


import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      todos: [
        'Learn React',
        'Do Laundry'
      ]
    };
  }
  render() {
    return (

Welcome to My TODO List

          {this.state.todos.map((todo, index) =>
{todo}
)}

    );
  }
}

export default App;

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      todos: [],
      todoToAdd: ""
    };

    // This binding is necessary to make 'this' work in the callback
    this.handleChange = this.handleChange.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  handleChange(event) {
    const nextTodoAdd = event.target.value;

    this.setState({
      todoToAdd: nextTodoAdd
    });
  }

  handleClick(event) {
    const nextTodos = this.state.todos.concat(this.state.todoToAdd);
    const nextTodoToAdd = '';

    this.setState({
      todos: nextTodos,
      todoToAdd: nextTodoToAdd
    });
  }

  render() {
    return (

Welcome to My TODO List

          {this.state.todos.map((todo, index) =>
{todo}
)}

        <input type="text"
         placeholder="New TODO"
         value={this.state.todoToAdd}
         onChange={this.handleChange}
         />
         <button onClick={this.handleClick}>Add TODO</button>

    );
  }
}

export default App;

Add text box tracking and TODO items


import 'ui-router-extras';
import futureRoutes from 'app/routes.json!';

var routing = function(module) {

  module.requires.push('ct.ui.router.extras.future');

  var RouterConfig = ['$stateProvider', '$futureStateProvider', function ($stateProvider, $futureStateProvider) {

    $futureStateProvider.stateFactory('load', ['$q', '$ocLazyLoad', 'futureState', function($q, $ocLazyLoad, futureState) {
      var def = $q.defer();

      System.import(futureState.src).then(loaded => {
        var newModule = loaded;
        if (!loaded.name) {
          var key = Object.keys(loaded);
          newModule = loaded[key[0]];
        }

        $ocLazyLoad.load(newModule).then(function() {
          def.resolve();
        }, function() {
          console.log('error loading: ' + loaded.name);
        });
      });

      return def.promise;
    }]);

    futureRoutes.forEach(function(r) {
      $futureStateProvider.futureState(r);
    });

  }];

  return RouterConfig;
};

export default routing;

import 'ui-router-extras';
import futureRoutes from 'app/routes.json!';

var routing = function(module) {

  module.requires.push('ct.ui.router.extras.future');

  var RouterConfig = ['$stateProvider', '$futureStateProvider', function ($stateProvider, $futureStateProvider) {

    $futureStateProvider.stateFactory('load', ['$q', '$ocLazyLoad', 'futureState', function($q, $ocLazyLoad, futureState) {
      var def = $q.defer();

      System.import(futureState.src).then(loaded => {
        var newModule = loaded;
        if (!loaded.name) {
          var key = Object.keys(loaded);
          newModule = loaded[key[1]];
        }

        $ocLazyLoad.load(newModule).then(function() {
          def.resolve();
        }, function() {
          console.log('error loading: ' + loaded.name);
        });
      });

      return def.promise;
    }]);

    futureRoutes.forEach(function(r) {
      $futureStateProvider.futureState(r);
    });

  }];

  return RouterConfig;
};

export default routing;

FIX : ignore __esModule key


"use strict";

const path = require("path");
const { SourceMapConsumer } = require("source-map");

const UNKNOWN_SOURCE = "\u0000unknown";

const getBytesPerFileUsingSourceMap = (bundleId, code, map, dir) => {
  const modules = Object.create(null);

  let line = 1;
  let column = 0;
  for (let i = 0; i < code.length; i++, column++) {
    const { source } = map.originalPositionFor({
      line,
      column,
    });
    const id =
      source == null
        ? `${UNKNOWN_SOURCE}-${bundleId}`
        : path.resolve(path.dirname(path.join(dir, bundleId)), source);

    modules[id] = modules[id] || { renderedLength: 0 };
    modules[id].renderedLength += 1;

    if (code[i] === "\n") {
      line += 1;
      column = -1;
    }
  }

  return modules;
};

const getSourcemapModules = (id, { map, code }, dir) => {
  return SourceMapConsumer.with(map, null, (map) => {
    return getBytesPerFileUsingSourceMap(id, code, map, dir);
  });
};

module.exports = getSourcemapModules;

"use strict";

const path = require("path");
const { SourceMapConsumer } = require("source-map");

const getBytesPerFileUsingSourceMap = (bundleId, code, map, dir) => {
  const modules = Object.create(null);

  let line = 1;
  let column = 0;
  for (let i = 0; i < code.length; i++, column++) {
    const { source } = map.originalPositionFor({
      line,
      column,
    });
    if (source != null) {
      const id = path.resolve(path.dirname(path.join(dir, bundleId)), source);

      modules[id] = modules[id] || { renderedLength: 0 };
      modules[id].renderedLength += 1;
    }

    if (code[i] === "\n") {
      line += 1;
      column = -1;
    }
  }

  return modules;
};

const getSourcemapModules = (id, { map, code }, dir) => {
  return SourceMapConsumer.with(map, null, (map) => {
    return getBytesPerFileUsingSourceMap(id, code, map, dir);
  });
};

module.exports = getSourcemapModules;

Remove unknown sources from SM


const chokidar = require('chokidar');
const webpack = require('webpack');

const pkg = require('../package.json');
const webpackErrorHandler = require('./webpack-errorhandler');

module.exports = config => {
  let watcher;

  const watch = changedPath => {
    if(watcher && changedPath) {
      // stop the old watcher
      console.log('Restarting webpack watch due to change webpack will not see...')
      console.log(changedPath);
      watcher.close();
    }

    // start the new watcher
    watcher = webpack(config, (err, stats) => {
      // note we're passing it a fake callback because we don't want watch to terminate on error :)
      webpackErrorHandler(err, stats, { noexit: true }, function() {});
    });
  }

  // enable watch mode on all webpack configs
  config.forEach((b, i) => {
    b.watch = true;
  });

  chokidar.watch(pkg.directories.source, { ignoreInitial: true })
    .on('ready', watch)
    .on('addDir', watch)
    .on('unlinkDir', watch)
    .on('error', error => console.error('Webpack watch had an error: ', error));
};

const chokidar = require('chokidar');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');

const pkg = require('../package.json');

const host = 'localhost';
const port = 8080;
let server;

module.exports = config => {

  const watch = (changedPath) => {
    if(server && changedPath) {
      // stop the old dev server
      console.log('Restarting webpack watch due to change webpack will not see...')
      console.log(changedPath);
      server.close();
    }

    // start the new dev server

    // want to try for HMR on the configs?
    // See http://andrewhfarmer.com/webpack-hmr-tutorial/
    // and https://github.com/ahfarmer/webpack-hmr-starter-dev-server-api
    // but didn't work for me. Got errors about window not being defined
    // after registering the HMR entry points, and the page markup was not updating

    var compiler = webpack(config);

    // see https://webpack.github.io/docs/webpack-dev-server.html#api for dev-server API options
    server = new WebpackDevServer(compiler, {
      contentBase: pkg.directories.output,
      filename: "bundle.js",
      publicPath: "/",
      hot: false,
      stats: {
        colors: true,
        chunks: false,
        hash: false,
        timings: false,
        version: false
      }
    });

    server.listen(port, host, () => { console.log(`webpack-dev-server is now listening on http://${host}:${port}`); });
  }

  chokidar.watch(pkg.directories.source, { ignoreInitial: true })
    .on('ready', watch)
    .on('addDir', watch)
    .on('unlinkDir', watch)
    .on('error', error => console.error('webpack-dev-server had an error: ', error));
};

Change watch to webpack-dev-server, with the kill-and-reload methodology already present


import React, { Component } from 'react';
import { reduxForm } from 'redux-form';

class PostsNew extends Component {
  render() {
    return(

Create Form

    );
  }
}

export default reduxForm({
  form: 'PostNew',
  fields:['title', 'category', 'content']
})(PostsNew);

import React, { Component } from 'react';
import { reduxForm } from 'redux-form';

class PostsNew extends Component {
  render() {
    return(
      <form>

Create a New Post

          Title
          <input type="text" className="form-control" />

          Categories
          <input type="text" className="form-control" />

          Content
          <textarea className="form-control" />

        <button type="submit" className="btn btn-primary">Submit</button>
      </form>
    );
  }
}

export default reduxForm({
  form: 'PostNew',
  fields:['title', 'category', 'content']
})(PostsNew);

/// Whenever a user types something in.... record it on app state.

Set up the form content in post_new comp.


/// <reference path="../Services/VoteService.js" />
'use strict';

(function () {
    angular
        .module('GVA.Voting')
        .controller('AddVoterOptionDialogController', AddVoterOptionDialogController);

    AddVoterOptionDialogController.$inject = ['$scope', 'VoteService'];

    function AddVoterOptionDialogController($scope, VoteService) {

        $scope.multipleAddingAllowed = false;

        $scope.addOption = addOption;
        $scope.addOptionAndClose = addOptionAndClose;

        function addOption(form) {
            add(form);
            dismiss();
        }

        function add(form) {
            if (form.name === null) {
                return;
            }

            var newVoterOption = {
                Name: form.name,
                Description: form.description
            };

            $scope.options.push(newVoterOption);

            VoteService.addVoterOption($scope.ngDialogData.pollId, newVoterOption)
                .then($scope.notifyOptionAdded());
        }

        function addOptionAndClose(form) {
            add(form);
            dismiss();
        }

        function dismiss() {
            $scope.closeThisDialog();
        }
    }
})();

/// <reference path="../Services/VoteService.js" />
'use strict';

(function () {
    angular
        .module('GVA.Voting')
        .controller('AddVoterOptionDialogController', AddVoterOptionDialogController);

    AddVoterOptionDialogController.$inject = ['$scope', 'VoteService'];

    function AddVoterOptionDialogController($scope, VoteService) {

        $scope.multipleAddingAllowed = false;

        $scope.addOption = addOption;
        $scope.addOptionAndClose = addOptionAndClose;

        function addOption(form) {
            add(form);
            dismiss();
        }

        function add(form) {
            if (form.name === null) {
                return;
            }

            var newVoterOption = {
                Name: form.name,
                Description: form.description
            };

            $scope.options.push(newVoterOption);

            VoteService.addVoterOption($scope.ngDialogData.pollId, newVoterOption)
                .then($scope.notifyOptionAdded);
        }

        function addOptionAndClose(form) {
            add(form);
            dismiss();
        }

        function dismiss() {
            $scope.closeThisDialog();
        }
    }
})();

Fix the reload when adding and option


// Defining Module
var demoApp = angular.module('demoApp', ['ngRoute']);

// Defining Module Routes
demoApp.config(function($routeProvider) {
    $routeProvider
        .when('/view1', {
            controller: 'simpleController',
            templateUrl: 'partials/view1.html'
        })
        .when('/view2', {
            controller: 'simpleController',
            templateUrl: 'partials/view2.html'
        })
        .otherwise({
            redirectTo: '/view1'
        });
});

// Defining Controller
demoApp.controller('simpleController', function($scope) {
    $scope.customers = [{
        name: 'Dave Jones',
        city: 'Phoenix'
    }, {
        name: 'Jamie Riley',
        city: 'Atlanta'
    }, {
        name: 'Heedy Wahlin',
        city: 'Chandler'
    }, {
        name: 'Thomas Wahlin',
        city: 'Seattle'
    }];

});

// Defining addCustomer for Adding New Customers
$scope.addCustomer = function() {
    $scope.customer.push({
        name: $scope.newCustomer.name,
        city: $scope.newCustomer.city
    });
};

// Defining Module
var demoApp = angular.module('demoApp', ['ngRoute']);

// Defining Module Routes
demoApp.config(function($routeProvider) {
    $routeProvider
        .when('/view1', {
            controller: 'simpleController',
            templateUrl: 'partials/view1.html'
        })
        .when('/view2', {
            controller: 'simpleController',
            templateUrl: 'partials/view2.html'
        })
        .otherwise({
            redirectTo: '/view1'
        });
});

// Defining Controller
demoApp.controller('simpleController', function($scope) {
    $scope.customers = [{
        name: 'Dave Jones',
        city: 'Phoenix'
    }, {
        name: 'Jamie Riley',
        city: 'Atlanta'
    }, {
        name: 'Heedy Wahlin',
        city: 'Chandler'
    }, {
        name: 'Thomas Wahlin',
        city: 'Seattle'
    }];
    // Defining addCustomer for Adding New Customers
    $scope.addCustomer = function() {
        $scope.customers.push({
            name: $scope.newCustomer.name,
            city: $scope.newCustomer.city
        });
    };

});

Put function in scope & corect object usage


import React from 'react';
import {FontIcon, Styles} from 'material-ui';
import Radium from 'radium';

let ThemeManager = new Styles.ThemeManager();

let styles = {
  page: {
    display: 'flex',
    flexDirection: 'column',
  },
  commandLine: {
    flex: '1'
  }
};

@Radium
export default class PageLayout extends React.Component {
  render() {
    let [editView, commandLine, messages] = this.props.children;

    return

{editView}

{commandLine}

{messages}

;
  }

  getChildContext() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  }

}

PageLayout.childContextTypes = {
  muiTheme: React.PropTypes.object
};

import React from 'react';
import {FontIcon, Styles} from 'material-ui';
import Radium from 'radium';

let ThemeManager = new Styles.ThemeManager();

let styles = {
  page: {},
  editView: {
    padding: '10px 10px 100px 10px'
  },
};

@Radium
export default class PageLayout extends React.Component {
  render() {
    let [ editView, commandLine, messages ] = this.props.children;

    return

{editView}

{commandLine}

{messages}

;
  }
}

Add padding around entire page.


module.exports = {
  // messenger events
  dataEvent: 'data',
  openEvent: 'open',
  closeEvent: 'close',

  // messenger functions
  writeMethod: 'write',
  closeMethod: 'close',

  // leave timeout (ms)
  leaveTimeout: 3000
};

module.exports = {
  // messenger events
  dataEvent: 'data',
  openEvent: 'open',
  closeEvent: 'close',
  errorEvent: 'error',

  // messenger functions
  writeMethod: 'write',
  closeMethod: 'close',

  // leave timeout (ms)
  leaveTimeout: 3000
};

Set a default for the error event


define([
  'text!snippet-collapsible',
  'text!snippet-ticks',
  'text!snippet-callout',
  'text!snippet-add-action',
  'text!snippet-video',
  'text!snippet-action-item'
], function (
    collapsibleSnippet,
    ticksSnippet,
    calloutSnippet,
    addActionSnippet,
    videoSnippet,
    actionItemSnippet
  ) {
  'use strict';
  /**
   * This plugin adds each mastalk md snippet
   */
  return function (type) {
    return function (scribe) {
      var commandName = "mastalk_" + type;
      var mastalkCommand = new scribe.api.Command('insertHTML');

      mastalkCommand.execute = function () {
        scribe.insertPlainText(this.getType()[type].trim());
      };

      mastalkCommand.getType = function () {
        return {
          actionItem: actionItemSnippet,
          addAction: addActionSnippet,
          collapsible: collapsibleSnippet,
          callout: calloutSnippet,
          ticks: ticksSnippet,
          video: videoSnippet
        };
      };

      mastalkCommand.queryState = function () {
        return true;
      };

      mastalkCommand.queryEnabled = function () {
        return true;
      };

      scribe.commands[commandName] = mastalkCommand;
    };
  };
});

define([
  'text!snippet-collapsible',
  'text!snippet-ticks',
  'text!snippet-callout',
  'text!snippet-add-action',
  'text!snippet-video',
  'text!snippet-action-item'
], function (
    collapsibleSnippet,
    ticksSnippet,
    calloutSnippet,
    addActionSnippet,
    videoSnippet,
    actionItemSnippet
  ) {
  'use strict';
  /**
   * This plugin adds each mastalk md snippet
   */
  return function (type) {
    return function (scribe) {
      var commandName = "mastalk_" + type;
      var mastalkCommand = new scribe.api.Command('insertHTML');

      mastalkCommand.execute = function () {
        scribe.insertPlainText(this.getType()[type].trim() + '\n\n');
      };

      mastalkCommand.getType = function () {
        return {
          actionItem: actionItemSnippet,
          addAction: addActionSnippet,
          collapsible: collapsibleSnippet,
          callout: calloutSnippet,
          ticks: ticksSnippet,
          video: videoSnippet
        };
      };

      mastalkCommand.queryState = function () {
        return true;
      };

      mastalkCommand.queryEnabled = function () {
        return true;
      };

      scribe.commands[commandName] = mastalkCommand;
    };
  };
});

Add new line below each snippet


var config = {
    development: {
        server: {
            port: 8080
        }
    },
    testing: {
        server: {
            port: 8080
        }
    },
    production: {
        server: {
            port: 8080
        }
    }
};

module.exports = config[process.env.NODE_ENV || 'development'];

var config = {
    development: {
        server: {
            port: 3000
        }
    },
    testing: {
        server: {
            port: 3001
        }
    },
    production: {
        server: {
            port: 8080
        }
    }
};

module.exports = config[process.env.NODE_ENV || 'development'];

Revert "Changed port to 8080 on all environments"


var config = {};

//Port to listen on
config.port = process.env.PORT || 8081;
//Database address
config.db_host = process.env.DB_HOST || '127.0.0.1';
//Database port
config.db_port = process.env.DB_PORT || 27017;
//Collection name
config.db_collection = process.env.DB_COLLECTION || 'healthcare-demo';

config.log_level = process.env.LOG_LEVEL || 'debug';

config.paramDefaults = {
	listCount: null,
	listOffset: 0,
	listSort: 1,
	listSortKey: "_id",
	listStart: new Date(0),
	listEnd: new Date('01/01/3000'),
	listDate: 'createdDate'
};

module.exports = config;

var config = {};

//Port to listen on
config.port = process.env.PORT || 8081;
//Database address
config.db_host = process.env.DB_HOST || '127.0.0.1';
//Database port
config.db_port = process.env.DB_PORT || 27017;
//Collection name
config.db_collection = process.env.DB_COLLECTION || 'health_demo';

config.log_level = process.env.LOG_LEVEL || 'debug';

config.paramDefaults = {
	listCount: null,
	listOffset: 0,
	listSort: 1,
	listSortKey: "_id",
	listStart: new Date(0),
	listEnd: new Date('01/01/3000'),
	listDate: 'createdDate'
};

module.exports = config;

Use db collection created on build machine in Mongo


'use strict';

// Dependencies
const cssnext = require('cssnext')
const path = require('path')

// Aliases
let basedir = __dirname
let env = process.env.NODE_ENV

module.exports = {
  env: env,

  paths: {
    destination: path.join(basedir, 'dist'),
    source: path.join(basedir, 'src'),
    templates: path.join(basedir, 'templates')
  },

  processors: {
    defaults: {
      '*.md': {
        kind: 'page',
        template: 'page'
      },
      'posts/**/*.md': {
        kind: 'post',
        permalink: false,
        template: 'post'
      }
    },
    extractPathData: {
      'posts/**/*.md': 'posts/{category}/{date}--{slug}.md'
    },
    rewritePath: {
      'posts/**/*.md': function(file) {
        return ['blog', file.category, file.slug + '.html'].join('/')
      }
    },
    postcss: [
      cssnext()
    ]
  },

  globals: {
    env: env,
    site: {
      title: 'Steffen Bruchmann’s Website'
    }
  }
}

'use strict';

// Dependencies
const cssnext = require('cssnext')
const moment = require('moment')
const path = require('path')

// Aliases
let basedir = __dirname
let env = process.env.NODE_ENV

module.exports = {
  env: env,

  paths: {
    destination: path.join(basedir, 'dist'),
    source: path.join(basedir, 'src'),
    templates: path.join(basedir, 'templates')
  },

  processors: {
    defaults: {
      '*.md': {
        kind: 'page',
        template: 'page'
      },
      'posts/**/*.md': {
        kind: 'post',
        permalink: false,
        template: 'post'
      }
    },
    extractPathData: {
      'posts/**/*.md': 'posts/{category}/{date}--{slug}.md'
    },
    rewritePath: {
      'posts/**/*.md': function(file) {
        return ['blog', file.category, file.slug + '.html'].join('/')
      }
    },
    postcss: [
      cssnext()
    ]
  },

  globals: {
    buildDate: moment(),
    env: env,
    site: {
      title: 'Steffen Bruchmann’s Website'
    }
  }
}

Add build date to globals


(function (angular){
  'use strict';

  angular.module('app')
    .controller('counterController', counterController)
    .controller('todoController', todoController)

    counterController.$inject = []
    todoController.$inject = []

    function counterController(){
      this.counter = 0;

      this.add = function() {
       this.counter >= 10 ? this.counter : this.counter ++;
      }

      this.sub = function(){
        this.counter === 0 ? this.counter : this.counter --;
      }
    };

    function todoController(){
      this.tasks = [{name: "Brush Your Teeth", complete: true}, {name: "Tie Shoes", complete: false}];
      this.newTask = '';
      this.completed = 1;
      this.total = this.tasks.length;

      this.add = function(){
        console.log(this.newTask)
        this.tasks.push({name: this.newTask, complete: false});
      }.bind(this)

      this.complete = function(taskIndex){
        console.log(taskIndex);
        this.tasks[taskIndex].complete = true;

         this.completed = this.tasks.reduce(function(p, n){
          return n.complete === true ? p + 1 : p;
        }, 0);

      }

    }

})(window.angular);

(function (angular){
  'use strict';

  angular.module('app')
    .controller('counterController', counterController)
    .controller('todoController', todoController)

    counterController.$inject = []
    todoController.$inject = []

    function counterController(){
      this.counter = 0;

      this.add = function() {
       this.counter >= 10 ? this.counter : this.counter ++;
      }

      this.sub = function(){
        this.counter === 0 ? this.counter : this.counter --;
      }
    };

    function todoController(){
      this.tasks = [{name: "Brush Your Teeth", complete: true}, {name: "Tie Shoes", complete: false}];
      this.newTask = '';
      this.completed = 1;
      this.total = this.tasks.length;

      this.add = function(){
        console.log(this.newTask)
        this.tasks.push({name: this.newTask, complete: false});

        this.total = this.tasks.length;
      }.bind(this)

      this.complete = function(taskIndex){
        console.log(taskIndex);
        this.tasks[taskIndex].complete = true;
        this.
         this.completed = this.tasks.reduce(function(p, n){
          return n.complete === true ? p + 1 : p;
        }, 0);

      }

    }

})(window.angular);

Fix completed fraction display to update when new task added


class SpriteList {
  constructor() {
    this.sprites = [];
  }

  draw() {
    for (var i = 0; i < this.sprites.length; i++) {
      if (this.sprites[i]) {
        this.sprites[i].draw();
      }
    }
  }

  push(newSprite) {
    this.sprites.push(newSprite);
  }

  remove(sprite) {
    var index = this.sprites.indexOf(sprite);
    this.sprites.splice(index, 1);
  }

  getLength() {
    return this.sprites.length;
  }
}

module.exports = SpriteList;

class SpriteList {
  constructor() {
    this.sprites = [];
  }

  draw() {
    _.invokeMap(_.compact(this.sprites), 'draw');
  }

  push(newSprite) {
    this.sprites.push(newSprite);
  }

  remove(sprite) {
    var index = this.sprites.indexOf(sprite);
    this.sprites.splice(index, 1);
  }

  getLength() {
    return this.sprites.length;
  }
}

module.exports = SpriteList;

Refactor an ugly for loop.


const ghpages = require('gh-pages')
const gitRemoteOriginUrl = require('git-remote-origin-url')
const path = require('path')

const GH_TOKEN = process.env.GH_TOKEN
const GH_USER = process.env.GH_USER
const GH_EMAIL = process.env.GH_EMAIL

function publish (remoteUrl) {
  const repo = GH_TOKEN ? remoteUrl.replace(/(\/\/)/, `$1${GH_TOKEN}@`) : remoteUrl
  const user = GH_USER && GH_EMAIL ? { name: GH_USER, email: GH_EMAIL } : {}

  console.log('Starting deployment to GitHub pages')
  ghpages.publish(path.join(__dirname, 'dist'), Object.assign({}, {
    silent: true,
    repo: repo
  }, user), function (err) {
    if (err) {
      console.error(`Deployment error: ${err.message}`)
      return process.exit(1)
    }

    console.log('Deployment complete!')
    return process.exit(0)
  })
}

gitRemoteOriginUrl().then(publish)

const ghpages = require('gh-pages')
const gitRemoteOriginUrl = require('git-remote-origin-url')
const path = require('path')

const GH_TOKEN = process.env.GH_TOKEN
const GH_USER = process.env.GH_USER
const GH_EMAIL = process.env.GH_EMAIL

function publish (remoteUrl) {
  const repo = GH_TOKEN ? remoteUrl.replace(/(\/\/)/, `$1${GH_TOKEN}@`) : remoteUrl
  const user = GH_USER && GH_EMAIL ? { name: GH_USER, email: GH_EMAIL } : {}

  console.log('Starting deployment to GitHub pages')
  ghpages.publish(path.join(__dirname, 'dist'), Object.assign({}, {
    repo: repo
  }, user), function (err) {
    if (err) {
      console.error(`Deployment error: ${err.message}`)
      return process.exit(1)
    }

    console.log('Deployment complete!')
    return process.exit(0)
  })
}

gitRemoteOriginUrl().then(publish)

Remove silent option for debugging


/*global _*/
/*global angular*/

(function() {
    'use strict';

    angular.module('core').directive('slideSection',
        function() {
            return {
                link: function postLink(scope, element, attrs) {
                    scope.$watchGroup(scope.members, function(values) {
                        if (_.some(values)) {
                            element.show();
                        } else {
                            element.hide();
                        }
                    });
                },
                controller: ['$scope', function SlideSectionController($scope) {
                    $scope.members = [];

                    this.addMember = function(member) {
                        if (!_.includes($scope.members)) {
                            $scope.members.push(member);
                        }
                    };
                }]
            };
        }
    );
}());

/*global _*/
/*global angular*/

(function() {
    'use strict';

    angular.module('core').directive('slideSection',
        function() {
            return {
                link: function postLink(scope, element, attrs) {
                    scope.$watchGroup(scope.members, function(values) {
                        if (_.some(values)) {
                            element.show();
                        } else {
                            element.hide();
                        }
                    });
                },
                controller: ['$scope', function SlideSectionController($scope) {
                    $scope.members = [];

                    this.addMember = function(member) {
                        member = 'slide.content.' + member;

                        if (!_.includes($scope.members, member)) {
                            $scope.members.push(member);
                        }
                    };
                }]
            };
        }
    );
}());

Fix slide-section not watching the slide-part members.


import { mpe } from './util.js'

function matchingKey (action) {
	switch (action) {
		case 'like': return 'like-of'
		case 'repost': return 'repost-of'
		case 'bookmark': return 'bookmark-of'
		default: return 'in-reply-to'
	}
}

export default class IndieAction extends HTMLElement {
	connectedCallback () {
		for (const el of this.querySelectorAll('a, button')) {
			el.addEventListener('click', e => mpe().newEntry({
				[matchingKey(this.getAttribute('do'))]: [this.getAttribute('with')]
			}))
		}
	}
}

customElements.define('indie-action', IndieAction)

import { mpe } from './util.js'

function matchingKey (action) {
	switch (action) {
		case 'like': return 'like-of'
		case 'repost': return 'repost-of'
		case 'bookmark': return 'bookmark-of'
		default: return 'in-reply-to'
	}
}

export default class IndieAction extends HTMLElement {
	connectedCallback () {
		const editor = mpe()
		for (const el of this.querySelectorAll('a, button')) {
			el.addEventListener('click', e => editor.newEntry({
				[matchingKey(this.getAttribute('do'))]: [this.getAttribute('with')],
				content: [{ [editor.defaultctype]: '' }],
			}))
		}
	}
}

customElements.define('indie-action', IndieAction)

Add content on new reactions


'use strict';
var U = require('lodash');
var DynamoDB = require('./dynamodb');

function CreateRelation() {}

module.exports = CreateRelation;

CreateRelation.create = function createCreateRelation(spec) {
	var obj = new CreateRelation();
	return obj.initialize(spec);
};

U.extend(CreateRelation.prototype, {
	initialize: function (spec) {
		Object.defineProperties(this, {
			dynamodb: {
				value: spec.dynamodb
			}
		});

		return this;
	},

	parameters: function (subject, object) {
		return {
			Item: DynamoDB.serializeRelation({
				subject: subject,
				object: object
			}),
			TableName: this.dynamodb.relationTable(),
			ConditionExpression: 'attribute_not_exists(subject) AND ' +
				'attribute_not_exists(object)'
			// Potentially useful parameters:
			// ReturnConsumedCapacity
			// ReturnItemCollectionMetrics
		};
	},

	create: function (subject, object) {
		return this.dynamodb
			.putItem(this.parameters(subject, object))
			.then(U.constant(true));
	}
});

'use strict';
var U = require('lodash');
var DynamoDB = require('./dynamodb');

function CreateRelation() {}

module.exports = CreateRelation;

CreateRelation.create = function createCreateRelation(spec) {
	var obj = new CreateRelation();
	return obj.initialize(spec);
};

U.extend(CreateRelation.prototype, {
	initialize: function (spec) {
		Object.defineProperties(this, {
			dynamodb: {
				value: spec.dynamodb
			}
		});

		return this;
	},

	parameters: function (subjectId, objectId) {
		return {
			Item: DynamoDB.serializeRelation({
				subject: subjectId,
				object: objectId
			}),
			TableName: this.dynamodb.relationTable(),
			ConditionExpression: 'attribute_not_exists(subject) AND ' +
				'attribute_not_exists(object)'
			// Potentially useful parameters:
			// ReturnConsumedCapacity
			// ReturnItemCollectionMetrics
		};
	},

	create: function (subjectId, objectId) {
		return this.dynamodb
			.putItem(this.parameters(subjectId, objectId))
			.then(U.constant(true));
	}
});

Fix parameter syntax in CreateReleation


'use babel';

import { CompositeDisposable } from 'atom';
import fs from 'fs';

export default {
  modalPanel: null,
  subscriptions: null,

  config: {
    shouldCreateFile: {
      type: 'boolean',
      default: true,
    },
    testExtension: {
      type: 'string',
      default: '.spec',
    },
  },

  activate(state) {
    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'open-tests:open': () => this.open()
    }));
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  getTestPath() {
    const testExtension = atom.config.get('open-tests.testExtension')
    const filePath = atom.workspace.getActivePaneItem().buffer.file.path

    const index = filePath.lastIndexOf('.')
    const fileExtension = filePath.substring(index)
    const fileWithoutExt = filePath.substring(0,index)

    return (fileWithoutExt + testExtension + fileExtension)
  },

  open() {
    const shouldCreate = atom.config.get('open-tests.shouldCreateFile')

    const testPath = getTestPath()

    if (!fs.existsSync(path) && !shouldCreate) {
      atom.notifications.addError('File not found')
      return
    }

    atom.open({ pathsToOpen: testPath })
  }
};

'use babel';

import { CompositeDisposable } from 'atom';
import fs from 'fs';

export default {
  modalPanel: null,
  subscriptions: null,

  config: {
    shouldCreateFile: {
      type: 'boolean',
      default: true,
    },
    testExtension: {
      type: 'string',
      default: '.spec',
    },
  },

  activate(state) {
    this.subscriptions = new CompositeDisposable();
    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'open-tests:open': () => this.open()
    }));
  },

  deactivate() {
    this.subscriptions.dispose();
  },

  getTestPath() {
    const testExtension = atom.config.get('open-tests.testExtension')
    const filePath = atom.workspace.getActivePaneItem().buffer.file.path

    const index = filePath.lastIndexOf('.')
    const fileExtension = filePath.substring(index)
    const fileWithoutExt = filePath.substring(0,index)

    return (fileWithoutExt + testExtension + fileExtension)
  },

  open() {
    const shouldCreate = atom.config.get('open-tests.shouldCreateFile')

    const testPath = this.getTestPath()

    if (!fs.existsSync(path) && !shouldCreate) {
      atom.notifications.addError('File not found')
      return
    }

    atom.open({ pathsToOpen: testPath })
  }
};

Fix call to undefined function


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

module.exports = (env = {}) => {
  let plugins = [];

  if (env.production) {
    plugins = [
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({
        compressor: {
          warnings: false,
          screw_ie8: true,
        },
      }),
    ];
  }

  return {
    devtool: 'source-map',
    resolve: {
      extensions: ['.js'],
    },
    entry: path.join(__dirname, 'src/main.js'),
    output: {
      path: path.resolve(__dirname, 'dist/'),
      filename: 'openseadragon-annotations.js',
      libraryTarget: 'var',
      library: ['OpenSeadragon', 'Viewer', 'prototype', 'annotations'],
      pathinfo: true,
    },
    externals: {
      OpenSeadragon: 'OpenSeadragon',
    },
    module: {
      loaders: [
        { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
        { test: /\.png$/, loader: 'url-loader' },
      ],
    },
    plugins,
  };
};

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

module.exports = (env = {}) => {
  let plugins = [];

  if (env.production) {
    plugins = [
      new webpack.optimize.OccurrenceOrderPlugin(),
      new webpack.optimize.UglifyJsPlugin({
        sourceMap: true,
        compressor: {
          warnings: false,
          screw_ie8: true,
        },
      }),
    ];
  }

  return {
    devtool: 'source-map',
    resolve: {
      extensions: ['.js'],
    },
    entry: path.join(__dirname, 'src/main.js'),
    output: {
      path: path.resolve(__dirname, 'dist/'),
      filename: 'openseadragon-annotations.js',
      libraryTarget: 'var',
      library: ['OpenSeadragon', 'Viewer', 'prototype', 'annotations'],
      pathinfo: true,
    },
    externals: {
      OpenSeadragon: 'OpenSeadragon',
    },
    module: {
      loaders: [
        { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
        { test: /\.png$/, loader: 'url-loader' },
      ],
    },
    plugins,
  };
};

Enable sourcemaps in the uglifyJs plugin


import path from 'path';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';

const sourcePath = path.join(__dirname, './src');
const distPath = path.join(__dirname, './dist');

export default {
  mode: 'production',
  entry: {
    js: [path.join(sourcePath, '/component.js')],
  },
  output: {
    path: distPath,
    filename: (process.env.MIN === 'true') ? 'index.min.js' : 'index.js',
    library: 'zbutton',
    libraryTarget: 'umd',
    umdNamedDefine: true,
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [MiniCssExtractPlugin.loader, 'css-loader?sourceMap', 'postcss-loader'],
      },
      {
        test: /\.hbs$/,
        exclude: /node_modules/,
        use: ['handlebars-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.css'],
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: 'style.css' }),
  ],
};

import path from 'path';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';

const sourcePath = path.join(__dirname, './src');
const distPath = path.join(__dirname, './dist');

export default {
  mode: (process.env.MIN === 'true') ? 'production' : 'none',
  entry: {
    js: [path.join(sourcePath, '/component.js')],
  },
  output: {
    path: distPath,
    filename: (process.env.MIN === 'true') ? 'index.min.js' : 'index.js',
    library: 'zbutton',
    libraryTarget: 'umd',
    umdNamedDefine: true,
  },
  devtool: 'source-map',
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ['babel-loader'],
      },
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [MiniCssExtractPlugin.loader, 'css-loader?sourceMap', 'postcss-loader'],
      },
      {
        test: /\.hbs$/,
        exclude: /node_modules/,
        use: ['handlebars-loader'],
      },
    ],
  },
  resolve: {
    extensions: ['.js', '.css'],
  },
  plugins: [
    new MiniCssExtractPlugin({ filename: 'style.css' }),
  ],
};

Add mode config based on MIN env variable


define([
	"../var/support"
], function( support ) {

(function() {
	var fragment = document.createDocumentFragment(),
		div = fragment.appendChild( document.createElement( "div" ) ),
		input = document.createElement( "input" );

	// Support: Windows Web Apps (WWA)
	// `name` and `type` must use .setAttribute for WWA (#14901)
	input.setAttribute( "type", "radio" );
	input.setAttribute( "checked", "checked" );

	div.appendChild( input );

	// Support: Android<4.2
	// Older WebKit doesn't clone checked state correctly in fragments
	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

	// Support: IE<=11+
	// Make sure textarea (and checkbox) defaultValue is properly cloned
	div.innerHTML = "<textarea>x</textarea>";
	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
})();

return support;

});

define([
	"../var/support"
], function( support ) {

(function() {
	var fragment = document.createDocumentFragment(),
		div = fragment.appendChild( document.createElement( "div" ) ),
		input = document.createElement( "input" );

	// Support: Android 4.0-4.3
	// Check state lost if the name is set (#11217)
	// Support: Windows Web Apps (WWA)
	// `name` and `type` must use .setAttribute for WWA (#14901)
	input.setAttribute( "type", "radio" );
	input.setAttribute( "checked", "checked" );
	input.setAttribute( "name", "t" );

	div.appendChild( input );

	// Support: Android<4.2
	// Older WebKit doesn't clone checked state correctly in fragments
	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;

	// Support: IE<=11+
	// Make sure textarea (and checkbox) defaultValue is properly cloned
	div.innerHTML = "<textarea>x</textarea>";
	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
})();

return support;

});

Check state lost if the name is set for Android 4.0-4.3


describe('Address Book', function() {
	it('should be able to add a contact', function() {
		var addressB = new addressBook(),
			thisContact = new Contact();
		addressB.addContact(thisContact);
		expect(addressB.getContact(0)).toBe(thisContact);
	});
});

Add test for add contact (at the moment is failing)


import React, { Component } from 'react';

class IssueList extends Component {
  constructor() {
    super();
    this.renderIssue = this.renderIssue.bind(this);
  }

  renderIssue(issue) {
    return (

{issue.key}

{issue.title}

            {issue.type} {issue.state}

    );
  }

  cardStyle(issue) {
    if (issue.status) {
      switch(issue.status.result){
        case 'SUCCESS':
          return 'card-success';
        case 'RUNNING':
          return 'card-info';
        case 'ERROR':
          return 'card-danger';
      }
    }
    return "card-outline-secondary";
  }

  render() {
    return (

        {this.props.issues.map(this.renderIssue)}

    )
  }
}

export default IssueList;

import React, { Component } from 'react';

class IssueList extends Component {
  constructor() {
    super();
    this.renderIssue = this.renderIssue.bind(this);
  }

  renderIssue(issue) {
    return (

{issue.key}

{issue.title}

            {issue.type} {issue.state}

    );
  }

  cardStyle(issue) {
    if (issue.status) {
      switch(issue.status.result){
        case 'SUCCESS':
          return 'card-success';
        case 'RUNNING':
          return 'card-info';
        case 'FAILURE':
          return 'card-danger';
      }
    }
    return "card-outline-secondary";
  }

  render() {
    return (

        {this.props.issues.map(this.renderIssue)}

    )
  }
}

export default IssueList;

Update status results in React app


const {convert} = require('stencila-convert')

module.exports = cli => {
  cli
    .command('convert', 'Convert files or folders to other formats')

    .argument('<input>', 'Input file or folder to convert from')
    .argument('<output>', 'Input file or folder to convert to')
    .option('--from', 'Format to convert from (overrides file name extensions)')
    .option('--to', 'Format to convert to (overrides file name extensions)')

    .action(async (args, options, logger) => {
      const {input, output} = args
      const {from, to} = options
      logger.debug(`Converting "${input}" to "${output}"`)
      try {
        await convert(input, output, null, null, from, to)
        logger.ok(`Success converting "${input}" to "${output}"`)
      } catch (err) {
        logger.error(`Error converting "${input}" to "${output}": ${err.message}`)
      }
    })
}

const {convert} = require('stencila-convert')

module.exports = cli => {
  cli
    .command('convert', 'Convert files or folders to other formats')

    .argument('[input]', 'Input file or folder to convert from (or "-" for standard input)', null, '-')
    .argument('[output]', 'Input file or folder to convert to (or "-" for standard output)', null, '-')
    .option('--from', 'Format to convert from (overrides file name extensions)')
    .option('--to', 'Format to convert to (overrides file name extensions)')

    .action(async (args, options, logger) => {
      const {input, output} = args
      const {from, to} = options
      logger.debug(`Converting "${input}" to "${output}"`)
      try {
        await convert(input, output, null, null, from, to)
        logger.ok(`Success converting "${input}" to "${output}"`)
      } catch (err) {
        logger.error(`Error converting "${input}" to "${output}": ${err.message}`)
      }
    })
}

Allow for input from stdin and output to stdout


const gulp = require('gulp');
const pump = require('pump');
const rename = require('gulp-rename');
const sass = require('gulp-sass');
const webpack = require('webpack-stream');
const uglify = require('gulp-uglify');

var config = {
	"pug": {
		"src": "./app/pug/*.pug",
		"dest": "./"
	},
	"sass": {
		"src": "./app/sass/*.scss",
		"dest": "./css/"
	},
	"js": {
		"src": "./app/js/*.js",
		"dest": "./js/"
	}
};

gulp.task('pug', () => {
	return gulp.src(config.pug.src)
	.pipe(pug())
	.pipe(gulp.dest(config.pug.dest))
});

gulp.task('sass', () => {
	return gulp.src(config.sass.src)
	.pipe(sass())
	.pipe(gulp.dest(config.sass.dest))
});

gulp.task('js', (cb) => {
	pump([
        gulp.src(config.js.src),
        uglify(),
        gulp.dest(config.js.dest)
    ],
    cb
  );
});

gulp.task('watch', () => {
	gulp.watch(config.sass.src, ['sass']);
	gulp.watch(config.js.src, ['js']);
});

gulp.task('default', ['watch']);

const gulp = require('gulp');
const pump = require('pump');
const rename = require('gulp-rename');
const sass = require('gulp-sass');
const webpack = require('webpack-stream');
const uglify = require('gulp-uglify');

var config = {
	"pug": {
		"src": "./app/pug/*.pug",
		"dest": "./"
	},
	"sass": {
		"src": "./app/sass/*.scss",
		"dest": "./css/"
	},
	"js": {
		"src": "./app/js/*.js",
		"dest": "./js/"
	}
};

gulp.task('pug', () => {
	return gulp.src(config.pug.src)
	.pipe(pug())
	.pipe(gulp.dest(config.pug.dest))
});

gulp.task('sass', () => {
	return gulp.src(config.sass.src)
	.pipe(sass())
	.pipe(gulp.dest(config.sass.dest))
});

gulp.task('js', function() {
	return gulp.src(config.js.src)
	.pipe(webpack({
		watch: true,
		module: {
      loaders: [
        { test: /\.jsx?/, loader: 'babel' },
      ],
    },
	}))
	.pipe(rename(function(path) {
		path.basename = 'app'
	}))
	.pipe(gulp.dest('./js/'));
});

gulp.task('watch', () => {
	gulp.watch(config.sass.src, ['sass']);
	gulp.watch(config.js.src, ['js']);
});

gulp.task('default', ['watch']);

Rewrite JS compilation task to make use of Webpack


/**
 * ImageController
 *
 * @description :: Server-side logic for managing Images
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var cloudinary = require('cloudinary');

module.exports = {

  create: function (req, res) {

    req.file('image').upload({
      maxBytes: 10000000
    }, function whenDone(err, uploads) {

      if (err) {
        return res.serverError(err);
      }

      // If no files were uploaded, respond with an error
      if (uploads.length === 0) {
        return res.badRequest('No file was uploaded');
      }

      // Only consider one file per POST request
      var upload = uploads[0];

      // Upload image via Cloudinary
      cloudinary.uploader.upload(upload, function(result) {

        sails.log.info(result);

        Image.create({
          filename: result.public_id,
          height:   result.height,
          width:    result.width
        }).exec(function (err, image) {
          if (err) return res.serverError(err);
          return res.created(image);
        });

      });

    });

  }

};

/**
 * ImageController
 *
 * @description :: Server-side logic for managing Images
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

var cloudinary = require('cloudinary');

module.exports = {

  create: function (req, res) {

    req.file('image').upload({
      maxBytes: 10000000
    }, function whenDone(err, uploads) {

      if (err) {
        return res.serverError(err);
      }

      // If no files were uploaded, respond with an error
      if (uploads.length === 0) {
        return res.badRequest('No file was uploaded');
      }

      // Only consider one file per POST request
      var upload = uploads[0];

      // Upload image via Cloudinary
      cloudinary.uploader.upload(upload.fd, function(result) {

        sails.log.info(result);

        Image.create({
          filename: result.public_id,
          height:   result.height,
          width:    result.width
        }).exec(function (err, image) {
          if (err) return res.serverError(err);
          return res.created(image);
        });

      });

    });

  }

};

Add proper file path name


'use strict';

angular.module('copayApp.controllers').controller('backupWarningController', function($scope, $state, $timeout, $stateParams, $ionicModal) {

  $scope.walletId = $stateParams.walletId;
  $scope.fromState = $stateParams.from == 'onboarding' ? $stateParams.from + '.backupRequest' : $stateParams.from;
  $scope.toState = $stateParams.from + '.backup';

  $scope.openPopup = function() {
    $ionicModal.fromTemplateUrl('views/includes/screenshotWarningModal.html', {
      scope: $scope,
      backdropClickToClose: true,
      hardwareBackButtonClose: true
    }).then(function(modal) {
      $scope.warningModal = modal;
      $scope.warningModal.show();
    });

    $scope.close = function() {
      $scope.warningModal.hide();
      $scope.warningModal.remove();
      $state.go($scope.toState, {
        walletId: $scope.walletId
      });
    };
  }

  $scope.goBack = function() {
    $state.go($scope.fromState, {
      walletId: $scope.walletId
    });
  };

});

'use strict';

angular.module('copayApp.controllers').controller('backupWarningController', function($scope, $state, $timeout, $stateParams, $ionicModal) {

  $scope.walletId = $stateParams.walletId;
  $scope.fromState = $stateParams.from == 'onboarding' ? $stateParams.from + '.backupRequest' : $stateParams.from;
  $scope.toState = $stateParams.from + '.backup';

  $scope.openPopup = function() {
    $ionicModal.fromTemplateUrl('views/includes/screenshotWarningModal.html', {
      scope: $scope,
      backdropClickToClose: true,
      hardwareBackButtonClose: true
    }).then(function(modal) {
      $scope.warningModal = modal;
      $scope.warningModal.show();
    });

    $scope.close = function() {
      $scope.warningModal.remove();
      $timeout(function() {
        $state.go($scope.toState, {
          walletId: $scope.walletId
        });
      }, 200);
    };
  }

  $scope.goBack = function() {
    $state.go($scope.fromState, {
      walletId: $scope.walletId
    });
  };

});

Fix backup view if spending password actived


import './Header.css';
import React from 'react';
import profile from '../profile.json';

export default class Header extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (

           Popular Repositories

           Yacine Rezgui

    );
  }
}

import './Header.css';
import React from 'react';
import profile from '../profile.json';

export default class Header extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (

           Popular Repositories

           {profile.name}

    );
  }
}

Change header static content to API data


var html = require('choo/html')
var picoModal = require('picomodal')
var _ = require('../util')

module.exports = function (props, emit) {
  var moves = _.chunksOf(2, props.game.game.moveHistory)
    .map(function (move, idx) {
      return (idx + 1) + '. ' + move[0].algebraic + (move[1] ? (' ' + move[1].algebraic) : '')
    })
    .join('\n')
  var modal

  function handleFocus (e) {
    e.target.select()
  }

  modal = picoModal(html`
    <div>
      <label for="move-history-textarea">
        Copy & paste move history to send to a friend
      </label>

      <textarea onfocus=${handleFocus} readonly=${true}>${moves}</textarea>
    </div>
  `).afterClose(function () {
    emit('closeModal')
    modal.destroy()
  }).show()

  return modal
}

var html = require('choo/html')
var picoModal = require('picomodal')
var _ = require('../util')

module.exports = function (props, emit) {
  var moves = _.chunksOf(2, props.game.game.moveHistory)
    .map(function (move, idx) {
      return (idx + 1) + '. ' + move[0].algebraic + (move[1] ? (' ' + move[1].algebraic) : '')
    })
    .join('\n')
  var modal

  function handleFocus (e) {
    e.target.select()
  }

  modal = picoModal(html`
    <div>
      <label for="move-history-textarea">
        Copy & paste move history to send to a friend
      </label>
      <textarea id="move-history-textarea" onfocus=${handleFocus} readonly=${true}>${moves}</textarea>
    </div>
  `).afterClose(function () {
    emit('closeModal')
    modal.destroy()
  }).show()

  return modal
}

Fix textarea / label association


/* jslint node: true */
module.exports = (sequelize, { INTEGER, STRING, BOOLEAN, DATE }) => {
  const Recycle = sequelize.define('Recycle', {
    quantity: INTEGER,
    address: STRING,
    isPickup: { type: BOOLEAN, defaultValue: false },
    date: DATE
  })

  Recycle.associate = ({ User }) => {
    Recycle.belongsTo(User, { constraints: true, foreignKeyConstraint: true })
  }

  return Recycle
}

/* jslint node: true */
module.exports = (sequelize, { INTEGER, STRING, BOOLEAN, DATE }) => {
  const Recycle = sequelize.define('Recycle', {
    quantity: INTEGER(4),
    address: STRING(180),
    isPickup: { type: BOOLEAN, defaultValue: false },
    date: DATE
  })

  Recycle.associate = ({ User }) => {
    Recycle.belongsTo(User, { constraints: true, foreignKeyConstraint: true })
  }

  return Recycle
}

Enforce column constraints similar to form validation


var koa = require('koa')
  , router = require('koa-router')
  , mount = require('koa-mount')
  , bodyParser = require('koa-bodyparser')
  , koaqs = require('koa-qs')
  , session = require('koa-session')
  , accesslog = require('koa-accesslog')

var Grant = require('grant-koa')
  , grant = new Grant(require('./config.json'))

var app = koa()
app.keys = ['secret','key']
app.use(accesslog())
app.use(mount(grant))
app.use(bodyParser())
app.use(session(app))
app.use(router(app))
koaqs(app)

app.get('/handle_facebook_callback', function *(next) {
  console.log(this.query)
  this.body = JSON.stringify(this.query, null, 2)
})

app.get('/handle_twitter_callback', function *(next) {
  console.log(this.query)
  this.body = JSON.stringify(this.query, null, 2)
})

app.listen(3000, function() {
  console.log('Koa server listening on port ' + 3000)
})

var koa = require('koa')
  , router = require('koa-router')
  , mount = require('koa-mount')
  , bodyParser = require('koa-bodyparser')
  , koaqs = require('koa-qs')
  , session = require('koa-session')
  , accesslog = require('koa-accesslog')

var Grant = require('grant-koa')
  , grant = new Grant(require('./config.json'))

var app = koa()
app.keys = ['secret','key']
app.use(accesslog())
app.use(session(app))
app.use(mount(grant))
app.use(bodyParser())
app.use(router(app))
koaqs(app)

app.get('/handle_facebook_callback', function *(next) {
  console.log(this.query)
  this.body = JSON.stringify(this.query, null, 2)
})

app.get('/handle_twitter_callback', function *(next) {
  console.log(this.query)
  this.body = JSON.stringify(this.query, null, 2)
})

app.listen(3000, function() {
  console.log('Koa server listening on port ' + 3000)
})

Use session middleware before mounting grant


var Watcher = require('large-watcher');

module.exports = function(codebox) {
    var events = codebox.events;

    codebox.logger.log("Starting the file watcher");

    codebox.workspace.path()
    .then(function(path) {
        var watcher = Watcher(path, 2);

        // Handle deleted files
        watcher.on('deleted', function(files) {
            codebox.events.emit('watcher:deleted', files);
        });

        // Handle modified files
        watcher.on('modified', function(files) {
            codebox.events.emit('watcher:modified', files);
        });

        codebox.logger.log("File watcher started");
    });

};

var Watcher = require('large-watcher');

module.exports = function(codebox) {
    var events = codebox.events;

    codebox.logger.log("Starting the file watcher");

    codebox.workspace.path()
    .then(function(path) {
        var watcher = Watcher(path, 2);

        // Handle deleted files
        watcher.on('deleted', function(files) {
            codebox.events.emit('fs:deleted', files);
        });

        // Handle modified files
        watcher.on('modified', function(files) {
            codebox.events.emit('fs:modified', files);
        });

        codebox.logger.log("File watcher started");
    });

};

Change events name to adapt to client


"use strict";

var webdriverio = require('webdriverio');
var options = {
  desiredCapabilities: {
    browserName: 'phantomjs'
  }
};
var client = webdriverio.remote(options);

before(function(done) {
  client.init(done);
});

after(function(done) {
  client.end(done);
});

exports.client = client;

"use strict";

var webdriverio = require('webdriverio');
var options = {
  desiredCapabilities: {
    browserName: 'phantomjs'
  }
};
var client = webdriverio.remote(options);

before(function(done) {
  client.init().then(function(result) {
    done();
  }, function(error) {
    done(error);
  });
});

after(function(done) {
  client.end().then(function(result) {
    done();
  }, function(error) {
    done(error);
  });
});

exports.client = client;

Convert init and end to use promises


Object.freeze(Object.prototype);
require.paths.unshift('../lib');
global.assert = require('assert');
global.fs = require('fs');
global.Step = require('step');
global.nStore = require('nstore');

// A mini expectations module to ensure expected callback fire at all.
var expectations = {};
global.expect = function expect(message) {
  expectations[message] = new Error("Missing expectation: " + message);
}
global.fulfill = function fulfill(message) {
  delete expectations[message];
}
process.addListener('exit', function () {
  Object.keys(expectations).forEach(function (message) {
    throw expectations[message];
  });
});

function clean() {
  fs.writeFileSync("fixtures/toDelete.db", fs.readFileSync("fixtures/sample.db", "binary"), "binary");
  try {
    fs.unlinkSync('fixtures/new.db');
  } catch (err) {
    if (err.errno !== process.ENOENT) {
      throw err;
    }
  }
}

// Clean the test environment at startup
clean();

// Clean on exit too
// process.addListener('exit', clean);

Object.freeze(Object.prototype);
require.paths.unshift('../lib');
global.assert = require('assert');
global.fs = require('fs');
global.Step = require('step');
global.nStore = require('nstore');

// A mini expectations module to ensure expected callback fire at all.
var expectations = {};
global.expect = function expect(message) {
  expectations[message] = new Error("Missing expectation: " + message);
}
global.fulfill = function fulfill(message) {
  delete expectations[message];
}
process.addListener('exit', function () {
  Object.keys(expectations).forEach(function (message) {
    throw expectations[message];
  });
});

function clean() {
  fs.writeFileSync("fixtures/toDelete.db", fs.readFileSync("fixtures/sample.db", "binary"), "binary");
  try {
    fs.unlinkSync('fixtures/new.db');
  } catch (err) {
    if (err.errno !== process.ENOENT) {
      throw err;
    }
  }
}

// Clean the test environment at startup
clean();

// Clean on exit too
process.addListener('exit', clean);

Clean up fixtures on exit too.


// This script contains the code necessary to make requests to the python API,
// as well as a more general function which is also used to fetch the README
// for rendering.

//Make a synchronous request and return the response
function requestPage(url, onSuccess) {
  var data = null;
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4 && xhttp.status == 200) {
      onSuccess(xhttp.responseText);
    }
  };
  xhttp.open("GET",url,true);
  xhttp.send();
}

//Make an AJAX request to the server while passing a page
function apiRequest(api,page,onSuccess) {
  var url="api/"+api+"?page="+page;
  requestPage(url, function (data){
    onSuccess(JSON.parse(data));
  });
}

//Get the name of all pages linked to by a page
function getSubPages(page,onSuccess) {
  apiRequest("links",page,onSuccess);
}

//Get the name of the wikipedia article for a query
function getPageName(query,onSuccess) {
  apiRequest("pagename",query,onSuccess);
}

function getRandomName(onSuccess) {
  requestPage("api/random", function(resp){
    getPageName(resp,onSuccess);
  });
}

function getSuggestions(text, onSuccess) {
  requestPage("api/suggest"+"?text="+text, function(data) {
    onSuccess(JSON.parse(data));
  })
}

Add JS bindings to suggestions


/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var flags = {};

if ( process.argv.length > 2 ) {
  process.argv[2].split(',').forEach(function(f) {
    flags[f] = true;
  });
}

var env = {
  FOAM_FILES: function(files) {
    var payload = '';

    files.filter(function(f) {
      return f.flags ? flags[f.flags] : true;
    }).map(function(f) {
      return f.name;
    }).forEach(function(f) {
      var data = require('fs').readFileSync(__dirname + '/../src/' + f + '.js').toString();
      payload += data;
    });

    require('fs').writeFileSync(__dirname + '/../foam-bin.js', payload);
  }
};

var data = require('fs').readFileSync(__dirname + '/../src/files.js');

with (env) { eval(data.toString()); }

/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * 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.
 */

var flags = {};

if ( process.argv.length > 2 ) {
  process.argv[2].split(',').forEach(function(f) {
    flags[f] = true;
  });
}

var outfile = __dirname + '/../foam-bin.js';
if ( process.argv.length > 3 ) {
  outfile = process.argv[3];
}

var env = {
  FOAM_FILES: function(files) {
    var payload = '';

    files.filter(function(f) {
      return f.flags ? flags[f.flags] : true;
    }).map(function(f) {
      return f.name;
    }).forEach(function(f) {
      var data = require('fs').readFileSync(__dirname + '/../src/' + f + '.js').toString();
      payload += data;
    });

    require('fs').writeFileSync(outfile, payload);
  }
};

var data = require('fs').readFileSync(__dirname + '/../src/files.js');

with (env) { eval(data.toString()); }

Build script: Support specifying the output file


var webdriverio = require('../../index'),
    client = webdriverio.remote({
        desiredCapabilities: {
            browserName: 'chrome',
            version: '27',
            platform: 'XP',
            tags: ['examples'],
            name: 'This is an example test'
        },
        host: 'ondemand.saucelabs.com',
        port: 80,
        user: process.env.SAUCE_USERNAME,
        key: process.env.SAUCE_ACCESS_KEY,
        logLevel: 'silent'
    }).init();

client
    .url('http://google.com')
    .setValue('*[name="q"]','webdriverio')
    .click('*[name="btnG"]')
    .pause(1000)
    .getTitle(function(err,title) {
        console.log(title);
    })
    .end();

var webdriverio = require('../../index'),
    client = webdriverio.remote({
        desiredCapabilities: {
            browserName: 'chrome',
            version: '27',
            platform: 'XP',
            tags: ['examples'],
            name: 'This is an example test',

            // If using Open Sauce (https://saucelabs.com/opensauce/),
            // capabilities must be tagged as "public" for the jobs's status
            // to update (failed/passed). If omitted on Open Sauce, the job's
            // status will only be marked "Finished." This property can be
            // be omitted for commerical (private) Sauce Labs accounts.
            // Also see https://support.saucelabs.com/customer/portal/articles/2005331-why-do-my-tests-say-%22finished%22-instead-of-%22passed%22-or-%22failed%22-how-do-i-set-the-status-
            'public': true
        },
        host: 'ondemand.saucelabs.com',
        port: 80,
        user: process.env.SAUCE_USERNAME,
        key: process.env.SAUCE_ACCESS_KEY,
        logLevel: 'silent'
    }).init();

client
    .url('http://google.com')
    .setValue('*[name="q"]','webdriverio')
    .click('*[name="btnG"]')
    .pause(1000)
    .getTitle(function(err,title) {
        console.log(title);
    })
    .end();

Add `public` property to Sauce Labs example's `desiredCapabilities`.


#!/bin/env node
var express = require('express')
  , stylus = require('stylus')
  , nib = require('nib')
var util = require('util')
var fs = require("fs")
var server = express()

function compile(str, path) {
  return stylus(str)
    .set('filename', path)
    .use(nib());
}

server.set('views', __dirname + '/views')
server.set('view engine', 'jade')
server.use(express.logger('dev'))
server.use(stylus.middleware(
  { src: __dirname + '/public'
  , compile: compile
  }
))
server.use(express.static(__dirname + '/public'))
server.use(express.urlencoded())
server.use(express.json())

server.get('/fireplot', function (req, res) {
  const folder = './public/json/alfresco/';
  const fs = require('fs');
  var fileList = fs.readdirSync(folder);
  var cp = require("child_process");
  res.render('fireplot',
  { title : 'Fire Plots', files: fileList}
  )
})

var port = process.env.OPENSHIFT_NODEJS_PORT || 8080
, ip = process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1";
server.listen(port, ip);
console.log('Server running on http://%s:%s', ip, port);

Add startup port/ip console log


const config = require("./webpack.config");
const webpack = require("webpack");

const cdnUrl = process.env.CDN_URL || "/";

config.plugins = (config.plugins || []).concat([
  new webpack.DefinePlugin({
    "process.env": {
      NODE_ENV: JSON.stringify("production")
    },
    SENTRY_DSN: JSON.stringify(
      "https://12b6be8ef7c44f28ac37ab5ed98fd294@sentry.io/146021"
    )
  }),
  new webpack.optimize.UglifyJsPlugin({
    sourceMap: true
  })
]);

config.output.publicPath = `${cdnUrl}built/`;

config.entry.winamp.unshift("./js/googleAnalytics.min.js");

module.exports = config;

const config = require("./webpack.config");
const webpack = require("webpack");

const cdnUrl = process.env.CDN_URL || "/";

config.devtool = "source-map";

config.plugins = (config.plugins || []).concat([
  new webpack.DefinePlugin({
    "process.env": {
      NODE_ENV: JSON.stringify("production")
    },
    SENTRY_DSN: JSON.stringify(
      "https://12b6be8ef7c44f28ac37ab5ed98fd294@sentry.io/146021"
    )
  }),
  new webpack.optimize.UglifyJsPlugin({
    sourceMap: true
  })
]);

config.output.publicPath = `${cdnUrl}built/`;

config.entry.winamp.unshift("./js/googleAnalytics.min.js");

module.exports = config;

Enable source maps for prod


// import necessary packages
// path fs and express

// create app
// instantiate var app equal to express()

// define view engine
// app.set view engine to html
// app.engine(html function(path options callbacks))
	// fs. readfile(path standard utf 8 encoding and callback to be used on contents of file)

// middle ware to accept requests and processes them
// tell express to return static files at root folder where bundle.js exists
// app.use express.static file path

// routes
// app.get at root '/' function(request response)
	// return index.html file using res.sendFile (path.join current path, and index html file)

// error handler for other types of requests
// app.use (function error, request, response, next)
	// if errors, respond with error status or 500

// server
// tell server to run on some port e.g. 8000
// tell server to listen on that point
	// log message to console to confirm listening on port

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

// create app
var app = express();

// view engine
app.set('view engine', 'html');
app.engine('html', function(path, options, callbacks){
	fs.readFile(path, 'utf-8', callback);
});

// middleware
app.use(express.static(__dirname));

// routes
app.get('/', function(req, res){
	res.sendFile(path.join(__dirname, 'index.html'));
});

Implement express routes using app.get combining directory and filename location


class ModelSchema {
	constructor(model, query) {
		this.model = model
		this.query = query || 'default'
	}

	get type() {
		return this.model.describe()
	}

	async create(data) {
		const [doc, error] = await this.model.create(data)

		if (error) throw error
		return doc.data
	}

	async read(selector) {
		const docs = await this.model.query(this.query, selector)

		return docs.data
	}

	async update(selector, data) {
		const doc = await this.model.get(selector)
		return await doc.mutate(data)
	}

	async del(selector) {
		return await this.model.del(selector, this.query)
	}
}

module.exports = ModelSchema

class ModelSchema {
	constructor(model, query) {
		this.model = model
		this.query = query || 'default'
	}

	get type() {
		if (this._type) return this._type

		const descriptor = this.model.describe()
		this._type = Object.keys(descriptor).reduce((acc, key) => {
			return { ...acc, [key]: descriptor[key].type }
		}, {})

		return this._type
	}

	async create(data) {
		const [doc, error] = await this.model.create(data)

		if (error) throw error
		return doc.data
	}

	async read(selector) {
		const docs = await this.model.query(this.query, selector)

		return docs.data
	}

	async update(selector, data) {
		const doc = await this.model.get(selector)
		return await doc.mutate(data)
	}

	async del(selector) {
		return await this.model.del(selector, this.query)
	}
}

module.exports = ModelSchema

Fix model schema type to only return `type` property


var AWS = require("aws-sdk");
AWS.config.update({region: 'us-east-1'});

exports.handler = function(event, context) {
    var s3 = new AWS.S3();
    var params = {Bucket: 'cat-assets', Key: 'catfacts.txt'};
    var file = s3.getObject(params, function(err, data){
        if(err){
            context.fail(err);
        }
        var lines = data.Body.toString().split('\r\n');
        var fact = lines[Math.floor(Math.random()*lines.length)] + "! :3";
        console.log(fact);

        var sns = new AWS.SNS();
        params = {
            Message: fact,
            Subject: "Cat Facts",
            TopicArn: "arn:aws:sns:us-east-1:110820207274:CatFacts"
        };
        sns.publish(params, context.done);
    });
};

var AWS = require("aws-sdk");
AWS.config.update({region: 'us-east-1'});

exports.handler = function(event, context) {
    var s3 = new AWS.S3();
    var params = {Bucket: 'cat-assets', Key: 'catfacts.txt'};
    var file = s3.getObject(params, function(err, data){
        if(err){
            context.fail(err);
        }
        var lines = data.Body.toString().split('\r\n');
        var i = Math.floor(Math.random()*lines.length);
        var fact = lines.splice(i, 1) + "! :3";
        console.log(fact);

        s3.putObject({
			Bucket: 'cat-assets',
			Key: 'catfacts.txt',
			Body: lines.join('\r\n')
		}, function(err){
		    if (err){
		        context.fail(err);
		    }
            var sns = new AWS.SNS();
            params = {
                Message: fact,
                Subject: "Cat Facts",
                TopicArn: "arn:aws:sns:us-east-1:110820207274:CatFacts"
            };
            sns.publish(params, context.done);
    	});
    });
};

Remove fact from list once used


/*
In the general preferences you should put something like:
require(['TrackOptions'], function(TrackOptions) {
    TrackOptions('massOptions');
})
*/

define([], function () {
    function watchAnswers(cookieName, exercises) {
        var myAnswers = JSON.parse(window.localStorage.getItem(cookieName) || "{}");

        for (var i=0; i<exercises.length; i++) {
            var exercise=exercises[i];
            var myAnswer=myAnswers[exercise.id];
            if (myAnswer) {
                exercise.myResult=myAnswer;
            }
        }

        exercises.onChange(function (evt) {
            var target=evt.target.__parent;
            if (target) {
                myAnswers[target.id]=target.myResult;
                window.localStorage.setItem(cookieName, JSON.stringify(myAnswers));
            }
        });
    }
    return watchAnswers;
});

/*
In the general preferences you should put something like:
require(['TrackOptions'], function(TrackOptions) {
    TrackOptions('massOptions');
})
*/

define([], function () {
    function watchAnswers(cookieName, exercises) {
        var myAnswers = JSON.parse(window.localStorage.getItem(cookieName) || "{}");

        for (var i=0; i<exercises.length; i++) {
            var exercise=exercises[i];
            var myAnswer=myAnswers[exercise.id];
            if (myAnswer) {
                exercise.myResult=myAnswer;
            }
        }

        exercises.onChange(function (evt) {
            switch (evt.target.__name) {
                case 'myResult':
                    var target=evt.target.__parent;
                    if (target) {
                        myAnswers[target.id]=target.myResult;
                    }
                    break;
                case 'exercises':
                    myAnswers={};
            }
            window.localStorage.setItem(cookieName, JSON.stringify(myAnswers));
        });
    }
    return watchAnswers;
});

Allow to clear the answers


var ngAnnotate = require('ng-annotate');
var utils = require('loader-utils');
var SourceMapConsumer = require('source-map').SourceMapConsumer;
var SourceMapGenerator = require('source-map').SourceMapGenerator;

module.exports = function(source, sm) {
  this.cacheable && this.cacheable();
  var filename = utils.getCurrentRequest(this);

  var res = ngAnnotate(source, {
      add: true,
      sourcemap: {inline: false, inFile: filename, sourceRoot: filename}
    }
  );

  var mergeMap;
  if (sm) {
    var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(sm));
    if (res.map) {
      generator.applySourceMap(new SourceMapConsumer(res.map), filename);
      mergeMap = generator.toString();
    } else {
      mergeMap = sm;
    }
  }

  this.callback(null, res.src || source, mergeMap);
};

var ngAnnotate = require('ng-annotate');
var utils = require('loader-utils');
var SourceMapConsumer = require('source-map').SourceMapConsumer;
var SourceMapGenerator = require('source-map').SourceMapGenerator;

function isEmpty(obj) {
    return Object.keys(obj).length === 0;
}

function getOptions(sourceMapEnabled) {
    var defaults = { add: true };

    var options = this.query ? utils.parseQuery(this.query) : defaults;

    if (sourceMapEnabled && options.sourcemap === undefined) {
        var filename = utils.getCurrentRequest(this);
        options.sourcemap = {inline: false, inFile: filename, sourceRoot: filename};
    }

    return options;
}

module.exports = function(source, sm) {
  var sourceMapEnabled = this.sourceMap;
  this.cacheable && this.cacheable();

  var res = ngAnnotate(source, getOptions.call(this, sourceMapEnabled));

  var mergeMap;

  if (sourceMapEnabled && sm) {
    var generator = SourceMapGenerator.fromSourceMap(new SourceMapConsumer(sm));
    if (res.map) {
      generator.applySourceMap(new SourceMapConsumer(res.map), filename);
      mergeMap = generator.toString();
    } else {
      mergeMap = sm;
    }
  }

  this.callback(null, res.src || source, mergeMap);
};

Support configuration via query params


var _ = require('lodash');
var loaderUtils = require('loader-utils');

module.exports = function (source) {
  'use strict';
  if (this.cacheable) {
    this.cacheable();
  }
  var allLoadersButThisOne = this.loaders.filter(function(loader) {
    return loader.module !== module.exports;
  });
  // This loader shouldn't kick in if there is any other loader
  if (allLoadersButThisOne.length > 0) {
    return source;
  }
  // Use underscore for a minimalistic loader
  var options = loaderUtils.parseQuery(this.query);
  var template = _.template(source, options);
  return 'module.exports = ' + template;
};

'use strict';

var _ = require('lodash');
var loaderUtils = require('loader-utils');

module.exports = function (source) {
  if (this.cacheable) {
    this.cacheable();
  }
  var allLoadersButThisOne = this.loaders.filter(function(loader) {
    return loader.module !== module.exports;
  });
  // This loader shouldn't kick in if there is any other loader
  if (allLoadersButThisOne.length > 0) {
    return source;
  }
  // Use underscore for a minimalistic loader
  var options = loaderUtils.parseQuery(this.query);
  var template = _.template(source, options);
  return 'module.exports = ' + template;
};

Add missing use strict statements