import Bounds from './Bounds';
import GroupItem from './GroupItem';

export default function Scenegraph() {
  this.root = createMark({
    marktype: 'group',
    interactive: false
  });
  this.root.items = [new GroupItem(this.root)];
}

var prototype = Scenegraph.prototype;

prototype.select = function(path, markdef) {
  var items = this.root.items[0],
      node, i, n;

  for (i=0, n=path.length-1; i<n; ++i) {
    items = items.items[path[i]];
    if (!items) error('Invalid scenegraph path: ' + path);
  }
  items = items.items;

  if (!(node = items[path[n]])) {
    if (markdef) items[path[n]] = node = createMark(markdef);
    else error('Invalid scenegraph path: ' + path);
  }

  return node;
};

function error(msg) {
  throw Error(msg);
}

function createMark(def) {
  return {
    bounds:      new Bounds(),
    clip:        !!def.clip,
    interactive: def.interactive === false ? false : true,
    items:       [],
    marktype:    def.marktype,
    name:        def.name || undefined,
    role:        def.role || undefined
  };
}

import Bounds from './Bounds';
import GroupItem from './GroupItem';

export default function Scenegraph() {
  this.root = createMark({
    marktype: 'group',
    interactive: false
  });
  this.root.items = [new GroupItem(this.root)];
}

var prototype = Scenegraph.prototype;

prototype.select = function(path, markdef) {
  var group = this.root.items[0],
      mark = group.items[path[0]],
      i, n;

  try {
    for (i=1, n=path.length-1; i<n; ++i) {
      group = mark.items[path[i++]];
      mark = group.items[path[i]];
    }

    if (!mark && !markdef) throw n;

    if (markdef) {
      mark = createMark(markdef, group);
      group.items[path[n]] = mark;
    }

    return mark;
  } catch (err) {
    error('Invalid scenegraph path: ' + path);
  }
};

function error(msg) {
  throw Error(msg);
}

function createMark(def, group) {
  return {
    bounds:      new Bounds(),
    clip:        !!def.clip,
    group:       group,
    interactive: def.interactive === false ? false : true,
    items:       [],
    marktype:    def.marktype,
    name:        def.name || undefined,
    role:        def.role || undefined
  };
}

Add group reference to new mark instances.


import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'

// create the saga middleware
export const sagaMiddleware = createSagaMiddleware()

const composeEnhancers =
  process.env.NODE_ENV !== 'production' &&
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__()
    : compose

// mount it on the Store
const store = createStore(
  reducer,
  composeEnhancers(
    applyMiddleware(sagaMiddleware)
  )
)

export default store

import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'

import reducer from './reducers'

// create the saga middleware
export const sagaMiddleware = createSagaMiddleware()

const composeEnhancers =
  process.env.NODE_ENV !== 'production' &&
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
    : compose

// mount it on the Store
const store = createStore(
  reducer,
  composeEnhancers(
    applyMiddleware(sagaMiddleware)
  )
)

export default store

Remove brackets for correct function of devel mode


import React, { Component, PropTypes } from 'react'
import ReactDOM from 'react-dom'
import ReactDOMServer from 'react-dom/server'
import SVGInjector from 'svg-injector'

export default class ReactSVG extends Component {

  static defaultProps = {
    callback: () => {},
    className: '',
    evalScripts: 'once',
    style: {}
  }

  static propTypes = {
    callback: PropTypes.func,
    className: PropTypes.string,
    evalScripts: PropTypes.oneOf([ 'always', 'once', 'never' ]),
    path: PropTypes.string.isRequired,
    style: PropTypes.object
  }

  renderSVG(props = this.props) {
    const {
      callback: each,
      className,
      evalScripts,
      path,
      style
    } = props

    this.container = this.container || ReactDOM.findDOMNode(this)

    const div = document.createElement('div')
    div.innerHTML = ReactDOMServer.renderToStaticMarkup(
      <img
        className={className}
        data-src={path}
        style={style}
      />
    )

    const img = this.container.appendChild(div.firstChild)

    SVGInjector(img, {
      evalScripts,
      each
    })
  }

  removeSVG() {
    this.container.removeChild(this.container.firstChild)
  }

  componentDidMount() {
    this.renderSVG()
  }

  componentWillReceiveProps(nextProps) {
    this.removeSVG()
    this.renderSVG(nextProps)
  }

  shouldComponentUpdate() {
    return false
  }

  componentWillUnmount() {
    this.removeSVG()
  }

  render() {
    return <div />
  }

}

import React, { Component, PropTypes } from 'react'
import ReactDOMServer from 'react-dom/server'
import SVGInjector from 'svg-injector'

export default class ReactSVG extends Component {

  static defaultProps = {
    callback: () => {},
    className: '',
    evalScripts: 'once',
    style: {}
  }

  static propTypes = {
    callback: PropTypes.func,
    className: PropTypes.string,
    evalScripts: PropTypes.oneOf([ 'always', 'once', 'never' ]),
    path: PropTypes.string.isRequired,
    style: PropTypes.object
  }

  refCallback = (container) => {
    if (!container) {
      this.removeSVG()
      return
    }

    this.container = container
    this.renderSVG()
  }

  renderSVG(props = this.props) {
    const {
      callback: each,
      className,
      evalScripts,
      path,
      style
    } = props

    const div = document.createElement('div')
    div.innerHTML = ReactDOMServer.renderToStaticMarkup(
      <img
        className={className}
        data-src={path}
        style={style}
      />
    )

    const img = this.container.appendChild(div.firstChild)

    SVGInjector(img, {
      evalScripts,
      each
    })
  }

  removeSVG() {
    this.container.removeChild(this.container.firstChild)
  }

  componentWillReceiveProps(nextProps) {
    this.removeSVG()
    this.renderSVG(nextProps)
  }

  shouldComponentUpdate() {
    return false
  }

  render() {
    return <div ref={this.refCallback} />
  }

}

Handle mounting and unmounting via ref callback


/**
 * External imports
 */
import koa from 'koa';
import route from 'koa-route';
import libdebug from 'debug';

// create debug logger
const debug = libdebug('lgho:root');

/**
 * Routes
 */
function* root() {
  this.response.status = 200;
}

export default function create(options = {}) {
  debug('options %j', options);

  return koa()
  .use(route.get('/', root));
}

/**
 * External imports
 */
import route from 'koa-route';
import createDebugLogger from 'debug';
import createKoaApplication from 'koa';

// create debug logger
const log = createDebugLogger('lgho:root');

/**
 * Routes
 */
function* root() {
  this.response.body = {
    'let go': null,
    'hold on': null,
  };
  this.response.status = 200;
}

export default function create(options = {}) {
  log('options %j', options);

  return createKoaApplication()
  .use(route.get('/', root));
}

Update root route to respond with hold-on/let-go object.


import pluralize, { singular } from 'pluralize';

function normalize(slug: string): string {
  return singular(slug.toLowerCase()).replace(/(-|_|\.|\s)+/g, '_');
}

function urlify(slug: string): string {
  return pluralize(slug).replace('_', '-');
}

const formats = {
  pascal(slug: string): string {
    return slug
      .split('_')
      .map(word => `${word.charAt(0).toUpperCase()}${word.substr(1)}`)
      .join(' ');
  },
  camel(slug: string): string {
    const splitSlug = slug.split('_');

    return [
      splitSlug[0],
      formats.pascal(splitSlug.slice(1).join('_')).replace(' ', ''),
    ].join('');
  },
};

export default function slugizoid(slug: string = ''): string {
  const _original = slug;
  const _normalized = normalize(slug);

  return {
    toString(options: { format: 'pascal' | 'camel', plural: boolean }): string {
      const { format, plural } = Object.assign(
        { format: 'pascal', plural: false },
        options
      );

      return (plural ? pluralize : singular)(formats[format](_normalized));
    },

    equals(slug: string): boolean {
      return normalize(slug) === _normalized;
    },

    slugify(): string {
      return _normalized;
    },

    urlify(): string {
      return urlify(_normalized);
    },
  };
}

import pluralize, { singular } from 'pluralize';

function normalize(slug: string): string {
  return singular(slug.toLowerCase()).replace(/(-|_)+/g, '_');
}

function urlify(slug: string): string {
  return pluralize(slug).replace('_', '-');
}

const formats = {
  pascal(slug: string): string {
    return slug
      .split('_')
      .map(word => `${word.charAt(0).toUpperCase()}${word.substr(1)}`)
      .join(' ');
  },
  camel(slug: string): string {
    const splitSlug = slug.split('_');

    return [
      splitSlug[0],
      formats.pascal(splitSlug.slice(1).join('_')).replace(' ', ''),
    ].join('');
  },
};

export default function slugizoid(slug: string = ''): string {
  const _original = slug;
  const _normalized = normalize(slug);

  return {
    toString(options: { format: 'pascal' | 'camel', plural: boolean }): string {
      const { format, plural } = Object.assign(
        { format: 'pascal', plural: false },
        options
      );

      return (plural ? pluralize : singular)(formats[format](_normalized));
    },

    equals(slug: string): boolean {
      return normalize(slug) === _normalized;
    },

    slugify(): string {
      return _normalized;
    },

    urlify(): string {
      return urlify(_normalized);
    },
  };
}

Remove whitespace and '.' delims


import express from 'express';
import leagueTips from 'league-tooltips';
import runTask from './cronTask';
import taskGenerator from './cronTasks/generator';
import config from './config';
import routes from './routes';

// ==== Server ====

const app = express();

app.use(leagueTips(config.key.riot, 'euw', {
  url: '/tooltips',
  fileName: 'league-tips.min.js',
  protocol: 'https',
  cors: {
    origin: 'https://lol-item-sets-generator.org/',
    methods: 'GET',
    headers: 'Content-Type'
  }
}));

app.use('/sprites', routes.sprites);
app.use('/tooltips', routes.tooltips);
app.use('/', routes.index);

app.listen(config.port, () => {
  console.log('[SERVER] Listening on port ' + config.port);
});

// ==== Generator ====

const version = require('../package.json').version;
console.log(`[GENERATOR] Generator version : ${version}.`);

runTask(taskGenerator, config.cron);

import express from 'express';
import leagueTips from 'league-tooltips';
import runTask from './cronTask';
import taskGenerator from './cronTasks/generator';
import config from './config';
import routes from './routes';

// ==== Server ====

const app = express();

app.use(leagueTips(config.key.riot, 'euw', {
  url: '/tooltips',
  fileName: 'league-tips.min.js',
  protocol: 'https',
  cors: {
    origin: 'https://lol-item-sets-generator.org',
    methods: 'GET',
    headers: 'Content-Type'
  }
}));

app.use('/sprites', routes.sprites);
app.use('/tooltips', routes.tooltips);
app.use('/', routes.index);

app.listen(config.port, () => {
  console.log('[SERVER] Listening on port ' + config.port);
});

// ==== Generator ====

const version = require('../package.json').version;
console.log(`[GENERATOR] Generator version : ${version}.`);

runTask(taskGenerator, config.cron);

Fix CORS allowed origin typo.


import fs from 'fs'
import _ from 'lodash'
import postcss from 'postcss'
import stylefmt from 'stylefmt'

import defaultConfig from './defaultConfig'
import mergeConfig from './util/mergeConfig'

import generateUtilities from './lib/generateUtilities'
import substituteHoverableAtRules from './lib/substituteHoverableAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import substituteBreakpointAtRules from './lib/substituteBreakpointAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'

const plugin = postcss.plugin('tailwind', (options = {}) => {
  if (_.isFunction(options)) {
    options = options()
  }

  const config = mergeConfig(defaultConfig, options)

  return postcss([
    generateUtilities(config),
    substituteHoverableAtRules(config),
    substituteResponsiveAtRules(config),
    substituteBreakpointAtRules(config),
    substituteClassApplyAtRules(config),
    stylefmt,
  ])
})

module.exports = plugin

import fs from 'fs'
import _ from 'lodash'
import postcss from 'postcss'
import stylefmt from 'stylefmt'

import defaultConfig from './defaultConfig'
import mergeConfig from './util/mergeConfig'

import generateUtilities from './lib/generateUtilities'
import substituteHoverableAtRules from './lib/substituteHoverableAtRules'
import substituteResponsiveAtRules from './lib/substituteResponsiveAtRules'
import substituteBreakpointAtRules from './lib/substituteBreakpointAtRules'
import substituteClassApplyAtRules from './lib/substituteClassApplyAtRules'

const plugin = postcss.plugin('tailwind', (options = {}) => {
  const config = mergeConfig(defaultConfig, options)

  return postcss([
    generateUtilities(config),
    substituteHoverableAtRules(config),
    substituteResponsiveAtRules(config),
    substituteBreakpointAtRules(config),
    substituteClassApplyAtRules(config),
    stylefmt,
  ])
})

module.exports = plugin

Revert "Allow passing config as lazy-evaluated function"


'use strict';

import 'source-map-support/register';
import http from 'http';
import express from 'express';
import RED from 'node-red';

// Create an Express app
let app = express();

// Create a server
let server = http.createServer(app);

// Create the settings object - see default settings.js file for other options
let settings = {
  verbose: true,
  disableEditor: false,
  httpAdminRoot: '/red',
  httpNodeRoot: '/api',
  userDir: (process.env.HOME || process.env.USERPROFILE) + '/.node-red',
  functionGlobalContext: { }    // enables global context
};

// Initialise the runtime with a server and settings
RED.init(server, settings);

// Add a simple route for static content served from 'public'
app.use('/', express.static('public'));
if (settings.httpAdminRoot) {
  app.get('/', (_, res) => {
    res.redirect(settings.httpAdminRoot);
  });
}

// Serve the editor UI from /red
app.use(settings.httpAdminRoot, RED.httpAdmin);

// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot, RED.httpNode);

server.listen(8000);

// Start the runtime
RED.start();

'use strict';

import 'source-map-support/register';
import http from 'http';
import express from 'express';
import RED from 'node-red';

// Exit handler
process.stdin.resume();
function exitHandler(err) {
  if (err instanceof Error) {
    console.log(err.stack);
    process.exit(1);
  } else if (isNaN(err)) {
    process.exit();
  } else {
    process.exit(err);
  }
}
process.on('exit', exitHandler);
process.on('SIGINT', exitHandler);
process.on('uncaughtException', exitHandler);

// Create an Express app
let app = express();

// Create a server
let server = http.createServer(app);

// Create the settings object - see default settings.js file for other options
let settings = {
  verbose: true,
  disableEditor: false,
  httpAdminRoot: '/red',
  httpNodeRoot: '/api',
  userDir: (process.env.HOME || process.env.USERPROFILE) + '/.node-red',
  functionGlobalContext: { }    // enables global context
};

// Initialise the runtime with a server and settings
RED.init(server, settings);

// Add a simple route for static content served from 'public'
app.use('/', express.static('public'));
if (settings.httpAdminRoot) {
  app.get('/', (_, res) => {
    res.redirect(settings.httpAdminRoot);
  });
}

// Serve the editor UI from /red
app.use(settings.httpAdminRoot, RED.httpAdmin);

// Serve the http nodes UI from /api
app.use(settings.httpNodeRoot, RED.httpNode);

server.listen(8000);

// Start the runtime
RED.start();

Add the process exit handler to perform finalization process


import AsyncStorage from '@react-native-community/async-storage';
import { persistStore, persistReducer } from 'redux-persist';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { createReactNavigationReduxMiddleware } from 'react-navigation-redux-helpers';
import reducers from './reducers';

// Create middleware and connect
const appNavigatorMiddleware = createReactNavigationReduxMiddleware(state => state.nav, 'root');

const persistConfig = {
  keyPrefix: '',
  key: 'root',
  storage: AsyncStorage,
  blacklist: [
    'nav',
    'pages',
    'user',
    'prescription',
    'patient',
    'form',
    'prescriber',
    'wizard',
    'payment',
  ],
};

const persistedReducer = persistReducer(persistConfig, reducers);

const store = createStore(persistedReducer, {}, applyMiddleware(thunk, appNavigatorMiddleware));

const persistedStore = persistStore(store);

export { store, persistedStore };

import AsyncStorage from '@react-native-community/async-storage';
import { persistStore, persistReducer } from 'redux-persist';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { createReactNavigationReduxMiddleware } from 'react-navigation-redux-helpers';
import reducers from './reducers';

// Create middleware and connect
const appNavigatorMiddleware = createReactNavigationReduxMiddleware(state => state.nav, 'root');

const persistConfig = {
  keyPrefix: '',
  key: 'root',
  storage: AsyncStorage,
  blacklist: [
    'nav',
    'pages',
    'user',
    'prescription',
    'patient',
    'form',
    'prescriber',
    'wizard',
    'payment',
    'insurance',
  ],
};

const persistedReducer = persistReducer(persistConfig, reducers);

const store = createStore(persistedReducer, {}, applyMiddleware(thunk, appNavigatorMiddleware));

const persistedStore = persistStore(store);

export { store, persistedStore };

Add insurance shape to blacklist


import _merge from 'lodash/merge'
import moment from 'moment'

let today = moment().format('YYYY-MM-DD')

export default {
  loading: true,
  schedule: {},
  // Restore saved preferences to over default lunches and classes
  lunches: _merge({ 'Monday': 1, 'Tuesday': 1, 'Wednesday': 1, 'Thursday': 1, 'Friday': 1 },
    JSON.parse(localStorage.getItem('lunches')) || {}),
  classes: _merge({ 1: '', 2: '', 3: '', 4: '', 5: '', 6: '', 7: '' },
    JSON.parse(localStorage.getItem('classes')) || {}),
  // Design constants
  colors: ['#3F51B5', '#1976D2', '#03A9F4', '#00BCD4', '#009688', '#4CAF50', '#8BC34A'],
  // Check if client is crawler so it doesn't see a countdown in the title!
  isCrawler: /bot|googlebot|crawler|spider|robot|crawling/i.test(navigator.userAgent),
  // Set default dates to determine week to display
  displayDate: today, today,
  // Set default countdown so checking each blocks begins with the first one
  countdown: { i: 0 },
  // Queue for next countdown call (a timeout Promise)
  queue: null
}

import _merge from 'lodash/merge'
import moment from 'moment'

let today = moment().format('YYYY-MM-DD')

export default {
  loading: true,
  schedule: {},
  // Restore saved preferences to over default lunches and classes
  lunches: _merge({ 'Monday': 1, 'Tuesday': 1, 'Wednesday': 1, 'Thursday': 1, 'Friday': 1 },
    JSON.parse(localStorage.getItem('lunches')) || {}),
  classes: _merge({ 1: '', 2: '', 3: '', 4: '', 5: '', 6: '', 7: '' },
    JSON.parse(localStorage.getItem('classes')) || {}),
  // Design constants
  colors: ['#3F51B5', '#1976D2', '#039BE5', '#00BCD4', '#009688', '#43A047', '#7CB342'],
  // Check if client is crawler so it doesn't see a countdown in the title!
  isCrawler: /bot|googlebot|crawler|spider|robot|crawling/i.test(navigator.userAgent),
  // Set default dates to determine week to display
  displayDate: today, today,
  // Set default countdown so checking each blocks begins with the first one
  countdown: { i: 0 },
  // Queue for next countdown call (a timeout Promise)
  queue: null
}

Modify block colors for greater contrast


const baseConfig = require('tdd-buffet/config/jest.config');
const path = require('path');
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('../tsconfig');

const rootDir = path.join(__dirname, '../');

module.exports = {
  ...baseConfig,

  rootDir,
  // For some reason Jest will complain that this is duplicating the packages/mugshot/package.json.
  modulePathIgnorePatterns: ['<rootDir>/package.json'],
  moduleNameMapper: {
    ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/packages/' }),
    // For some reason the ts-jest helper doesn't pick this one up.
    '^mugshot/(.*)$': '<rootDir>/packages/mugshot/$1'
  }
};

const baseConfig = require('tdd-buffet/config/jest.config');
const path = require('path');
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('../tsconfig');

const rootDir = path.join(__dirname, '../');

module.exports = {
  ...baseConfig,

  rootDir,
  // For some reason Jest will complain that this is duplicating the packages/mugshot/package.json.
  modulePathIgnorePatterns: ['<rootDir>/package.json'],
  moduleNameMapper: {
    ...pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/packages/' }),
    // For some reason the ts-jest helper doesn't pick this one up.
    '^mugshot/(.*)$': '<rootDir>/packages/mugshot/$1'
  },

  // We're doing multiple coverage runs so we don't want to print the table every time
  // and we want to check thresholds once at the end with nyc.
  coverageReporters: ['json', 'html'],
  coverageThreshold: undefined
};

Check coverage at the end


import * as components from './components'

import config, { setOptions } from './utils/config'
import { use, registerComponentProgrammatic } from './utils/plugins'

const Buefy = {
    install(Vue, options = {}) {
        // Options
        setOptions(Object.assign(config, options))
        // Components
        for (let componentKey in components) {
            Vue.use(components[componentKey])
        }
        // Config component
        const BuefyProgrammatic = {
            setOptions(options) {
                setOptions(Object.assign(config, options))
            }
        }
        registerComponentProgrammatic(Vue, '$buefy', BuefyProgrammatic)
    }
}

use(Buefy)

export default Buefy

export * from './components'

Add export all components in src


var coffeeScript = require("coffee-script");

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

commands.register({
    id: "coffeescript.preview",
    title: "CoffeeScript: Preview",
    context: ["editor"],
    shortcuts: [
        "ctrl+shift+c"
    ],
    run: function(args, context) {
        var name = context.model.get("name").replace(context.model.getExtension(), ".js");
        var code, error;

        try {
            code = coffeeScript.compile(context.getContent());
        } catch (e) {
            error = e;
            code = e.toString();
            name = "Error at compilation";
        }

        var f = File.buffer(name, code);
        return commands.run("file.open", {
            file: f
        })
        .then(function() {
            if (error) throw error;
        });
    }
});

var coffeeScript = require("coffee-script");

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

commands.register({
    id: "coffeescript.preview",
    title: "CoffeeScript: Preview",
    context: ["editor"],
    shortcuts: [
        "ctrl+shift+c"
    ],
    run: function(args, ctx) {
        var name = ctx.editor.model.get("name").replace(ctx.editor.model.getExtension(), ".js");
        var code, error;

        try {
            code = coffeeScript.compile(ctx.editor.getContent());
        } catch (e) {
            error = e;
            code = e.toString();
            name = "Error at compilation";
        }

        var f = File.buffer(name, code);
        return commands.run("file.open", {
            file: f
        })
        .then(function() {
            if (error) throw error;
        });
    }
});

Use new multiple cmd contexts


import React from "react";
import ReactDOM from "react-dom";
import { RoutingApp } from "./modules/RoutingApp";
import store from "./store";
import { Provider } from "react-redux";
import { STUY_SPEC_API_URL } from "./constants";

import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

import { objectFilter } from "./utils";

const apolloClient = new ApolloClient({
  link: new HttpLink({ uri: `${STUY_SPEC_API_URL}/graphql` }),
  cache: new InMemoryCache(),
});

Object.filter = objectFilter;

const App = () => (
  <Provider store={store}>
    <ApolloProvider client={apolloClient}>
      <RoutingApp />
    </ApolloProvider>
  </Provider>
);

ReactDOM.render(
  <App />,
  document.getElementById("app"),
);

import React from "react";
import ReactDOM from "react-dom";
import { RoutingApp } from "./modules/RoutingApp";
import store from "./store";
import { Provider } from "react-redux";
import { STUY_SPEC_API_URL } from "./constants";

import { ApolloProvider } from "react-apollo";
import { ApolloClient } from "apollo-client";
import { HttpLink } from "apollo-link-http";
import { InMemoryCache } from "apollo-cache-inmemory";

import { objectFilter } from "./utils";

const apolloClient = new ApolloClient({
  link: new HttpLink({ uri: `${STUY_SPEC_API_URL}/graphql` }),
  cache: new InMemoryCache(),
  connectToDevTools: true
});

Object.filter = objectFilter;

const App = () => (
  <Provider store={store}>
    <ApolloProvider client={apolloClient}>
      <RoutingApp />
    </ApolloProvider>
  </Provider>
);

ReactDOM.render(
  <App />,
  document.getElementById("app"),
);

Enable Apollo devtools in production


var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    './app/index.js'
  ],
  output: {
    path: __dirname + '/dist',
    filename: "index_bundle.js"
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    ]
  },
  plugins: [HtmlWebpackPluginConfig],
  debug: true,
  devtool: '#eval-source-map'
}

var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    './app/index.js'
  ],
  output: {
    path: __dirname + '/dist',
    filename: "index_bundle.js"
  },
  module: {
    loaders: [
      { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" },
      { test: /\.css$/, loader: "style-loader!css-loader" }
    ]
  },
  plugins: [HtmlWebpackPluginConfig],
  debug: true,
  devtool: '#eval-source-map'
}

Load style-loader and css-loader into webpack making require css possible


/*
    Copyright 2015 Leafbird

  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.
*/

describe('configure', function() {
  it('Confugure changes on original config.', function() {
    var leafbrd = Leafbird({});
    leafbrd.configure({});
    expect(leafbrd.config).toEqual(undefined);
  });
});

/*
    Copyright 2015 Leafbird

  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.
*/

describe('configure', function() {
  it('Confugure changes on original config.', function() {
    var leafbrd = Leafbird({});
    leafbrd.configure({});
    expect(leafbrd.config).toEqual(undefined);
  });

  it('verify if a leafbird global object has defined', function(){
    expect(leafbird).toBeDefined();
  });
});

Verify if leafbird variable has defined on the global scope


$(document).ready(function(){
  var arrayOfColumnNames = [
    "c0",
    "c1",
    "c2",
    "c3",
    "c4",
    "c5",
    "c6",
  ];

  for (var i=0; i<7; i++) {
    $("#board").append("

");

    // console.log($('#' + arrayOfColumnNames[i]));
    var thisColumn = $('#' + arrayOfColumnNames[i]);

    for (var j=0; j<6; j++) {
      $('#' + arrayOfColumnNames[i]).append("

");
    }
  }

});

$(document).ready(function(){
  var arrayOfColumnNames = [
    "c0",
    "c1",
    "c2",
    "c3",
    "c4",
    "c5",
    "c6",
  ];

  for (var i=0; i<7; i++) {
    $("#board").append("

");

    // console.log($('#' + arrayOfColumnNames[i]));
    var thisColumn = $('#' + arrayOfColumnNames[i]);

    for (var j=5; j>=0; j--) {
      $('#' + arrayOfColumnNames[i]).append("

");
    }
  }

  var board = [
    [],
    [],
    [],
    [],
    [],
    [],
    []
  ];

  var turns = 0;

  $('.column-div').on('click', function(){
    //gives us column that was clicked on
    var column = parseInt($(this).attr('id').slice(-1));
    //alternates red and black pieces depending on turn count
    if (board[column].length < 6){
      turns += 1;
      var color = (turns % 2) ? "red" : "black";
      //adds piece to board
      board[column].push(color);
      var row = board[column].length - 1;
      $('#c' + column + '-' + row).css('background-color', color);
    }
    console.log(board);
  });

});

Add pieces to the board


import React, { Component } from "react";
import PropTypes from "prop-types";
import BUI, { VaultProvider, VaultUI } from "@buttercup/ui";

class VaultPage extends Component {
    static propTypes = {
        sourceID: PropTypes.string.isRequired,
        vault: PropTypes.object
    };

    state = {
        masterPassword: ""
    };

    componentDidMount() {
        this.props.fetchVaultFacade(this.props.sourceID);
    }

    render() {
        console.log("COMPS", BUI);
        return (

                <Choose>
                    <When condition={this.props.vault}>
                        <VaultProvider vault={this.props.vault} onUpdate={() => {}}>
                            <VaultUI />
                        </VaultProvider>
                    </When>
                    <Otherwise>
                        Loading...
                    </Otherwise>
                </Choose>

        );
    }
}

export default VaultPage;

import React, { Component } from "react";
import PropTypes from "prop-types";
import { VaultProvider, VaultUI } from "@buttercup/ui";

class VaultPage extends Component {
    static propTypes = {
        sourceID: PropTypes.string.isRequired,
        vault: PropTypes.object
    };

    state = {
        masterPassword: ""
    };

    componentDidMount() {
        this.props.fetchVaultFacade(this.props.sourceID);
    }

    render() {
        return (

                <Choose>
                    <When condition={this.props.vault}>
                        <VaultProvider vault={this.props.vault} onUpdate={() => {}}>
                            <VaultUI />
                        </VaultProvider>
                    </When>
                    <Otherwise>
                        Loading...
                    </Otherwise>
                </Choose>

        );
    }
}

export default VaultPage;

Remove testing for vault ui


var links = inDocument.getElementsByTagName('a');

var candidateLinks = $A(links).select(function(candidateLink) {
  var textMatched   = PatternMatcher.matches(locator, getText(candidateLink));
  var idMatched     = PatternMatcher.matches(locator, candidateLink.id);
  var titleMatched  = PatternMatcher.matches(locator, candidateLink.title);

  return textMatched || idMatched || titleMatched;
});

if (candidateLinks.length == 0) {
  return null;
}

//reverse length sort
candidateLinks = candidateLinks.sortBy(function(s) {
  return s.length * -1;
});

return candidateLinks.first();

var links = inDocument.getElementsByTagName('a');

var candidateLinks = $A(links).select(function(candidateLink) {
  var textMatched = false;
  var titleMatched = false;
  var idMatched = false;

  if (getText(candidateLink).toLowerCase().indexOf(locator.toLowerCase()) != -1) {
    textMatched = true;
  }

  if (candidateLink.title.toLowerCase().indexOf(locator.toLowerCase()) != -1) {
    titleMatched = true;
  }

  if (candidateLink.id.toLowerCase().indexOf(locator.toLowerCase()) != -1) {
    idMatched = true;
  }

  return textMatched || idMatched || titleMatched;
});

if (candidateLinks.length == 0) {
  return null;
}

//reverse length sort
candidateLinks = candidateLinks.sortBy(function(s) {
  return s.length * -1;
});

return candidateLinks.first();

Make link location in Selenium more reliable and consistent with non-Selenium


var TC = require('tangram.cartodb');
var LeafletLayerView = require('./leaflet-layer-view');

var LeafletCartoDBVectorLayerGroupView = window.L.TileLayer.extend({
  includes: [
    LeafletLayerView.prototype
  ],

  options: {
    minZoom: 0,
    maxZoom: 28,
    tileSize: 256,
    zoomOffset: 0,
    tileBuffer: 50
  },

  events: {
    featureOver: null,
    featureOut: null,
    featureClick: null
  },

  initialize: function (layerGroupModel, map) {
    LeafletLayerView.call(this, layerGroupModel, this, map);
    layerGroupModel.bind('change:urls', this._onURLsChanged, this);

    this.tangram = new TC(map);

    layerGroupModel.each(this._onLayerAdded, this);
    layerGroupModel.onLayerAdded(this._onLayerAdded.bind(this));
  },

  onAdd: function (map) {

  },

  _onLayerAdded: function (layer) {
    var self = this;
    layer.bind('change:meta', function (e) {
      self.tangram.addLayer(e.attributes);
    });
  },

  _onURLsChanged: function (e, res) {
    this.tangram.addDataSource(res.tiles[0]);
  }
});

module.exports = LeafletCartoDBVectorLayerGroupView;

var TC = require('tangram.cartodb');
var LeafletLayerView = require('./leaflet-layer-view');
var L = require('leaflet');

var LeafletCartoDBVectorLayerGroupView = L.Layer.extend({
  includes: [
    LeafletLayerView.prototype
  ],

  options: {
    minZoom: 0,
    maxZoom: 28,
    tileSize: 256,
    zoomOffset: 0,
    tileBuffer: 50
  },

  events: {
    featureOver: null,
    featureOut: null,
    featureClick: null
  },

  initialize: function (layerGroupModel, map) {
    LeafletLayerView.call(this, layerGroupModel, this, map);
    layerGroupModel.bind('change:urls', this._onURLsChanged, this);

    this.tangram = new TC(map);

    layerGroupModel.each(this._onLayerAdded, this);
    layerGroupModel.onLayerAdded(this._onLayerAdded.bind(this));
  },

  onAdd: function (map) {
    L.Layer.prototype.onAdd.call(this, map);
  },

  _onLayerAdded: function (layer) {
    var self = this;
    layer.bind('change:meta', function (e) {
      self.tangram.addLayer(e.attributes);
    });
  },

  _onURLsChanged: function (e, res) {
    this.tangram.addDataSource(res.tiles[0]);
  }
});

module.exports = LeafletCartoDBVectorLayerGroupView;

Extend from the proper layer


function Mixin(proto, properties) {
  for (const property in properties) {
    const value = properties[property];
    if (proto[property] && typeof value == "function") {
      inherit(proto, property, value);
    } else {
      proto[property] = value;
    }
  }
}

function inherit(proto, name, func) {
  var parentFunc = proto[name];
  proto[name] = function () {
    var old = this.callParent;
    this.callParent = parentFunc;
    var ret = func.apply(this, arguments);
    if (old) {
      this.callParent = old;
    }
    return ret;
  };
}

module.exports = Mixin;

function Mixin(proto, properties) {
  for (const property in properties) {
    const value = properties[property];
    if (proto[property] && typeof value == "function") {
      inherit(proto, property, value);
    } else {
      proto[property] = value;
    }
  }
}

function inherit(proto, property, func) {
  var parentFunc = proto[property];
  proto[property] = function () {
    var old = this.callParent;
    this.callParent = parentFunc;
    var ret = func.apply(this, arguments);
    if (old) {
      this.callParent = old;
    }
    return ret;
  };
}

module.exports = Mixin;

Make name `name` match in `inherit` helper


importScripts('common.js');

function continuouslyGenerateRsaKey()
{
    var extractable = false;
    var usages = ['encrypt', 'decrypt'];
    // Note that the modulus length is small.
    var algorithm = {name: "RSAES-PKCS1-v1_5", modulusLength: 512, publicExponent: hexStringToUint8Array("010001")};

    return crypto.subtle.generateKey(algorithm, extractable, usages).then(function(result) {
        // Infinite recursion intentional!
        return continuouslyGenerateRsaKey();
    });
}

// Starts a Promise which continually generates new RSA keys.
var unusedPromise = continuouslyGenerateRsaKey();

// Inform the outer script that the worker started.
postMessage("Worker started");

importScripts('common.js');

function continuouslyGenerateRsaKey()
{
    var extractable = false;
    var usages = ['sign', 'verify'];
    // Note that the modulus length is small.
    var algorithm = {name: "RSASSA-PKCS1-v1_5", modulusLength: 512, publicExponent: hexStringToUint8Array("010001"), hash: {name: 'sha-1'}};

    return crypto.subtle.generateKey(algorithm, extractable, usages).then(function(result) {
        // Infinite recursion intentional!
        return continuouslyGenerateRsaKey();
    });
}

// Starts a Promise which continually generates new RSA keys.
var unusedPromise = continuouslyGenerateRsaKey();

// Inform the outer script that the worker started.
postMessage("Worker started");

Remove a lingering usage of RSA-ES.


// @flow

import * as t from '@babel/types'

// Empty out bodies of falsy parts of if/else statements
// to avoid requiring modules that aren't needed aka
// if (process.env.NODE_ENV === 'production') module.exports = require('./prod-version') else module.exports = require('./dev-version')
// OR
// module.exports = process.env.NODE_ENV === 'production' ? require('./prod-version') : require('./dev-version')

function processBooleanConditional(path: $FlowFixMe) {
  const { node } = path

  if (!t.isBooleanLiteral(node.test)) return

  function visitIfNode(leafNode) {
    if (!t.isBooleanLiteral(leafNode.test)) return
    const { test, consequent, alternate } = node

    if (test.value) {
      path.replaceWithMultiple(consequent.body)
      return
    }
    node.consequent.body = []
    if (t.isIfStatement(alternate)) {
      visitIfNode(alternate)
    } else if (t.isBlockStatement(alternate)) {
      path.replaceWithMultiple(alternate.body)
    }
  }

  if (t.isIfStatement(node)) {
    visitIfNode(node)
  } else {
    path.replaceWith(node.test.value ? node.consequent : node.alternate)
  }
}

export default {
  visitor: {
    IfStatement: processBooleanConditional,
    ConditionalExpression: processBooleanConditional,
  },
}

// @flow

import * as t from '@babel/types'

// Empty out bodies of falsy parts of if/else statements
// to avoid requiring modules that aren't needed aka
// if (process.env.NODE_ENV === 'production') module.exports = require('./prod-version') else module.exports = require('./dev-version')
// OR
// module.exports = process.env.NODE_ENV === 'production' ? require('./prod-version') : require('./dev-version')

function processBooleanConditional(path: $FlowFixMe) {
  const { node } = path

  if (!t.isBooleanLiteral(node.test)) return

  function visitIfNode(leafNode) {
    if (!t.isBooleanLiteral(leafNode.test)) return
    const { test, consequent, alternate } = leafNode

    if (test.value) {
      if (t.isBlockStatement(consequent)) {
        path.replaceWithMultiple(consequent.body)
      } else path.replaceWith(consequent)
      return
    }
    consequent.body = []
    if (t.isIfStatement(alternate)) {
      visitIfNode(alternate)
    } else if (t.isBlockStatement(alternate)) {
      path.replaceWithMultiple(alternate.body)
    } else if (t.isExpressionStatement(alternate)) {
      path.replaceWith(alternate)
    }
  }

  if (t.isIfStatement(node)) {
    visitIfNode(node)
  } else {
    path.replaceWith(node.test.value ? node.consequent : node.alternate)
  }
}

export default {
  visitor: {
    IfStatement: processBooleanConditional,
    ConditionalExpression: processBooleanConditional,
  },
}

Fix issue with non-block if/else blocks


/**
 *  Copyright 2015 Jaime Pajuelo
 *
 *  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.
 */

"use strict";

fmval.validators.ValidationError = (function () {

    /**
     * @constructor
     * @param {String} message
     */
    var ValidationError = function ValidationError(message) {
        this.parentClass.captureStackTrace(this, this.constructor);

        this.message = message;

        this.element = document.createElement('div');
        this.element.className = "control-error";
        this.element.textContent = message;
    };

    ValidationError.inherit(Error);

    /**
     * @type {String}
     */
    ValidationError.member('name', "ValidationError");

    return ValidationError;

})();

/**
 *  Copyright 2015 Jaime Pajuelo
 *
 *  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.
 */

"use strict";

fmval.validators.ValidationError = (function () {

    /**
     * @constructor
     * @param {String} message
     */
    var ValidationError = function ValidationError(message) {
        this.parentClass.captureStackTrace(this, this.constructor);

        this.message = message;

        this.element = document.createElement('p');
        this.element.className = "control-error";
        this.element.textContent = message;
    };

    ValidationError.inherit(Error);

    /**
     * @type {String}
     */
    ValidationError.member('name', "ValidationError");

    return ValidationError;

})();

Change 'div' element of validation error to 'p'


/* global jasmineImporter */

const {GLib} = imports.gi;

const Utils = jasmineImporter.utils;

function Node(name) {
    this.name = name;
    this.attrs = {};
    this.children = [];
    this.text = '';
}

function _attrsToString(attrs) {
    return Object.keys(attrs).map(key => {
        const value = attrs[key].toString();
        return ` ${key}="${GLib.markup_escape_text(value, -1)}"`;
    }).join('');
}

function _prettyprint(node) {
    if (node.children.length === 0 && node.text.length === 0)
        return `<${node.name}${_attrsToString(node.attrs)}/>\n`;

    const elementTop = `<${node.name}${_attrsToString(node.attrs)}>\n`;
    const elementBottom = `</${node.name}>\n`;
    const children = node.children.map(_prettyprint).join('');
    let text = GLib.markup_escape_text(node.text, -1).trim();
    if (text.length !== 0)
        text += '\n';

    return elementTop + Utils.indent(children, 2) + Utils.indent(text, 2) +
        elementBottom;
}

Node.prototype.toString = function () {
    return `<?xml version="1.0" encoding="UTF-8"?>\n${_prettyprint(this)}`;
};

/* global jasmineImporter */
/* exported Node */

const {GLib} = imports.gi;

const Utils = jasmineImporter.utils;

var Node = class Node {
    constructor(name) {
        this.name = name;
        this.attrs = {};
        this.children = [];
        this.text = '';
    }

    toString() {
        return `<?xml version="1.0" encoding="UTF-8"?>\n${_prettyprint(this)}`;
    }
};

function _attrsToString(attrs) {
    return Object.keys(attrs).map(key => {
        const value = attrs[key].toString();
        return ` ${key}="${GLib.markup_escape_text(value, -1)}"`;
    }).join('');
}

function _prettyprint(node) {
    if (node.children.length === 0 && node.text.length === 0)
        return `<${node.name}${_attrsToString(node.attrs)}/>\n`;

    const elementTop = `<${node.name}${_attrsToString(node.attrs)}>\n`;
    const elementBottom = `</${node.name}>\n`;
    const children = node.children.map(_prettyprint).join('');
    let text = GLib.markup_escape_text(node.text, -1).trim();
    if (text.length !== 0)
        text += '\n';

    return elementTop + Utils.indent(children, 2) + Utils.indent(text, 2) +
        elementBottom;
}

Change XMLWriter.Node to an ES6 class


var $ = $ || function() {}; // Keeps from throwing ref errors.

function swapselected(from, to) {
	$(to).html(options[$(from).val()]);
}

function detailselected(from, to) {
	$(to).text(details[$(from).val()]);
}

$(function() {
	$("#grp-slct").change(
		function() {
			swapselected("#grp-slct", "#subgrp-slct");
		});
	$("#subgrp-slct").change(
		function() {
			detailselected("#subgrp-slct", "#detail-msg");
		});

});

var $ = $ || function() {}; // Keeps from throwing ref errors.

function swapselected(from, to) {
	$(to).html(options[$(from).val()]);
}

function detailselected(from, to) {
	$(to).text(details[$(from).val()]);
}

$(function() {
	$("#grp-slct").change(
		function() {
			swapselected("#grp-slct", "#subgrp-slct");
		});
	$("#subgrp-slct").change(
		function() {
			detailselected("#subgrp-slct", "#detail-msg");
			$("#activity_key").attr("value", $("#subgrp-slct").val());
		});

});

Add the hidden activity value to the form so we know which activity has been selected.


module.exports = {
  extends: "eslint:recommended",
  rules: {
    "no-console": 0,
    "object-curly-spacing": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    quotes: ["error", "backtick"],
    semi: ["error", "never"],
  },
  env: {
    node: true,
  },
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module",
  },
}

module.exports = {
  extends: "eslint:recommended",
  rules: {
    "no-console": 0,
    "object-curly-spacing": ["error", "always"],
    "comma-dangle": ["error", "always-multiline"],
    quotes: ["error", "backtick"],
    semi: ["error", "never"],
    "arrow-body-style": [
      "error",
      "as-needed",
      { requireReturnForObjectLiteral: true },
    ],
  },
  env: {
    node: true,
    es6: true,
  },
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module",
  },
}

Add explicit rule for arrow functions and add support for es6 globals


import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from 'react-bootstrap';
import ModifyTitle from '../containers/ModifyTitle';
import ModifyIngredients from '../containers/ModifyIngredients';
import PropTypes from 'prop-types';

const ReviewRecipe = (props) => {
  return (

Review Recipe

      <ModifyTitle
        nextButton={false}
      />
      <ModifyIngredients
        nextButton={false}
        plusButton={false}
      />
      <Link to="/">
      <Button
        bsStyle="primary"
        bsSize="large"
        style={props.buttonStyle}
        onClick={() => {
          props.tempRecipe.editMode ?
            props.editRecipe(props.tempRecipe.id, props.tempRecipe)
            : props.addRecipe(props.tempRecipe);
          props.clearTempRecipe();
        }}
        block
        >
          Submit
        </Button>
      </Link>
      <Link to="/modify-ingredients">
        <Button bsSize="large" block>Back</Button>
      </Link>

  );
};

ReviewRecipe.propTypes = {
  buttonStyle: PropTypes.object.isRequired,
  addRecipe: PropTypes.func.isRequired,
  tempRecipe: PropTypes.object.isRequired,
  clearTempRecipe: PropTypes.func.isRequired
};

export default ReviewRecipe;

import React from 'react';
import { Link } from 'react-router-dom';
import { Button } from 'react-bootstrap';
import ModifyTitle from '../containers/ModifyTitle';
import ModifyIngredients from '../containers/ModifyIngredients';
import PropTypes from 'prop-types';

const ReviewRecipe = (props) => {
  return (

Review Recipe

      <ModifyTitle
        nextButton={false}
      />
      <ModifyIngredients
        nextButton={false}
        plusButton={false}
      />
      <Link to="/">
      <Button
        bsStyle="primary"
        bsSize="large"
        style={props.buttonStyle}
        onClick={() => {
          if (props.tempRecipe.editMode) {
            props.editRecipe(props.tempRecipe.id, props.tempRecipe);
          } else {
            props.addRecipe(props.tempRecipe);
          }
          props.clearTempRecipe();
        }}
        block
        >
          Submit
        </Button>
      </Link>
      <Link to="/modify-ingredients">
        <Button bsSize="large" block>Back</Button>
      </Link>

  );
};

ReviewRecipe.propTypes = {
  buttonStyle: PropTypes.object.isRequired,
  addRecipe: PropTypes.func.isRequired,
  tempRecipe: PropTypes.object.isRequired,
  clearTempRecipe: PropTypes.func.isRequired
};

export default ReviewRecipe;

Refactor if statement for clarity.


'use strict';

function cityElectionsController($scope, ballot) {
  $scope.ballot = ballot;

  $scope.isOffice = isOffice;
  $scope.isReferendum = isReferendum;

  function isOffice(contest) {
    return contest.type === 'office';
  }

  function isReferendum(contest) {
    return contest.type === 'referendum';
  }
}

module.exports = cityElectionsController;

'use strict';

function cityElectionsController($scope, ballot) {
  $scope.ballot = ballot;

  $scope.isOffice = isOffice;
  $scope.isReferendum = isReferendum;

  function isOffice(contest) {
    return contest.contest_type === 'office';
  }

  function isReferendum(contest) {
    return contest.contest_type === 'referendum';
  }
}

module.exports = cityElectionsController;

Fix the contest type property


(function () {
    'use strict';

    angular
        .module('dpDataSelection')
        .component('dpDataSelectionFormatter', {
            bindings: {
                variables: '<',
                formatter: '@',
                useInline: '<'
            },
            templateUrl: 'modules/data-selection/components/formatter/formatter.html',
            controller: DpDataSelectionFormatterController,
            controllerAs: 'vm'
        });

    DpDataSelectionFormatterController.$inject = ['$filter'];

    function DpDataSelectionFormatterController ($filter) {
        let vm = this,
            variablesObj = {};

        if (vm.formatter) {
            if (vm.variables.length === 1) {
                // Just pass the value (String) when there is only one variable
                vm.formattedValue = $filter(vm.formatter)(vm.variables[0].value);
            } else {
                // Pass all variables as an Object if there are more variables
                vm.variables.forEach(({key, value}) => variablesObj[key] = value);

                vm.formattedValue = $filter(vm.formatter)(variablesObj);
            }
        } else {
            // If there is no formatter; concatenate all values
            vm.formattedValue = vm.variables.map(variable => {
                return variable.value;
            }).join(' ');
        }
    }
})();

(function () {
    'use strict';

    angular
        .module('dpDataSelection')
        .component('dpDataSelectionFormatter', {
            bindings: {
                variables: '<',
                formatter: '@',
                useInline: '<'
            },
            templateUrl: 'modules/data-selection/components/formatter/formatter.html',
            controller: DpDataSelectionFormatterController,
            controllerAs: 'vm'
        });

    DpDataSelectionFormatterController.$inject = ['$filter'];

    function DpDataSelectionFormatterController ($filter) {
        let vm = this,
            variablesObj = {};

        if (vm.formatter) {
            if (vm.variables.length === 1) {
                // Just pass the value (String) when there is only one variable
                vm.formattedValue = $filter(vm.formatter)(vm.variables[0].value);
            } else {
                // Pass all variables as an Object if there are more variables
                vm.variables.forEach(({key, value}) => variablesObj[key] = value);

                vm.formattedValue = $filter(vm.formatter)(variablesObj);
            }
        } else {
            // If there is no formatter; concatenate all values
            vm.formattedValue = vm.variables.map(variable => {
                return variable.value;
            }).join(' ');
        }

        console.log(formattedValue);
    }
})();

Debug thing pushing to adw..


module.exports = function(React) {
  return {
    propTypes: {
      flux: React.PropTypes.object.isRequired
    },

    childContextTypes: {
      flux: React.PropTypes.object
    },

    getChildContext: function() {
      return {
        flux: this.props.flux
      };
    }
  };
};

var FluxMixin = function(React) {
  return {
    propTypes: {
      flux: React.PropTypes.object.isRequired
    },

    childContextTypes: {
      flux: React.PropTypes.object
    },

    getChildContext: function() {
      return {
        flux: this.props.flux
      };
    }
  };
};

FluxMixin.componentWillMount = function() {
  throw new Error("Fluxbox.FluxMixin is a function that takes React as a " +
    "parameter and returns the mixin, e.g.: mixins[Fluxbox.FluxMixin(React)]");
};

module.exports = FluxMixin;

Throw if Fluxbox.FluxMixin used as a mixin instead of a function


#!/usr/bin/env node

// Modules
var connect = require('connect'),
    fs = require('fs'),
    http = require('http'),
    path = require('path'),
    serveStatic = require('serve-static'),
    serveIndex = require('serve-index');

// Variables
var app = connect(),
    hookFile = 'web-server-hook.js';

function main(port, rootPath, indexFile) {
    var hook = {
        config: function() {},
        postConfig: function() {}
    };

    rootPath = path.resolve(rootPath);

    if (fs.existsSync(path.resolve(hookFile))) {
        hook = require(hookFile);
    }

    if (undefined !== hook.config) {
        hook.config(app, port, rootPath);
    }

    app.use(serveStatic(rootPath, {'index': [indexFile]}));
    app.use(serveIndex(rootPath, {'icons': true, 'view': 'details'}));

    if (undefined !== hook.postConfig) {
        hook.postConfig(app, port, rootPath);
    }

    if (undefined != hook.createServer) {
        hook.createServer(app, port, rootPath);
    } else {
        http.createServer(app).listen(port, function() {
            console.log('Static server started at http://localhost:%d/', port);
        });
    }
}

module.exports = main;

#!/usr/bin/env node

// Modules
var connect = require('connect'),
    fs = require('fs'),
    http = require('http'),
    path = require('path'),
    serveStatic = require('serve-static'),
    serveIndex = require('serve-index');

// Variables
var app = connect(),
    hookFile = 'web-server-hook.js';

function main(port, rootPath, indexFile) {
    var hook = {
        config: function() {},
        postConfig: function() {}
    };

    rootPath = path.resolve(rootPath);

    if (fs.existsSync(path.resolve(hookFile))) {
        hook = require('./' + hookFile);
    }

    if (undefined !== hook.config) {
        hook.config(app, port, rootPath);
    }

    app.use(serveStatic(rootPath, {'index': [indexFile]}));
    app.use(serveIndex(rootPath, {'icons': true, 'view': 'details'}));

    if (undefined !== hook.postConfig) {
        hook.postConfig(app, port, rootPath);
    }

    if (undefined != hook.createServer) {
        hook.createServer(app, port, rootPath);
    } else {
        http.createServer(app).listen(port, function() {
            console.log('Static server started at http://localhost:%d/', port);
        });
    }
}

module.exports = main;

Fix inclusion of server hook to use proper relative path


// Small jQuery plugin to get dates from server.
(function($){

    var serverDate;
    var init = function(){
        if (!serverDate) {
            $.ajax({
                "url": "/course-signup/rest/user/current",
                "type": "GET",
                "async": false,
                "dataType": "json",
                "success": function(data){
                    serverDate = data.date;
                }
            });
        }
    };

    $.serverDate = function(){
        init();
        return serverDate;

    };
})(jQuery);

// Small jQuery plugin to get dates from server.
(function($){

	// Work out the difference between client time and server time.
    var adjustment;

    var init = function(){
        if (!adjustment) {
            $.ajax({
                "url": "/course-signup/rest/user/current",
                "type": "GET",
                "async": false,
                "dataType": "json",
                "success": function(data){
                    var serverDate = data.date;
					var clientDate = new Date().getTime();
					adjustment = serverDate - clientDate;
                }
            });
        }
    };

    $.serverDate = function(){
        init();
        return (new Date().getTime() + adjustment);

    };
})(jQuery);

Make sure serverdate updates using the client clock.


import styles from './UserInputError.less';

import React, { Component, PropTypes } from 'react';
import { MIN_FONT_SIZE, MAX_FONT_SIZE } from 'flux/constants/config';

export default class UserInputError extends Component {
  static propTypes = {
    areColorsValid: PropTypes.bool.isRequired,
    isFontSizeValid: PropTypes.bool.isRequired
  };

  render() {
    const { areColorsValid, isFontSizeValid } = this.props;

    return (

          {
            !areColorsValid &&

                Please enter a valid hexadecimal color

          }
          {
            !isFontSizeValid &&

                Please enter a font size between {MIN_FONT_SIZE}px
                and {MAX_FONT_SIZE}px

          }

    );
  }
}

import styles from './UserInputError.less';

import React, { Component, PropTypes } from 'react';
import { MIN_FONT_SIZE } from 'flux/constants/config';

export default class UserInputError extends Component {
  static propTypes = {
    areColorsValid: PropTypes.bool.isRequired,
    isFontSizeValid: PropTypes.bool.isRequired
  };

  render() {
    const { areColorsValid, isFontSizeValid } = this.props;

    return (

          {
            !areColorsValid &&

                Please enter a valid hexadecimal color

          }
          {
            !isFontSizeValid &&

                Please enter a font size of {MIN_FONT_SIZE}px or above

          }

    );
  }
}

Update font size error message


var game = require('../game.js');
var chai = require('chai');

chai.should();

describe('Game', function() {
  describe('createPack', function() {
    it('has 52 cards', function() {
      var p = game.createPack();
      p.should.have.lengthOf(52);
    });
  });

  describe('shuffle', function() {
    it('should have same number of cards', function() {
      var p = game.createPack();
      var s = game.shuffle(p);
      p.should.have.lengthOf(s.length);
    });
  })
});

var game = require('../game.js');
var chai = require('chai');

chai.should();

describe('Game', function() {
  describe('createPack', function() {
    it('has 52 cards', function() {
      var p = game.createPack();
      p.should.have.lengthOf(52);
    });
  });

  describe('shuffle', function() {
    it('should have same number of cards', function() {
      var p = game.createPack();
      var s = game.shuffle(p);
      p.should.have.lengthOf(s.length);
    });
  })

  describe('draw', function() {
    describe('one card', function() {
      it('should draw the requested number', function() {
        var pack = game.createPack();
        var cards = game.draw(pack, 1, [], false);
        cards.should.have.lengthOf(1);
      });
    });

    describe('three cards', function() {
      it('should draw the requested number', function() {
        var pack = game.createPack();
        var cards = game.draw(pack, 3, [], false);
        cards.should.have.lengthOf(3);
      });
    });

  });
});

Add some tests for drawing cards


import React from 'react'
import moment from 'moment'
import { theme } from '../../tools'

let styles = {
  chip: {},
}

const LastHarvestStatus = ({harvest}) => {
  const date = new Date(harvest.finished || harvest.finishedAt).getTime()
  const hoursDifference = moment(date).fromNow()
  let status

  if (harvest.status === 'successful') {
    status = 'Réussi'
  } else {
    styles.chip.color =  theme.red
    status = 'En échec'
  }

  return (
    <div style={styles.chip}>
      {status} {hoursDifference}
    </div>
  )
}

export default LastHarvestStatus

import React from 'react'
import moment from 'moment'
import { theme } from '../../tools'

let styles = {
  chip: {},
}

const LastHarvestStatus = ({harvest}) => {
  const date = new Date(harvest.finished || harvest.finishedAt).getTime()
  const hoursDifference = moment(date).fromNow()
  let status

  if (harvest.status === 'successful') {
    styles.chip.color =  theme.highlightblue
    status = 'Réussi'
  } else {
    styles.chip.color =  theme.red
    status = 'En échec'
  }

  return (
    <div style={styles.chip}>
      {status} {hoursDifference}
    </div>
  )
}

export default LastHarvestStatus

Fix color on last harvested


const { next, hookStart, hookEnd } = require('hooter/effects')
const assignDefaults = require('./assignDefaults')
const validateConfig = require('./validateConfig')

const EVENTS_WITH_CONFIG = ['start', 'execute', 'process', 'handle', 'error']

module.exports = function* configurePlugin() {
  let schema, config

  function* provideConfig(...args) {
    let event = this.name

    if (!config && event !== 'error') {
      throw new Error(
        `The config must already be defined at the beginning of "${event}"`
      )
    }

    return yield next(config, ...args)
  }

  yield hookEnd('schema', function* (_schema) {
    schema = yield next(_schema).or(_schema)
    return schema
  })

  yield hookStart('configure', function* (_config) {
    return yield next(schema, _config)
  })

  yield hookStart('configure', function* (_schema, _config) {
    _config = assignDefaults(_schema, _config)
    return yield next(_schema, _config)
  })

  yield hookEnd('configure', function* (_schema, _config) {
    validateConfig(_schema, _config)
    config = yield next(_schema, _config).or(_config)
    return config
  })

  for (let event of EVENTS_WITH_CONFIG) {
    yield hookStart(event, provideConfig)
  }
}

const { next, hook, hookStart, hookEnd } = require('hooter/effects')
const assignDefaults = require('./assignDefaults')
const validateConfig = require('./validateConfig')

const EVENTS_WITH_CONFIG = ['start', 'execute', 'process', 'handle', 'error']

module.exports = function* configurePlugin() {
  let schema, config

  function* provideConfig(...args) {
    let event = this.name

    if (!config && event !== 'error') {
      throw new Error(
        `The config must already be defined at the beginning of "${event}"`
      )
    }

    return yield next(config, ...args)
  }

  yield hookEnd('schema', function* (_schema) {
    schema = yield next(_schema).or(_schema)
    return schema
  })

  yield hookStart('configure', function* (_config) {
    return yield next(schema, _config)
  })

  yield hook('configure', function* (_schema, _config) {
    _config = assignDefaults(_schema, _config)
    return yield next(_schema, _config)
  })

  yield hookEnd('configure', function* (_schema, _config) {
    validateConfig(_schema, _config)
    config = yield next(_schema, _config).or(_config)
    return config
  })

  for (let event of EVENTS_WITH_CONFIG) {
    yield hookStart(event, provideConfig)
  }
}

Use 'hook' to assign defaults


import Axios from 'axios';

export function request (url, method, data = {}, options = {scroll: true}) {
    let promise = Axios.post(url, data, {
      headers: {
        'X-HTTP-Method-Override': method,
        'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').getAttribute('content')
      }
    });

    promise.catch(e => {
      if (e.response) return e.response;
      throw e;
    })
    .then(response => {
      let html = response.data;
      let location = response.request.responseURL;

      if ((window.location.href == location) || (method == 'delete')){
        window.location.reload(true); // save scroll position for annotations
      } else {
        window.location.replace(location);
      }

      if (options["modal"]){
        options["modal"].destroy();
      }

    })
    .done();

    return promise;
}

export var get = (url, data = {}, options = {}) => request(url, 'get', data, options)
export var post = (url, data = {}, options = {}) => request(url, 'post', data, options)
export var rest_delete = (url, data = {}, options = {}) => request(url, 'delete', data, options)
export var patch = (url, data = {}, options = {}) => request(url, 'patch', data, options)

import Axios from 'axios';

export function request (url, method, data = {}, options = {scroll: true}) {
    let promise = Axios.post(url, data, {
      headers: {
        'X-HTTP-Method-Override': method,
        'X-CSRF-Token': document.querySelector('meta[name=csrf-token]').getAttribute('content')
      }
    });

    promise.catch(e => {
      if (e.response) return e.response;
      throw e;
    })
    .then(response => {
      let html = response.data;
      let location = response.request.responseURL;

      if ((window.location.href == location) || (method == 'delete')){
        // saving scroll position
        if (navigator.userAgent.match('Firefox') != null){
          window.location.reload(false);
        }
        else {
          window.location.reload(true);
        }
      } else {
        window.location.replace(location);
      }

      if (options["modal"]){
        options["modal"].destroy();
      }

    })
    .done();

    return promise;
}

export var get = (url, data = {}, options = {}) => request(url, 'get', data, options)
export var post = (url, data = {}, options = {}) => request(url, 'post', data, options)
export var rest_delete = (url, data = {}, options = {}) => request(url, 'delete', data, options)
export var patch = (url, data = {}, options = {}) => request(url, 'patch', data, options)

Save scroll position in Firefox.


import Ember from 'ember';
import DS from 'ember-data';
import { Offline } from 'ember-flexberry-data';

export default Offline.Store.extend({
  init() {
    this._super(...arguments);
    let owner = Ember.getOwner(this);
    let Store = DS.Store;
    let onlineStore = Store.create(owner.ownerInjection());
    this.set('onlineStore', onlineStore);
  }
});

import Ember from 'ember';
import DS from 'ember-data';
import { Offline } from 'ember-flexberry-data';

export default Offline.Store.extend({
  init() {
    this.set('offlineSchema', {
      TestDB: {
        0.1: {
          'ember-flexberry-dummy-suggestion': 'id,address,text,date,votes,moderated,type,author,editor1,*files,*userVotes,*comments',
          'ember-flexberry-dummy-suggestion-type': 'id,name,moderated,parent,*localizedTypes',
          'ember-flexberry-dummy-application-user': 'id,name,eMail,phone1,phone2,phone3,activated,vK,facebook,twitter,birthday,gender,vip,karma',
          'ember-flexberry-dummy-vote': 'id,suggestion,voteType,applicationUser',
          'ember-flexberry-dummy-comment': 'id,suggestion,text,votes,moderated,author,*userVotes',
          'ember-flexberry-dummy-comment-vote': 'id,comment,voteType,applicationUser',
        }
      },
    });
    let owner = Ember.getOwner(this);
    let Store = DS.Store;
    let onlineStore = Store.create(owner.ownerInjection());
    this.set('onlineStore', onlineStore);
    this._super(...arguments);
  }
});

Test dummy-app add offline schema for tests


// Manage the SHA of the latest control repository commit.

var restify = require('restify');

var storage = require('../storage');
var log = require('../logging').getLogger();

exports.store = function (req, res, next) {
  if (req.params.sha === undefined) {
    return next(new restify.InvalidContentError('Missing required "sha" attribute'));
  }

  if (!/[0-9a-fA-F]{40}/.test(req.params.sha)) {
    return next(new restify.InvalidContentError('Not a valid "sha"'));
  }

  storage.storeSHA(req.params.sha, function (err) {
    next.ifError(err);

    res.send(204);

    log.info('Stored control repository SHA', {
      sha: req.params.sha
    });
    next();
  });
};

exports.retrieve = function (req, res, next) {
  storage.getSHA(function (err, sha) {
    next.ifError(err);

    res.json(200, {sha: sha});

    log.info('Got control repository SHA', {
      sha: sha
    });
    next();
  });
};

// Manage the SHA of the latest control repository commit.

var restify = require('restify');

var storage = require('../storage');
var log = require('../logging').getLogger();

exports.store = function (req, res, next) {
  if (req.params.sha === undefined) {
    return next(new restify.InvalidContentError('Missing required "sha" attribute'));
  }

  if (!/[0-9a-fA-F]{40}/.test(req.params.sha)) {
    return next(new restify.InvalidContentError('Not a valid "sha"'));
  }

  storage.storeSHA(req.params.sha, function (err) {
    next.ifError(err);

    res.send(204);

    log.info('Stored control repository SHA', {
      sha: req.params.sha
    });
    next();
  });
};

exports.retrieve = function (req, res, next) {
  storage.getSHA(function (err, sha) {
    next.ifError(err);

    res.json(200, {sha: sha});
    next();
  });
};

Remove a misleading log message.


var Trie = require('../app/trie');

describe('Trie', function() {
  var trie;

  beforeEach(function() {
    trie = new Trie();
  });

  it('should be an object', function() {
    expect(trie).to.be.ok;
  });

  it('should have a root', function() {
    expect(trie.root).to.be.ok;
  });

  it('should have add method', function() {
    expect(trie.add).to.be.an.instanceof(Function);
  });

  it('should have search method', function() {
    expect(trie.search).to.be.an.instanceof(Function);
  });

  it('should have find method', function() {
    expect(trie.find).to.be.an.instanceof(Function);
  });

  it('should add string to trie', function() {
    expect(trie.add('test')).to.be.undefined;
  });

  it('should correctly find an added string', function() {
    trie.add('test');
    expect(trie.find('test')).to.be.true;
  });

});

var Trie = require('../app/trie');

describe('Trie', function() {
  var trie;

  beforeEach(function() {
    trie = new Trie();
  });

  it('should be an object', function() {
    expect(trie).to.be.ok;
  });

  it('should have a root', function() {
    expect(trie.root).to.be.ok;
  });

  it('should have add method', function() {
    expect(trie.add).to.be.an.instanceof(Function);
  });

  it('should have search method', function() {
    expect(trie.search).to.be.an.instanceof(Function);
  });

  it('should have find method', function() {
    expect(trie.find).to.be.an.instanceof(Function);
  });

  it('should add string to trie', function() {
    expect(trie.add('test')).to.be.undefined;
  });

  it('should correctly find an added string', function() {
    trie.add('test');
    expect(trie.find('test')).to.be.true;
  });

  it('should trim leading/trailing spaces when adding a string', function() {
    trie.add('  test   ');
    expect(trie.find('test')).to.be.true;
  });

});

Add test for trimming leading/trailing whitespace


// An example configuration file.
exports.config = {
  // The address of a running selenium server.
  //seleniumAddress: 'http://localhost:4444/wd/hub',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  specs: ['*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
  }
};

// An example configuration file.
exports.config = {
  // The address of a running selenium server.
  //seleniumAddress: 'http://localhost:4444/wd/hub',

  // Capabilities to be passed to the webdriver instance.
  capabilities: {
    'browserName': 'chrome'
  },

  allScriptsTimeout: 11000,

  // Spec patterns are relative to the location of the spec file. They may
  // include glob patterns.
  specs: ['*.spec.js'],

  // Options to be passed to Jasmine-node.
  jasmineNodeOpts: {
    showColors: true, // Use colors in the command line report.
    defaultTimeoutInterval: 30000
  }
};

Add timeouts to protractor demo


var starsky = require('..');

setInterval(function () {
  starsky.publish('starsky.test', {
    subject: 'test message'
  });
}, 1000);

starsky.connect();

var starsky = require('..');

starsky.configure(__dirname + '/config.yml');

setInterval(function () {
  starsky.publish('starsky.test', {
    subject: 'test message'
  }, confirm);
}, 1000);

function confirm (err) {
  if (err) console.error(err.message);
}

starsky.connect();

Add confirm callback to example


const { pick, mapValues, isArray, pickBy, get } = require('lodash')

const { search } = require('../../search/services')
const { transformApiResponseToSearchCollection } = require('../../search/transformers')
const { transformContactToListItem } = require('../transformers')
const removeArray = require('../../../lib/remove-array')

async function getContactsCollection (req, res, next) {
  try {
    res.locals.results = await search({
      searchEntity: 'contact',
      requestBody: req.body,
      token: req.session.token,
      page: req.query.page,
      isAggregation: false,
    })
      .then(transformApiResponseToSearchCollection(
        { query: req.query },
        transformContactToListItem,
      ))

    next()
  } catch (error) {
    next(error)
  }
}

function getRequestBody (req, res, next) {
  const selectedFiltersQuery = removeArray(pick(req.query, [
    'archived',
    'company_name',
    'company_sector',
    'address_country',
    'company_uk_region',
  ]), 'archived')

  mapValues(get(selectedFiltersQuery, 'archived'), (value) => {
    return isArray(value) ? null : value
  })

  const selectedSortBy = req.query.sortby
    ? { sortby: req.query.sortby }
    : null

  req.body = Object.assign({}, req.body, selectedSortBy, pickBy(selectedFiltersQuery))

  next()
}

module.exports = {
  getContactsCollection,
  getRequestBody,
}

const { pick, mapValues, isArray, pickBy, get } = require('lodash')

const { search } = require('../../search/services')
const { transformApiResponseToSearchCollection } = require('../../search/transformers')
const { transformContactToListItem } = require('../transformers')
const removeArray = require('../../../lib/remove-array')

async function getContactsCollection (req, res, next) {
  try {
    res.locals.results = await search({
      searchEntity: 'contact',
      requestBody: req.body,
      token: req.session.token,
      page: req.query.page,
      isAggregation: false,
    })
      .then(transformApiResponseToSearchCollection(
        { query: req.query },
        transformContactToListItem,
      ))

    next()
  } catch (error) {
    next(error)
  }
}

function getRequestBody (req, res, next) {
  const selectedFiltersQuery = removeArray(pick(req.query, [
    'archived',
    'name',
    'company_name',
    'company_sector',
    'address_country',
    'company_uk_region',
  ]), 'archived')

  mapValues(get(selectedFiltersQuery, 'archived'), (value) => {
    return isArray(value) ? null : value
  })

  const selectedSortBy = req.query.sortby
    ? { sortby: req.query.sortby }
    : null

  req.body = Object.assign({}, req.body, selectedSortBy, pickBy(selectedFiltersQuery))

  next()
}

module.exports = {
  getContactsCollection,
  getRequestBody,
}

Add support to the contact list middleware for contact name


// Profile Model
module.exports = function(sequelize, DataTypes) {
  var Profile = sequelize.define('Profile', {
    tagLine: {
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT,
      allowNull: false
    }
  }, {
    associate: function(models) {
      Profile.hasMany(models.ProfileItem);
    }
  });

  return Profile;
}

// Profile Model
module.exports = function(sequelize, DataTypes) {
  var Profile = sequelize.define('Profile', {
    tagLine: {
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT,
      allowNull: false
    },
    votes: {
      type: DataTypes.INTEGER,
      defaultValue: 0
    }
  }, {
    associate: function(models) {
      Profile.hasMany(models.ProfileItem);
    }
  });

  return Profile;
}

Add 'votes' field to Profile model


'use strict';

function isObject(/* subjects... */) {
  var index,
      length = arguments.length,
      current;

  if (length < 1) {
    return false;
  }

  for (index = 0; index < length; index += 1) {
    current = arguments[index];

    if (('object' !== typeof current) || (null === current)) {
      return false;
    }
  }

  return true;
}

function isInstanceOf(constructor /*, subjects... */) {
  var index,
      length = arguments.length;

  if (length < 2) {
    return false;
  }

  for (index = 1; index < length; index += 1) {
    if (!(arguments[index] instanceof constructor)) {
      return false;
    }
  }

  return true;
}

function xor(left, right) {
  return (left && !right) || (!left && right);
}

module.exports.isObject = isObject;
module.exports.isInstanceOf = isInstanceOf;
module.exports.xor = xor;

'use strict';

function isObject(/* subjects... */) {
  var index,
      length = arguments.length,
      current;

  if (length < 1) {
    return false;
  }

  for (index = 0; index < length; index += 1) {
    current = arguments[index];

    if (('object' !== typeof current) || (null === current)) {
      return false;
    }
  }

  return true;
}

function isInstanceOf(constructor /*, subjects... */) {
  var index,
      length = arguments.length;

  if (length < 2) {
    return false;
  }

  for (index = 1; index < length; index += 1) {
    if (!(arguments[index] instanceof constructor)) {
      return false;
    }
  }

  return true;
}

module.exports.isObject = isObject;
module.exports.isInstanceOf = isInstanceOf;

Remove unused `xor` utility function


import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | css styles');

test('check that Octicons scss is being applied', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal($('.octicon').css('display'), 'inline-block');
  });
});

import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | css styles');

test('check that Octicons scss is being applied', function(assert) {
  visit('/');

  andThen(function() {
    assert.equal($('span.octicon').css('display'), 'inline-block');
  });
});

Make sure we're testing span


const DocumentedItem = require('./item');

class DocumentedVarType extends DocumentedItem {
	registerMetaInfo(data) {
		this.directData = data;
	}

	serialize() {
		const names = [];
		for(const name of this.directData.names) names.push(this.constructor.splitVarName(name));
		if(!this.directData.description && !this.directData.nullable) return names;
		return {
			types: names,
			description: this.directData.description,
			nullable: this.directData.nullable
		};
	}

	static splitVarName(str) {
		if(str === '*') return ['*'];
		const matches = str.match(/([\w*]+)([^\w*]+)/g);
		const output = [];
		if(matches) {
			for(const match of matches) {
				const groups = match.match(/([\w*]+)([^\w*]+)/);
				output.push([groups[1], groups[2]]);
			}
		} else {
			output.push([str.match(/([\w*]+)/g)[0]]);
		}
		return output;
	}
}

/*
{
  "names":[
    "String"
  ]
}
*/

module.exports = DocumentedVarType;

const DocumentedItem = require('./item');

class DocumentedVarType extends DocumentedItem {
	registerMetaInfo(data) {
		this.directData = data;
	}

	serialize() {
		const names = [];
		for(const name of this.directData.names) names.push(this.constructor.splitVarName(name));
		if(!this.directData.description && !this.directData.nullable) return names;
		return {
			types: names,
			description: this.directData.description,
			nullable: this.directData.nullable
		};
	}

	static splitVarName(str) {
		if(str === '*') return ['*'];
		str = str.replace(/\./g, '');
		const matches = str.match(/([\w*]+)([^\w*]+)/g);
		const output = [];
		if(matches) {
			for(const match of matches) {
				const groups = match.match(/([\w*]+)([^\w*]+)/);
				output.push([groups[1], groups[2]]);
			}
		} else {
			output.push([str.match(/([\w*]+)/g)[0]]);
		}
		return output;
	}
}

/*
{
  "names":[
    "String"
  ]
}
*/

module.exports = DocumentedVarType;

Remove dots from generic types


/**
 * @fileOverview Routes for City.
 */
var log = require('logg').getLogger('app.router.city');

var HomeCtrl = require('../controllers/city/index.ctrl');
var StaticsCtrl = require('../controllers/city/statics.ctrl');

var router = module.exports = {};

/**
 * Initialize routes.
 *
 * @param {express} app Express instance.
 */
router.init = function(app) {
  log.fine('init() :: initializing routes...');
  var homeCtrl = HomeCtrl.getInstance();
  var staticsCtrl = StaticsCtrl.getInstance();

  app.get('/', homeCtrl.use);

  app.get('/submit-event/', staticsCtrl.use);
};

/**
 * @fileOverview Routes for City.
 */
var log = require('logg').getLogger('app.router.city');

var HomeCtrl = require('../controllers/city/index.ctrl');
var StaticsCtrl = require('../controllers/city/statics.ctrl');
var TogetherCtrl = require('../controllers/city/together.ctrl');

var router = module.exports = {};

/**
 * Initialize routes.
 *
 * @param {express} app Express instance.
 */
router.init = function(app) {
  log.fine('init() :: initializing routes...');
  var homeCtrl = HomeCtrl.getInstance();
  var staticsCtrl = StaticsCtrl.getInstance();
  var togetherCtrl = TogetherCtrl.getInstance();

  app.get('/', homeCtrl.use);

  app.get('/submit-event', staticsCtrl.use);

  app.get('/together', togetherCtrl.use);
};

Add route for together event


window.onload = function() {

  createChart('.ct-chart', true);

  document.getElementById('button1').onclick = function () {

    var chartDivNode = document.getElementById('chart');
    var chartSvgNode = chartDivNode.children[0];

    SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
  };

  document.getElementById('button2').onclick = function () {

    var dataURL = document.getElementById('canvas').toDataURL();
    document.getElementById('image').src = dataURL;
  };
}

window.onload = function() {

  // using true as the second parameter we force chartist.js to use plain SVG not <foreignObject>
  createChart('.ct-chart', true);

  document.getElementById('button1').onclick = function () {

    var chartDivNode = document.getElementById('chart');
    var chartSvgNode = chartDivNode.children[0];

    // SVG2Bitmap will render the chartist SVG code and create all necessary inline styles
    SVG2Bitmap(chartSvgNode, document.getElementById('canvas'));
  };

  document.getElementById('button2').onclick = function () {

    var dataURL = document.getElementById('canvas').toDataURL();
    document.getElementById('image').src = dataURL;
  };
}

Comment added to the JS code


/* globals jQuery,QUnit */

jQuery(document).ready(function() {
  var TestLoader = require('ember-cli/test-loader')['default'];
  TestLoader.prototype.shouldLoadModule = function(moduleName) {
    return moduleName.match(/\/.*[-_]test$/) || (!QUnit.urlParams.nojshint && moduleName.match(/\.jshint$/));
  };

  TestLoader.prototype.moduleLoadFailure = function(moduleName, error) {
    QUnit.module('TestLoader Failures');
    QUnit.test(moduleName + ': could not be loaded', function() {
      throw error;
    });
  };

  var autostart = QUnit.config.autostart !== false;
  QUnit.config.autostart = false;

  setTimeout(function() {
    TestLoader.load();

    if (autostart) {
      QUnit.start();
    }
  }, 250);
});

/* globals jQuery,QUnit */

jQuery(document).ready(function() {
  var TestLoaderModule = require('ember-cli/test-loader');
  var TestLoader = TestLoaderModule['default'];
  var addModuleIncludeMatcher = TestLoaderModule['addModuleIncludeMatcher'];

  function moduleMatcher(moduleName) {
    return moduleName.match(/\/.*[-_]test$/) || (!QUnit.urlParams.nojshint && moduleName.match(/\.jshint$/));
  }

  if (addModuleIncludeMatcher) {
    addModuleIncludeMatcher(moduleMatcher);
  } else {
    TestLoader.prototype.shouldLoadModule = moduleMatcher;
  }

  TestLoader.prototype.moduleLoadFailure = function(moduleName, error) {
    QUnit.module('TestLoader Failures');
    QUnit.test(moduleName + ': could not be loaded', function() {
      throw error;
    });
  };

  var autostart = QUnit.config.autostart !== false;
  QUnit.config.autostart = false;

  setTimeout(function() {
    TestLoader.load();

    if (autostart) {
      QUnit.start();
    }
  }, 250);
});

Use addModuleIncludeMatcher instead of prototype mutation.


var MAX_FILE_SIZE = 1048576;

$(function() {
    $('#pluginFile').on('change', function() {
        var alert = $('.alert-file');
        var fileName = $(this).val().trim();
        var fileSize = this.files[0].size;
        if (!fileName) {
            alert.fadeOut(1000);
            return;
        }

        if (fileSize > MAX_FILE_SIZE) {
            alert.find('i').removeClass('fa-upload').addClass('fa-times');
            alert.find('.file-upload').find('button')
                .removeClass('btn-success')
                .addClass('btn-danger')
                .prop('disabled', true);
            alert.find('.file-size').css('color', '#d9534f');
        }

        fileName = fileName.substr(fileName.lastIndexOf('\\') + 1, fileName.length);
        alert.find('.file-name').text(fileName);
        alert.find('.file-size').text(filesize(this.files[0].size));
        alert.fadeIn('slow');
    });
});

var MAX_FILE_SIZE = 1048576;

$(function() {
    $('#pluginFile').on('change', function() {
        var alert = $('.alert-file');
        var fileName = $(this).val().trim();
        var fileSize = this.files[0].size;
        if (!fileName) {
            alert.fadeOut(1000);
            return;
        }

        if (fileSize > MAX_FILE_SIZE) {
            alert.find('i').removeClass('fa-upload').addClass('fa-times');
            alert.find('.file-upload').find('button')
                .removeClass('btn-success')
                .addClass('btn-danger')
                .prop('disabled', true);
            alert.find('.file-size').css('color', '#d9534f');
        }

        fileName = fileName.substr(fileName.lastIndexOf('\\') + 1, fileName.length);
        alert.find('.file-name').text(fileName);
        alert.find('.file-size').text(filesize(this.files[0].size));
        alert.fadeIn('slow');
    });

    $('.file-upload').find('button').click(function() {
        $(this).find('i').removeClass('fa-upload').addClass('fa-spinner fa-spin');
    });
});

Add spinner to upload button


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

const {DateTime} = require('actions-on-google');

module.exports = {

  'ask_for_datetime': (conv) => {
    const options = {
      prompts: {
        initial: 'When would you like to schedule the appointment?',
        date: 'What day was that?',
        time: 'What time?',
      },
    };
    conv.ask(new DateTime(options));
  },

  'ask_for_datetime_confirmation': (conv, params, datetime) => {
    const { month, day } = datetime.date
    const { hours, minutes } = datetime.time
    conv.ask(`<speak>
        Great, we will see you on
        <say-as interpret-as="date" format="dm">${day}-${month}</say-as>
        <say-as interpret-as="time" format="hms12" detail="2">${hours}:${minutes || '00'}</say-as>
      </speak>`);
  },
};

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

const {DateTime} = require('actions-on-google');

module.exports = {

  'ask_for_datetime': (conv) => {
    const options = {
      prompts: {
        initial: 'When would you like to schedule the appointment?',
        date: 'What day was that?',
        time: 'What time?',
      },
    };
    conv.ask(new DateTime(options));
  },

  'ask_for_datetime_confirmation': (conv, params, datetime) => {
    const { month, day } = datetime.date
    const { hours, minutes } = datetime.time
    conv.ask(`<speak>` +
        `Great, we will see you on ` +
        `<say-as interpret-as="date" format="dm">${day}-${month}</say-as>` +
        `<say-as interpret-as="time" format="hms12" detail="2">${hours}:${minutes || '00'}</say-as>` +
      `</speak>`);
  },
};

Remove spaces from datetime SSML response.


'use strict';

var config       = require('../config');
var gulp         = require('gulp');
var sass         = require('gulp-sass');
var gulpif       = require('gulp-if');
var handleErrors = require('../util/handleErrors');
var browserSync  = require('browser-sync');
var autoprefixer = require('gulp-autoprefixer');

gulp.task('styles', function () {

  return gulp.src(config.styles.src)
    .pipe(sass({
      includePaths: [
        './node_modules/bootstrap-sass/assets/stylesheets',
      ],
      sourceComments: global.isProd ? 'none' : 'map',
      sourceMap: 'sass',
      outputStyle: global.isProd ? 'compressed' : 'nested'
    }))
    .pipe(autoprefixer("last 2 versions", "> 1%", "ie 8"))
    .on('error', handleErrors)
    .pipe(gulp.dest(config.styles.dest))
    .pipe(gulpif(browserSync.active, browserSync.reload({ stream: true })));

});

'use strict';

var config       = require('../config');
var gulp         = require('gulp');
var sass         = require('gulp-sass');
var gulpif       = require('gulp-if');
var handleErrors = require('../util/handleErrors');
var browserSync  = require('browser-sync');
var autoprefixer = require('gulp-autoprefixer');

gulp.task('styles', function () {

  return gulp.src(config.styles.src)
    .pipe(sass({
      includePaths: [
        './node_modules/bootstrap-sass/assets/stylesheets',
      ],
      sourceComments: global.isProd ? 'none' : 'map',
      sourceMap: 'sass',
      outputStyle: global.isProd ? 'compressed' : 'nested',
      errLogToConsole: true
    }))
    .pipe(autoprefixer("last 2 versions", "> 1%", "ie 8"))
    .on('error', handleErrors)
    .pipe(gulp.dest(config.styles.dest))
    .pipe(gulpif(browserSync.active, browserSync.reload({ stream: true })));

});

Add option to not break pipe when sass syntax error


import React, { PropTypes } from 'react';

export default class DashboardProjects extends React.Component { // eslint-disable-line
  render() {
    return (

Projects

        {this.props.children}

    );
  }
}

DashboardProjects.propTypes = {
  children: PropTypes.array,
};

import React, { PropTypes } from 'react';

export default class DashboardProjects extends React.Component { // eslint-disable-line
  render() {
    return (

Projects

        {this.props.children}

    );
  }
}

DashboardProjects.propTypes = {
  children: PropTypes.element,
};

Fix project dashboard's prop type.


var Deffy = require("deffy")

function SubElm(data, parent) {
    this.name = data.name;
    this.label = Deffy(data.label, this.name);
    this.type = data.type;
    this.id = [this.type, parent.name, this.name].join("_");
}

module.exports = SubElm;

var Deffy = require("deffy")
  , Typpy = require("typpy")
  ;

function SubElm(type, data, parent) {
    if (Typpy(data, SubElm)) {
        return data;
    }
    this.name = data.name || data.event || data.method;
    this.label = Deffy(data.label, this.name);
    this.type = type;
    this.id = [this.type, parent.name, this.name].join("_");
}

module.exports = SubElm;

Set the sub element name


(function() {
  if (typeof FastBoot === 'undefined') {
    var current = document.getElementById('fastboot-body-start');

    if (
      current &&
      typeof Ember.ViewUtils.isSerializationFirstNode === 'function' &&
      Ember.ViewUtils.isSerializationFirstNode(current.nextSibling)
    ) {
      Ember.ApplicationInstance.reopen({
        _bootSync: function(options) {
          if (options === undefined) {
            options = {
              _renderMode: 'rehydrate'
            };
          }

          return this._super(options);
        }
      });

      // Prevent clearRender  by removing `fastboot-body-start` which is already
      // guarded for
      current.parentNode.removeChild(current);
      var end = document.getElementById('fastboot-body-end');

      if (end) {
        end.parentNode.removeChild(end);
      }
    }
  }
})();

(function() {
  if (typeof FastBoot === 'undefined') {
    var current = document.getElementById('fastboot-body-start');
    var Ember = require('ember').default;

    if (
      current &&
      typeof Ember.ViewUtils.isSerializationFirstNode === 'function' &&
      Ember.ViewUtils.isSerializationFirstNode(current.nextSibling)
    ) {
      Ember.ApplicationInstance.reopen({
        _bootSync: function(options) {
          if (options === undefined) {
            options = {
              _renderMode: 'rehydrate'
            };
          }

          return this._super(options);
        }
      });

      // Prevent clearRender  by removing `fastboot-body-start` which is already
      // guarded for
      current.parentNode.removeChild(current);
      var end = document.getElementById('fastboot-body-end');

      if (end) {
        end.parentNode.removeChild(end);
      }
    }
  }
})();

Fix use of Ember global


/* global window */
/* @jsx createElement */
// @flow

// eslint-disable-next-line no-unused-vars
import { createElement } from 'jsx-dom';
import { watch } from '../core';
// $FlowFixMe
import cardInfoHeader from '../assets/tooltip-header-sprite.png';
// $FlowFixMe
import cardInfoBackground from '../assets/tooltip-text-background.png';
// $FlowFixMe
import Gwent from '../assets/fonts/hinted-GWENT-ExtraBold.woff2';
// $FlowFixMe
import HalisGRRegular from '../assets/fonts/hinted-HalisGR-Regular.woff2';
// $FlowFixMe
import HalisGRBold from '../assets/fonts/hinted-HalisGR-Bold.woff2';

// Setup the homepage
async function onLoad() {
    // fetch card data
    const { cards, dictionary } = await fetchJson('./data.json');

    // Start watching the whole body for card names.
    watch(
        window.document.body,
        {
            cards,
            dictionary,
            assets: {
                cardInfoHeader,
                cardInfoBackground,
                Gwent,
                HalisGRRegular,
                HalisGRBold
            }
        },
        { shouldUnderline: true }
    );
}

async function fetchJson(src: string): Promise<Object> {
    const response = await window.fetch(src);
    const json = await response.json();
    return json;
}

onLoad();

/* global window */
/* @jsx createElement */
// @flow

// eslint-disable-next-line no-unused-vars
import { createElement } from 'jsx-dom';
import { watch } from '../core';
// $FlowFixMe
import cardInfoHeader from '../assets/tooltip-header-sprite.png';
// $FlowFixMe
import cardInfoBackground from '../assets/tooltip-text-background.png';
// $FlowFixMe
import Gwent from '../assets/fonts/hinted-GWENT-ExtraBold.woff2';
// $FlowFixMe
import HalisGRRegular from '../assets/fonts/hinted-HalisGR-Regular.woff2';
// $FlowFixMe
import HalisGRBold from '../assets/fonts/hinted-HalisGR-Bold.woff2';
// $FlowFixMe importing so that it is copied to the font folder
import '../assets/fonts/hinted-HalisGR-Book.woff2';

// Setup the homepage
async function onLoad() {
    // fetch card data
    const { cards, dictionary } = await fetchJson('./data.json');

    // Start watching the whole body for card names.
    watch(
        window.document.body,
        {
            cards,
            dictionary,
            assets: {
                cardInfoHeader,
                cardInfoBackground,
                Gwent,
                HalisGRRegular,
                HalisGRBold
            }
        },
        { shouldUnderline: true }
    );
}

async function fetchJson(src: string): Promise<Object> {
    const response = await window.fetch(src);
    const json = await response.json();
    return json;
}

onLoad();

Fix missing Halis Book font on website