import postcss from 'postcss'
import { readFileSync as slurp } from 'fs'
import { resolve, isAbsolute } from 'path'
import { parse as parseUrl } from 'url'
import { default as rebaseUrl } from 'postcss-url'

export default function rebase(pkg, opts, filename) {
  return postcss([
      rebaseUrl({
        url: (url, decl, from, dirname, to, options, result) => {
          let parsed = parseUrl(url, true, true)

          if (parsed.host || isAbsolute(parsed.path)) {
            return url
          } else {
            let resolved = pkg.relative(resolve(pkg.root, opts.lib, parsed.path))
            return resolved
          }
        }
      })
    ]).process(slurp(filename, 'utf8'))
}

import postcss from 'postcss'
import { readFileSync as slurp } from 'fs'
import { resolve, isAbsolute } from 'path'
import { parse as parseUrl } from 'url'
import { default as rebaseUrl } from 'postcss-url'

export default function rebase(pkg, opts, filename) {
  return postcss([
      rebaseUrl({
        url: (url, decl, from, dirname, to, options, result) => {
          let parsed = parseUrl(url, true, true)

          if (parsed.host || isAbsolute(parsed.path)) {
            return url
          } else {
            let resolved = pkg.relative(resolve(pkg.root, opts.lib, parsed.path))
            return resolved.replace(/\\/g, '/')
          }
        }
      })
    ]).process(slurp(filename, 'utf8'))
}

Replace `\` with `/` in resolved path


/**
 * @package admiral
 * @author Andrew Munsell <andrew@wizardapps.net>
 * @copyright 2015 WizardApps
 */

exports = module.exports = function(app, config, fleet) {
    /**
     * Get the machines in the cluster
     */
    app.get('/v1/machines', function(req, res) {
        fleet.list_machinesAsync()
            .then(function(machines) {
                res
                    .json(machines)
                    .header('Cache-Control', 'private, max-age=60');
            })
            .catch(function(err) {
                res
                    .status(500)
                    .json({
                        error: 500,
                        message: 'There was a problem fetching the machines.'
                    });
            })
            .finally(function() {
                res.end();
            });
    });
};

exports['@singleton'] = true;
exports['@require'] = ['app', 'config', 'fleet'];

/**
 * @package admiral
 * @author Andrew Munsell <andrew@wizardapps.net>
 * @copyright 2015 WizardApps
 */

exports = module.exports = function(app, config, fleet) {
    /**
     * Get the machines in the cluster
     */
    app.get('/v1/machines', function(req, res) {
        fleet.list_machinesAsync()
            .then(function(machines) {
                res
                    .header('Cache-Control', 'private, max-age=60')
                    .json(machines);
            })
            .catch(function(err) {
                res
                    .status(500)
                    .json({
                        error: 500,
                        message: 'There was a problem fetching the machines.'
                    });
            })
            .finally(function() {
                res.end();
            });
    });
};

exports['@singleton'] = true;
exports['@require'] = ['app', 'config', 'fleet'];

Fix order of headers in response


"use strict";
/*jslint browser: true, nomen: true*/
/*global define*/

define([], function () {
    return function (frame) {
        var player = frame.player(),
            layout = frame.layout();

        frame.after(1, function() {
            frame.model().clear();
            layout.invalidate();
        })

        .after(500, function () {
            frame.model().title = '
The End
'
                        + '
' + frame.model().controls.html();
            layout.invalidate();
        })
        .after(500, function () {
            frame.model().controls.show();
        })

        .after(500, function () {
            frame.model().title = '
For more information:
'
                        + '
The Raft Paper
'
                        + '
Raft Web Site
'
                        + '
' + frame.model().controls.html();
            layout.invalidate();
        })

        player.play();
    };
});

Update Raft web site link


import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
} from 'react-native';

import I18n from 'react-native-i18n'

class Profile extends Component{

  async _onPressAddStory(){
    try {

    }
  }
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.title}>Smeagles {I18n.t('profile')}</Text>
        <Text style={styles.body}> {JSON.stringify(this.props.users)}</Text>
        <Text style={styles.body}> Temporary for styling Skeleton </Text>
        <TouchableHighlight onPress={this._onPressAddStory}.bind(this)} style={styles.button}>
        <Text style={styles.buttonText}>
        </Text>
        </TouchableHighlight>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
   marginTop: 25,
   fontSize: 20,
   alignSelf: 'center',
   margin: 40,
  },
  body: {
    flex: 0.1,
  }
});

module.exports = Profile;

import React, { Component } from 'react';

import {
  StyleSheet,
  Text,
  View,
  TouchableHighlight,
} from 'react-native';

import I18n from 'react-native-i18n'

class Profile extends Component{

_onPressAddStory(){

  }
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.title}>Smeagles {I18n.t('profile')}</Text>
        <Text style={styles.body}> {JSON.stringify(this.props.users)}</Text>
        <Text style={styles.body}> Temporary for styling Skeleton </Text>
        <TouchableHighlight onPress={this._onPressAddStory.bind(this)} style={styles.button}>
          <Text style={styles.buttonText}>
          Add Story
          </Text>
        </TouchableHighlight>
      </View>
    )
  }
};

var styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  title: {
   marginTop: 25,
   fontSize: 20,
   alignSelf: 'center',
   margin: 40,
  },
  body: {
    flex: 0.1,
  }
});

module.exports = Profile;

Fix error, need to add PressAddStory button


export default function dashesToCamelCase(str) {

    return str.charAt(0).toUpperCase() + str.slice(1);
};

export default function dashesToCamelCase(str) {
    return str.replace(/-([a-z])/g, function (g) {
        return g[1].toUpperCase();
    });
};

Add helper for converting dashed words to lower camel case


const path = require('path')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: resolve('src/index.js'),
  output: {
    path: resolve('dist'),
    filename: '[name].js'
  },
  resolve: {
    alias: {
      '@': resolve('src')
    }
  },
  module: {
    rules: [
      // general resolve
      {
        test: /\.js$/,
        use: 'babel-loader',
        include: resolve('src')
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader']
        }),
        include: resolve('src/assets')
      }
    ]
  },
  plugins: [
    // generate index.html based on src/index.html
    new HtmlWebpackPlugin({
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      }
    })
  ]
}

const path = require('path')
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const HtmlWebpackPlugin = require('html-webpack-plugin')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: resolve('src/index.js'),
  output: {
    path: resolve('dist'),
    filename: '[name].js'
  },
  resolve: {
    alias: {
      '@': resolve('src')
    }
  },
  module: {
    rules: [
      // general resolve
      {
        test: /\.js$/,
        use: 'babel-loader',
        include: resolve('src')
      },
      {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: ['css-loader', 'sass-loader']
        }),
        include: resolve('src/assets')
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'index.html',
      minify: {
        removeComments: true,
        collapseWhitespace: true,
        removeAttributeQuotes: true
      }
    })
  ]
}

Update HTML Webpack Plugin to use index.html as template


define(
  ['data/data', 'collections/v3/interactions', 'collections/v3/datasuitcases', 'models/v3/DataSuitcase', 'collections/v3/forms', 'models/v3/form'],
  function (Backbone, InteractionCollection, DataSuitcaseCollection, DataSuitcase, FormCollection, Form) {
    "use strict";
    var Application = Backbone.Model.extend({

      initialize: function () {
                // Nested interactions
        this.interactions = new InteractionCollection();

                // Nested Data Suitcases
        this.datasuitcases = new DataSuitcaseCollection();

        this.on('change', this.update);
      },

      update: function () {
        if (this.has("DataSuitcases")) {
          var ds = this.get("DataSuitcases"),
            count,
            dsmodel;
          for (count = 0; count < ds.length; count = count + 1) {
            if (this.datasuitcases.where({name: ds[count]}).length === 0) {
              dsmodel = new DataSuitcase({
                name: ds[count],
                siteName: this.get("siteName"),
                BICtype: "DataSuitcase"
              });
              this.datasuitcases.add(dsmodel);
              dsmodel.fetch();
            }
          }
        }
      }
    }),
      app;

    app = new Application();

    return app;
  }
);

define(
  ['data/data', 'collections/v3/interactions', 'collections/v3/datasuitcases', 'models/v3/DataSuitcase', 'collections/v3/forms', 'models/v3/form'],
  function (Backbone, InteractionCollection, DataSuitcaseCollection, DataSuitcase, FormCollection, Form) {
    "use strict";
    var Application = Backbone.Model.extend({

      initialize: function () {
                // Nested interactions
        this.interactions = new InteractionCollection();

                // Nested Data Suitcases
        this.datasuitcases = new DataSuitcaseCollection();
        this.forms = new FormCollection();

        this.on('change', this.update);
      },

      update: function () {
        var modelArray = this.get("DataSuitcases"),
          count,
          model,
          children = {
            DataSuitcases: this.datasuitcases,
            Forms: this.forms
          };

        if (this.has("DataSuitcases")) {
          modelArray = this.get("DataSuitcases");
          for (count = 0; count < modelArray.length; count = count + 1) {
            if (this.datasuitcases.where({name: modelArray[count]}).length === 0) {
              model = new DataSuitcase({
                name: modelArray[count],
                siteName: this.get("siteName"),
                BICtype: "DataSuitcase"
              });
              this.datasuitcases.add(model);
              model.fetch();
            }
          }
        }
      }
    }),
      app;

    app = new Application();

    return app;
  }
);

Create a collection for Forms


const { KafkaJSNotImplemented } = require('../../../errors')

const Types = {
  None: 0,
  GZIP: 1,
  Snappy: 2,
  LZ4: 3,
}

const Codecs = {
  [Types.GZIP]: () => require('./gzip'),
  [Types.Snappy]: () => {
    throw new KafkaJSNotImplemented('Snappy compression not implemented')
  },
  [Types.LZ4]: () => {
    throw new KafkaJSNotImplemented('LZ4 compression not implemented')
  },
}

const lookupCodec = type => (Codecs[type] ? Codecs[type]() : null)
const lookupCodecByAttributes = attributes => {
  const codec = Codecs[attributes & 0x3]
  return codec ? codec() : null
}

module.exports = {
  Types,
  Codecs,
  lookupCodec,
  lookupCodecByAttributes,
}

const { KafkaJSNotImplemented } = require('../../../errors')

const MESSAGE_CODEC_MASK = 0x3
const RECORD_BATCH_CODEC_MASK = 0x07

const Types = {
  None: 0,
  GZIP: 1,
  Snappy: 2,
  LZ4: 3,
}

const Codecs = {
  [Types.GZIP]: () => require('./gzip'),
  [Types.Snappy]: () => {
    throw new KafkaJSNotImplemented('Snappy compression not implemented')
  },
  [Types.LZ4]: () => {
    throw new KafkaJSNotImplemented('LZ4 compression not implemented')
  },
}

const lookupCodec = type => (Codecs[type] ? Codecs[type]() : null)
const lookupCodecByAttributes = attributes => {
  const codec = Codecs[attributes & MESSAGE_CODEC_MASK]
  return codec ? codec() : null
}
const lookupCodecByRecordBatchAttributes = attributes => {
  const codec = Codecs[attributes & RECORD_BATCH_CODEC_MASK]
  return codec ? codec() : null
}

module.exports = {
  Types,
  Codecs,
  lookupCodec,
  lookupCodecByAttributes,
  lookupCodecByRecordBatchAttributes,
}

Add support for Record Batch compression codec flag


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var WALLPAPER_PICKER_WIDTH = 550;
var WALLPAPER_PICKER_HEIGHT = 420;

var wallpaperPickerWindow;

chrome.app.runtime.onLaunched.addListener(function() {
  if (wallpaperPickerWindow && !wallpaperPickerWindow.contentWindow.closed) {
    wallpaperPickerWindow.focus();
    chrome.wallpaperPrivate.minimizeInactiveWindows();
    return;
  }

  chrome.app.window.create('main.html', {
    frame: 'chrome',
    width: WALLPAPER_PICKER_WIDTH,
    height: WALLPAPER_PICKER_HEIGHT
  }, function(w) {
    wallpaperPickerWindow = w;
    chrome.wallpaperPrivate.minimizeInactiveWindows();
    w.onClosed.addListener(function() {
      chrome.wallpaperPrivate.restoreMinimizedWindows();
    });
  });
});

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

var WALLPAPER_PICKER_WIDTH = 550;
var WALLPAPER_PICKER_HEIGHT = 420;

var wallpaperPickerWindow;

chrome.app.runtime.onLaunched.addListener(function() {
  if (wallpaperPickerWindow && !wallpaperPickerWindow.contentWindow.closed) {
    wallpaperPickerWindow.focus();
    chrome.wallpaperPrivate.minimizeInactiveWindows();
    return;
  }

  chrome.app.window.create('main.html', {
    frame: 'chrome',
    width: WALLPAPER_PICKER_WIDTH,
    height: WALLPAPER_PICKER_HEIGHT,
    minWidth: WALLPAPER_PICKER_WIDTH,
    maxWidth: WALLPAPER_PICKER_WIDTH,
    minHeight: WALLPAPER_PICKER_HEIGHT,
    maxHeight: WALLPAPER_PICKER_HEIGHT
  }, function(w) {
    wallpaperPickerWindow = w;
    chrome.wallpaperPrivate.minimizeInactiveWindows();
    w.onClosed.addListener(function() {
      chrome.wallpaperPrivate.restoreMinimizedWindows();
    });
  });
});

Disable resize of wallpaper picker


module.exports = {
  "extends": "./index.js",
  "parser": "babel-eslint",
  "env": {
    "browser": true
  },
  "plugins": [
    "lit", "html"
  ],
  "globals": {
    "D2L": false
  },
  "rules": {
    "strict": 0,
    "lit/no-duplicate-template-bindings": 2,
    "lit/no-legacy-template-syntax": 2,
    "lit/no-template-bind": 2,
    "lit/no-template-map": 0,
    "lit/no-useless-template-literals": 2,
    "lit/attribute-value-entities": 2,
    "lit/binding-positions": 2,
    "lit/no-property-change-update": 2,
    "lit/no-invalid-html": 2,
    "lit/no-value-attribute": 2
  }
};

module.exports = {
  "extends": "./index.js",
  "parser": "babel-eslint",
  "env": {
    "browser": true
  },
  "plugins": [
    "lit", "html"
  ],
  "globals": {
    "D2L": false
  },
  "rules": {
    "strict": [2, "never"],
    "lit/no-duplicate-template-bindings": 2,
    "lit/no-legacy-template-syntax": 2,
    "lit/no-template-bind": 2,
    "lit/no-template-map": 0,
    "lit/no-useless-template-literals": 2,
    "lit/attribute-value-entities": 2,
    "lit/binding-positions": 2,
    "lit/no-property-change-update": 2,
    "lit/no-invalid-html": 2,
    "lit/no-value-attribute": 2
  }
};

Update strict to error if present since it is redundant in modules, and not really necessary in demo pages.


Photo = function (doc) {
  _.extend(this, doc);
};

_.extend(Photo.prototype, {
	getImgTag: function (dimension) {
		return {
			'class': 'lazy',
			'data-src': _.str.sprintf(
				'%s/photos/%s/%s',
				Meteor.settings.public.uri.cdn,
				dimension,
				this.filename
			),
			'data-src-retina': _.str.sprintf(
				'%s/photos/%s@2x/%s',
				Meteor.settings.public.uri.cdn,
				dimension,
				this.filename
			),
			alt: this.title,
			width: dimension,
			height: dimension
		};
	}
});

Photos = new Mongo.Collection('Photos', {
	transform: function (doc) { return new Photo(doc); }
});

Photo = function (doc) {
  _.extend(this, doc);
};

_.extend(Photo.prototype, {
	getImgTag: function (dimension) {
		return {
			'class': 'lazy',
			'src': 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
			'data-src': _.str.sprintf(
				'%s/photos/%s/%s',
				Meteor.settings.public.uri.cdn,
				dimension,
				this.filename
			),
			'data-src-retina': _.str.sprintf(
				'%s/photos/%s@2x/%s',
				Meteor.settings.public.uri.cdn,
				dimension,
				this.filename
			),
			alt: this.title,
			width: dimension,
			height: dimension
		};
	}
});

Photos = new Mongo.Collection('Photos', {
	transform: function (doc) { return new Photo(doc); }
});

Use a transparent pixel to hold the height


import createTestHelpers from '../createTestHelpers';
const {expectTransform, expectNoChange} = createTestHelpers(['no-strict']);

describe('Removal of "use strict"', () => {
  it('should remove statement with "use strict" string', () => {
    expectTransform('"use strict";').toReturn('');
    expectTransform('\'use strict\';').toReturn('');
  });

  it('should remove the whole line where "use strict" used to be', () => {
    expectTransform('"use strict";\nfoo();').toReturn('foo();');
    expectTransform('foo();\n"use strict";\nbar();').toReturn('foo();\nbar();');
  });

  it('should not remove comments before "use strict"', () => {
    expectTransform('// foo();\n"use strict";\nbar();').toReturn('// foo();\nbar();');
  });

  it('should keep "use strict" used inside other code', () => {
    expectNoChange('x = "use strict";');
    expectNoChange('foo("use strict");');
  });
});

import createTestHelpers from '../createTestHelpers';
const {expectTransform, expectNoChange} = createTestHelpers(['no-strict']);

describe('Removal of "use strict"', () => {
  it('should remove statement with "use strict" string', () => {
    expectTransform('"use strict";').toReturn('');
    expectTransform('\'use strict\';').toReturn('');
  });

  it('should remove the whole line where "use strict" used to be', () => {
    expectTransform(
      '"use strict";\n' +
      'foo();'
    ).toReturn(
      'foo();'
    );

    expectTransform(
      'foo();\n' +
      '"use strict";\n' +
      'bar();'
    ).toReturn(
      'foo();\n' +
      'bar();'
    );
  });

  it('should not remove comments before "use strict"', () => {
    expectTransform(
      '// comment\n' +
      '"use strict";\n' +
      'bar();'
    ).toReturn(
      '// comment\n' +
      'bar();'
    );
  });

  it('should keep "use strict" used inside other code', () => {
    expectNoChange('x = "use strict";');
    expectNoChange('foo("use strict");');
  });
});

Split multiline tests to actual multiple lines


import { moduleForComponent, test } from 'ember-qunit';<% if (testType === 'integration') { %>
import hbs from 'htmlbars-inline-precompile';<% } %>

moduleForComponent('<%= componentPathName %>', '<%= friendlyTestDescription %>', {
  <% if (testType === 'integration' ) { %>integration: true<% } else if(testType === 'unit') { %>// Specify the other units that are required for this test
  // needs: ['component:foo', 'helper:bar'],
  unit: true<% } %>
});

test('it renders', function(assert) {
  <% if (testType === 'integration' ) { %>// Set any properties with this.set('myProperty', 'value');
  // Handle any actions with this.on('myAction', function(val) { ... });

  this.render(hbs`{{<%= componentPathName %>}}`);

  assert.equal(this.$().text().trim(), '');

  // Template block usage:
  this.render(hbs`
    {{#<%= componentPathName %>}}
      template block text
    {{/<%= componentPathName %>}}
  `);

  assert.equal(this.$().text().trim(), 'template block text');<% } else if(testType === 'unit') { %>
  // Creates the component instance
  /*let component =*/ this.subject();
  // Renders the component to the page
  this.render();
  assert.equal(this.$().text().trim(), '');<% } %>
});

import { moduleForComponent, test } from 'ember-qunit';<% if (testType === 'integration') { %>
import hbs from 'htmlbars-inline-precompile';<% } %>

moduleForComponent('<%= componentPathName %>', '<%= friendlyTestDescription %>', {
  <% if (testType === 'integration' ) { %>integration: true<% } else if(testType === 'unit') { %>// Specify the other units that are required for this test
  // needs: ['component:foo', 'helper:bar'],
  unit: true<% } %>
});

test('it renders', function(assert) {
<% if (testType === 'integration' ) { %>
  // Set any properties with this.set('myProperty', 'value');
  // Handle any actions with this.on('myAction', function(val) { ... });

  this.render(hbs`{{<%= componentPathName %>}}`);

  assert.equal(this.$().text().trim(), '');

  // Template block usage:
  this.render(hbs`
    {{#<%= componentPathName %>}}
      template block text
    {{/<%= componentPathName %>}}
  `);

  assert.equal(this.$().text().trim(), 'template block text');<% } else if(testType === 'unit') { %>
  // Creates the component instance
  /*let component =*/ this.subject();
  // Renders the component to the page
  this.render();
  assert.equal(this.$().text().trim(), '');<% } %>
});

Remove space from generated unit-tests


export default function () {
  this.passthrough('/translations/**');

  this.get('/api/locale', { locale: 'en' });
}

export default function () {
  this.passthrough('/translations/**');

  this.get('/api/locale', { locale: 'en' });

  this.get('/api/notifications', { events: [] });
}

Add basic `GET /api/notifications` route handler


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

import { getModeIcon } from '../../util/itinerary'

export default class ModeButton extends Component {
  static propTypes = {
    active: PropTypes.bool,
    label: PropTypes.string,
    mode: PropTypes.string,
    icons: PropTypes.object,
    onClick: PropTypes.func
  }

  render () {
    const {active, icons, label, mode, onClick} = this.props
    const buttonColor = active ? '#000' : '#bbb'
    return (

        <button
          className='mode-button'
          onClick={onClick}
          title={mode}
          style={{ borderColor: buttonColor }}
        >

            {getModeIcon(mode, icons)}

        </button>

{label}

        {active &&

}

    )
  }
}

Change color of mode button checkboxes to green


'use strict';

import React from 'react';

import ActivityIndicator from './pure/activityIndicator';

import ui from '../../ui';

class Loading extends React.Component {

  static propTypes = {
    dispatch: React.PropTypes.func.isRequired,
    kind: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.arrayOf(React.PropTypes.string)
    ]).isRequired,
    uri: React.PropTypes.string.isRequired,
    where: React.PropTypes.string.isRequired
  };

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const { dispatch, kind, uri, where, readId } = this.props;
    dispatch({type: 'READ_PERFORM', uri, where, kind, readId});
  }

  render() {
    return (
      <ActivityIndicator />
    );
  }
}

ui.register(['__loading'], ({ element, dispatch}) => {
  return (
    <Loading
      kind={element.get('kind').toJS()}
      uri={element.get('uri')}
      where={element.get('where', 'content')}
      dispatch={dispatch}
      readId={element.get('readId')}/>
  );
});

'use strict';

import React from 'react';

import ActivityIndicator from './pure/activityIndicator';

import ui from '../../ui';

class Loading extends React.Component {

  static propTypes = {
    dispatch: React.PropTypes.func.isRequired,
    kind: React.PropTypes.oneOfType([
      React.PropTypes.string,
      React.PropTypes.arrayOf(React.PropTypes.string)
    ]).isRequired,
    uri: React.PropTypes.string.isRequired,
    where: React.PropTypes.string.isRequired,
    readId: React.PropTypes.string.isRequired
  };

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const { dispatch, kind, uri, where, readId } = this.props;
    dispatch({type: 'READ_PERFORM', uri, where, kind, readId});
  }

  render() {
    return (
      <ActivityIndicator />
    );
  }
}

ui.register(['__loading'], ({ element, dispatch}) => {
  return (
    <Loading
      kind={element.get('kind').toJS()}
      uri={element.get('uri')}
      where={element.get('where', 'content')}
      dispatch={dispatch}
      readId={element.get('readId')}/>
  );
});

Add missing prop validation for readId


var mode = 0; //primary

function calc_mode() {
	var modes = ["primary", "secondary", "tertiary"];
	return modes[mode];
}

$(function() {
	$(".add").button();
	$(".edit").button();
	$(".delete").button().click(function() {
		var res = confirm("Are you sure you want to delete this item?");
		if (res)
			window.location.href=$(this).attr('href');
		else
			return false;
	});
	$(".view").button();
	$(".submit").button();

	$("#ingredients_table table").tablesorter();
	$("#effects_table table").tablesorter();

	$("#calc_ingredients tbody").find('tr').each(function(){
		$(this).click(function(){
			$('#'+calc_mode()).html($(this).text());
		});
	});
});

var mode = 0; //primary

function calc_mode() {
	var modes = ["primary", "secondary", "tertiary"];
	return modes[mode];
}

$(function() {
	$(".add").button();
	$(".edit").button();
	$(".delete").button().click(function() {
		var res = confirm("Are you sure you want to delete this item?");
		if (res)
			window.location.href=$(this).attr('href');
		else
			return false;
	});
	$(".view").button();
	$(".submit").button();

	$("#ingredients_table table").tablesorter();
	$("#effects_table table").tablesorter();

	$("#calc_ingredients tbody").find('tr').each(function(){
		$(this).click(function(){
			$('#'+calc_mode()).html($(this).text());
		});
	});

	$("#primary").click(function(){
		$(this).text('--');
		mode = 0;
	});

	$("#secondary").click(function(){
		$(this).text('--');
		mode = 1;
	});

	$("#tertiary").click(function(){
		$(this).text('--');
		mode = 2;
	});
});

Add events handler on selected ingredients


export default {
  run(editor, sender, opts = {}) {
    const modal = editor.Modal;
    const am = editor.AssetManager;
    const config = am.getConfig();
    const title = opts.modalTitle || editor.t('assetManager.modalTitle') || '';
    const types = opts.types;
    const accept = opts.accept;

    am.setTarget(opts.target);
    am.onClick(opts.onClick);
    am.onDblClick(opts.onDblClick);
    am.onSelect(opts.onSelect);

    if (!this.rendered || types) {
      let assets = am.getAll().filter(i => i);

      if (types && types.length) {
        assets = assets.filter(a => types.indexOf(a.get('type')) !== -1);
      }

      am.render(assets);
      this.rendered = am.getContainer();
    }

    if (accept) {
      const uploadEl = this.rendered.querySelector(
        `input#${config.stylePrefix}uploadFile`
      );
      uploadEl && uploadEl.setAttribute('accept', accept);
    }

    modal.open({ title, content: this.rendered });
    return this;
  }
};

export default {
  run(editor, sender, opts = {}) {
    const modal = editor.Modal;
    const am = editor.AssetManager;
    const config = am.getConfig();
    const title = opts.modalTitle || editor.t('assetManager.modalTitle') || '';
    const types = opts.types;
    const accept = opts.accept;

    am.setTarget(opts.target);
    am.onClick(opts.onClick);
    am.onDblClick(opts.onDblClick);
    am.onSelect(opts.onSelect);

    if (!this.rendered || types) {
      let assets = am.getAll().filter(i => i);

      if (types && types.length) {
        assets = assets.filter(a => types.indexOf(a.get('type')) !== -1);
      }

      am.render(assets);
      this.rendered = am.getContainer();
    }

    if (accept) {
      const uploadEl = this.rendered.querySelector(
        `input#${config.stylePrefix}uploadFile`
      );
      uploadEl && uploadEl.setAttribute('accept', accept);
    }

    modal
      .open({ title, content: this.rendered })
      .onceClose(() => editor.stopCommand(this.id));
    return this;
  },

  stop(editor) {
    const { Modal } = editor;
    Modal && Modal.close();
  }
};

Add stop command to openAssets


module.exports = {
  'root': true,

  'parser': 'babel-eslint',

  'extends': [
    'airbnb',
    'plugin:import/errors'
  ],

  'rules': {
    'space-before-function-paren': 0,
    'comma-dangle': [2, 'never'],
    'one-var': 0,
    'one-var-declaration-per-line': 0,
    'prefer-arrow-callback': 0,
    'strict': 0,
    'no-use-before-define': [2, {'functions': false}],
    'no-underscore-dangle': 0,

    'react/wrap-multilines': 0,
    'react/prefer-stateless-function': 0,
    'react/jsx-first-prop-new-line': 0,
    'react/jsx-no-bind': 0,
    'react/sort-comp': [2, {
      order: [
        'displayName',
        'propTypes',
        'mixins',
        'statics',
        'getDefaultProps',
        'getInitialState',
        'constructor',
        'render',
        '/^_render.+$/', // any auxiliary _render methods
        'componentWillMount',
        'componentDidMount',
        'componentWillReceiveProps',
        'shouldComponentUpdate',
        'componentWillUpdate',
        'componentDidUpdate',
        'componentWillUnmount',
        '/^on[A-Z].+$/', // event handlers
        'everything-else',
        '/^_.+$/' // private methods
      ]
    }]
  }
}

module.exports = {
  'root': true,

  'parser': 'babel-eslint',

  'extends': [
    'airbnb',
    'plugin:import/errors'
  ],

  'rules': {
    'space-before-function-paren': 0,
    'comma-dangle': [2, 'never'],
    'one-var': 0,
    'one-var-declaration-per-line': 0,
    'prefer-arrow-callback': 0,
    'strict': 0,
    'no-use-before-define': [2, {'functions': false}],
    'no-underscore-dangle': 0,

    'react/wrap-multilines': 0,
    'react/prefer-stateless-function': 0,
    'react/jsx-first-prop-new-line': 0,
    'react/jsx-no-bind': 0,
    'react/sort-comp': [2, {
      order: [
        'displayName',
        'propTypes',
        'mixins',
        'statics',
        'getDefaultProps',
        'defaultProps',
        'getInitialState',
        'constructor',
        'render',
        '/^_render.+$/', // any auxiliary _render methods
        'componentWillMount',
        'componentDidMount',
        'componentWillReceiveProps',
        'shouldComponentUpdate',
        'componentWillUpdate',
        'componentDidUpdate',
        'componentWillUnmount',
        '/^on[A-Z].+$/', // event handlers
        'everything-else',
        '/^_.+$/' // private methods
      ]
    }]
  }
}

Enforce that defaultProps sit next to statics


module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module"
  },
  plugins: ["ember"],
  extends: [
    "eslint:recommended",
    "plugin:ember/recommended",
    "plugin:prettier/recommended"
  ],
  env: {
    browser: true
  },
  rules: {
    "prettier/prettier": 2,
    "ember/new-module-imports": 2
  },
  overrides: [
    // node files
    {
      files: [
        "index.js",
        "testem.js",
        "ember-cli-build.js",
        "config/**/*.js",
        "tests/dummy/config/**/*.js",
        "blueprints/**/*.js"
      ],
      excludedFiles: ["app/**", "addon/**", "tests/dummy/app/**"],
      parserOptions: {
        sourceType: "script",
        ecmaVersion: 2015
      },
      env: {
        browser: false,
        node: true
      },
      plugins: ["node"],
      rules: Object.assign(
        {},
        require("eslint-plugin-node").configs.recommended.rules,
        {
          // add your custom rules and overrides for node files here
        }
      )
    }
  ]
};

module.exports = {
  root: true,
  parserOptions: {
    ecmaVersion: 2017,
    sourceType: "module"
  },
  plugins: ["ember", "prettier"],
  extends: [
    "eslint:recommended",
    "plugin:ember/recommended",
    "plugin:prettier/recommended"
  ],
  env: {
    browser: true
  },
  rules: {
    "prettier/prettier": 2,
    "ember/new-module-imports": 2
  },
  overrides: [
    // node files
    {
      files: [
        "index.js",
        "testem.js",
        "ember-cli-build.js",
        "config/**/*.js",
        "tests/dummy/config/**/*.js",
        "blueprints/**/*.js"
      ],
      excludedFiles: ["app/**", "addon/**", "tests/dummy/app/**"],
      parserOptions: {
        sourceType: "script",
        ecmaVersion: 2015
      },
      env: {
        browser: false,
        node: true
      },
      plugins: ["node"],
      rules: Object.assign(
        {},
        require("eslint-plugin-node").configs.recommended.rules,
        {
          // add your custom rules and overrides for node files here
        }
      )
    }
  ]
};

Add prettier as eslint plugin


import devcards from '../';
import React from 'react';
import Button from './Button';

var devcard = devcards.ns('buttons');

devcard(
  'Buttons',
  `
  A simple display of bootstrap buttons.

  * default
  * primary
  * success
  * info
  * warning
  * danger
  * link
  `,
  (
    <div>
      <Button kind="default">default</Button>
      <Button kind="primary">primary</Button>
      <Button kind="success">success</Button>
      <Button kind="info">info</Button>
      <Button kind="warning">warning</Button>
      <Button kind="danger">danger</Button>
      <Button kind="link">link</Button>
    </div>
  )
);

import devcards from '../';
import React from 'react';
import Button from './Button';

var devcard = devcards.ns('buttons');

devcard(
  'Buttons',
  `
  A simple display of bootstrap buttons.

  * default
  * primary
  * success
  * info
  * warning
  * danger
  * link
  `,
  <div style={{textAlign: 'center'}}>
    <Button kind="default">default</Button>
    <Button kind="primary">primary</Button>
    <Button kind="success">success</Button>
    <Button kind="info">info</Button>
    <Button kind="warning">warning</Button>
    <Button kind="danger">danger</Button>
    <Button kind="link">link</Button>
  </div>
);

Align as an option isn't ideal, include inline style example instead


import { unlinkUser } from '../lib/postgres';

export default (bot) => {
  return async (payload, reply) => {
    const page_scoped_id = payload.sender.id;

    await unlinkUser(page_scoped_id);
    await reply({ text: 'You have successfully logged out' });
    console.log(`Unlinked account -> ${page_scoped_id}`);
  };
};

import { unlinkUser } from '../lib/postgres';

export default (bot) => {
  return async (payload, reply) => {
    const page_scoped_id = payload.sender.id;

    await unlinkUser(page_scoped_id);
    await reply({ text: 'You have successfully logged out from EBudgie' });
    console.log(`Unlinked account -> ${page_scoped_id}`);
  };
};

Change messega for unlinking account


/* @flow */
import { FETCHED_MEMBER } from '../../../shared/redux/modules/member.js'
import { mergeAll, converge, unapply, compose, objOf, prop } from 'ramda'

import type { Action, Reducer } from 'redux'

type State = {}

const reducer: Reducer<State, Action> =
  (state = { id: 0, address: [], name: '' }, { type, payload }) => {
    switch (type) {
      case FETCHED_MEMBER:
        return converge
          ( unapply(mergeAll)
          , [ compose(objOf('name'), getName)
            , compose(objOf('address'), getAddress)
            , compose(objOf('id'), prop('id'))
            ]
          )(payload)
      default:
        return state
    }
  }

const getName = ({ title, full_name }) => title + ' ' + full_name

const getAddress = (
  { title
  , first_name = ''
  , last_name = ''
  , address1
  , address2
  , address3
  , address4
  , county
  , postcode
  }
) =>
  [ `${title} ${first_name[0] || ''} ${last_name}`, address1, address2,
    address3, address4, county, postcode ]

export default reducer

/* @flow */
import { FETCHED_MEMBER } from '../../../shared/redux/modules/member.js'
import { mergeAll, converge, unapply, compose, objOf, prop } from 'ramda'

import type { Action, Reducer } from 'redux'

type State = {}

const reducer: Reducer<State, Action> =
  (state = { id: 0, address: [], name: '' }, { type, payload }) => {
    switch (type) {
      case FETCHED_MEMBER:
        return converge
          ( unapply(mergeAll)
          , [ compose(objOf('name'), getName)
            , compose(objOf('address'), getAddress)
            , compose(objOf('id'), prop('id'))
            ]
          )(payload)
      default:
        return state
    }
  }

const getName = ({ title, full_name }) => title + ' ' + full_name

const getAddress = (
  { title
  , first_name = ''
  , last_name = ''
  , address1
  , address2
  , address3
  , address4
  , county
  , postcode
  }
) =>
  [ `${title} ${(first_name && first_name[0]) || ''} ${last_name}`
  , address1
  , address2
  , address3
  , address4
  , county
  , postcode ]

export default reducer

Fix bug that meant member details not displaying if no first name had been entered.


define([
  'angular'
],
function (angular) {
  'use strict';

  angular
    .module('kibana.directives')
    .directive('configModal', function($modal,$q) {
      return {
        restrict: 'A',
        link: function(scope, elem) {

          // create a new modal. Can't reuse one modal unforunately as the directive will not
          // re-render on show.
          elem.bind('click',function(){

            var tmpScope = scope.$new();
            tmpScope.panel = angular.copy(scope.panel);

            tmpScope.editSave = function(panel) {
              scope.panel = panel;
            };

            var panelModal = $modal({
              template: './app/partials/paneleditor.html',
              persist: true,
              show: false,
              scope: tmpScope,
              keyboard: false
            });

            // and show it
            $q.when(panelModal).then(function(modalEl) {
              modalEl.modal('show');
            });
            scope.$apply();
          });
        }
      };
    });
});

define([
  'angular',
  'underscore'
],
function (angular,_) {
  'use strict';

  angular
    .module('kibana.directives')
    .directive('configModal', function($modal,$q) {
      return {
        restrict: 'A',
        link: function(scope, elem) {

          // create a new modal. Can't reuse one modal unforunately as the directive will not
          // re-render on show.
          elem.bind('click',function(){

            // Create a temp scope so we can discard changes to it if needed
            var tmpScope = scope.$new();
            tmpScope.panel = angular.copy(scope.panel);

            tmpScope.editSave = function(panel) {
              // Correctly set the top level properties of the panel object
              _.each(panel,function(v,k) {
                scope.panel[k] = panel[k];
              });
            };

            var panelModal = $modal({
              template: './app/partials/paneleditor.html',
              persist: true,
              show: false,
              scope: tmpScope,
              keyboard: false
            });

            // and show it
            $q.when(panelModal).then(function(modalEl) {
              modalEl.modal('show');
            });
            scope.$apply();
          });
        }
      };
    });
});

Fix saving of top level panel properties


function arrayToList(array) {
    let list = null;
    for (let i = array.length - 1; i >= 0; --i) {
        list = {value: array[i], rest: list};
    }
    return list;
}

function listToArray(list) {
    let array = [];
    for (let node = list; node; node = node.rest) {
        array.push(node.value);
    }
    return array;
}

function prepend(element, list) {
    return {element, rest: list};
}

function nth(list, n) {
    // Could check if (!list) here instead or in the return expression
    if (n === 0) return list.value;
    else return list.rest ? nth(list.rest, n-1) : undefined;
}

function arrayToList(arr) {
	if (arr.length == 0) return null;

	let list = null;
	for (let i = arr.length - 1; i >= 0; --i) {
		list = {value: arr[i], rest: list};
	}

	return list;
}

function listToArray(list) {
	let arr = [];

	for (let node = list; node; node = node.rest) {
		arr.push(node.value)
	}

	return arr;
}

function prepend(elem, list) {
	return {value: elem, rest: list};
}

function nth(list, n) {
	if (n == 0) {
		return list.value;
	}

	if (list.rest == null) {
		return undefined;
	}

	return nth(list.rest, n -1);
}

Add chapter 4, exercise 3


module.exports = {
    "Dagens bedrift": "PRESENTATIONS",
    "Fest og moro": "NIGHTLIFE",
    "Konsert": "MUSIC",
    "Kurs og events": "PRESENTATIONS",
    "Revy og teater": "PERFORMANCES",
    "Foredrag": "PRESENTATIONS",
    "Møte": "DEBATE",
    "Happening": "NIGHTLIFE",
    "Kurs": "OTHER",
    "Show": "PERFORMANCES",
    "Fotballkamp": "SPORT",
    "Film": "PRESENTATIONS",
    "Samfundsmøte": "DEBATE",
    "Excenteraften": "DEBATE",
    "Temafest": "NIGHTLIFE",
    "Bokstavelig talt": "DEBATE",
    "Quiz": "OTHER",
    "DJ": "MUSIC",
    "Teater": "PERFORMANCES",
    "Annet": "OTHER",
    "Kurs": "PRESENTATIONS",
    "Omvising": "PRESENTATIONS",
    "Samfunn": "DEBATE",
    "Festival": "PERFORMANCES",
    "Sport": "SPORT",
    "Forestilling": "PERFORMANCES"
};

module.exports = {
    "Dagens bedrift": "PRESENTATIONS",
    "Fest og moro": "NIGHTLIFE",
    "Konsert": "MUSIC",
    "Kurs og events": "PRESENTATIONS",
    "Revy og teater": "PERFORMANCES",
    "Foredrag": "PRESENTATIONS",
    "Møte": "DEBATE",
    "Happening": "NIGHTLIFE",
    "Kurs": "OTHER",
    "Show": "PERFORMANCES",
    "Fotballkamp": "SPORT",
    "Film": "PRESENTATIONS",
    "Samfundsmøte": "DEBATE",
    "Excenteraften": "DEBATE",
    "Temafest": "NIGHTLIFE",
    "Bokstavelig talt": "DEBATE",
    "Quiz": "OTHER",
    "DJ": "MUSIC",
    "Teater": "PERFORMANCES",
    "Annet": "OTHER",
    "Kurs": "PRESENTATIONS",
    "Omvising": "PRESENTATIONS",
    "Samfunn": "DEBATE",
    "Festival": "PERFORMANCES",
    "Sport": "SPORT",
    "Forestilling": "PERFORMANCES",
    "Utstilling" : "EXHIBITIONS"
};

Add category mapping for exhibitions


function render(viewName, layoutPath) {
    if (!layoutPath) {
        return function (req, res) {
            res.render(viewName);
        };
    }
    else {
        return function (req, res) {
            res.render(viewName, { layout: layoutPath });
        };
    }

}

module.exports = {
    render: render
};

function render(viewName, layoutPath) {
    return function (req, res) {
        if (layoutPath) {
            res.locals.layout = layoutPath;
        }

        res.render(viewName);
    };
}

module.exports = {
    render: render
};

Change implementation of `render` route


var path = require('path');
var url = require('url');

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

var ssr = require('../index');
var xhr = require('./xhr');
var proxy = require('./proxy');

module.exports = function (config) {
	var app = express()
		.use(compression())
		.use(xhr());

	var pkgPath = path.join(config.path, 'package.json');
	var pkg = require(pkgPath);
	var render = ssr({
		config: pkgPath + '!npm',
		main: pkg.main
	});

	if (config.configure) {
		config.configure(app);
	}

	if (config.proxy) {
		var apiPath = config.proxyTo || '/api';
		app.use(apiPath, proxy(config.proxy));
	}

	app.use(express.static(path.join(config.path)));

	app.use("/", function (req, res) {
		const pathname = url.parse(req.url).pathname;

		render(pathname).then(res.send.bind(res));
	});

	return app;
};

var path = require('path');
var url = require('url');

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

var ssr = require('../index');
var xhr = require('./xhr');
var proxy = require('./proxy');
var doctype = '<!DOCTYPE html>';

module.exports = function (config) {
	var app = express()
		.use(compression())
		.use(xhr());

	var pkgPath = path.join(config.path, 'package.json');
	var pkg = require(pkgPath);
	var render = ssr({
		config: pkgPath + '!npm',
		main: pkg.main
	});

	if (config.configure) {
		config.configure(app);
	}

	if (config.proxy) {
		var apiPath = config.proxyTo || '/api';
		app.use(apiPath, proxy(config.proxy));
	}

	app.use(express.static(path.join(config.path)));

	app.use("/", function (req, res) {
		var pathname = url.parse(req.url).pathname;

		render(pathname).then(function(html) {
			var dt = config.doctype || doctype;
			res.send(dt + '\n' + html);
		});
	});

	return app;
};

Add HTML5 doctype to all rendered pages.


// External
import * as d3 from 'd3';

export function mergeSelections (selections) {
  // Create a new empty selection
  const mergedSelection = d3.selectAll('.d3-list-graph-not-existent');

  function pushSelection (selection) {
    selection.each(function pushDomNode () {
      mergedSelection[0].push(this);
    });
  }

  for (let i = selections.length; i--;) {
    pushSelection(selections[i]);
  }

  return mergedSelection;
}

export function allTransitionsEnded (transition, callback) {
  if (transition.size() === 0) {
    callback();
  }
  let n = 0;
  transition
    .each(() => ++n)
    .on('end', function (...args) {
      if (!--n) callback.apply(this, args);
    });
}

// External
import * as d3 from 'd3';

export function mergeSelections (selections) {
  // Create a new empty selection
  const mergedSelection = d3.selectAll('.d3-list-graph-not-existent');

  for (let i = selections.length; i--;) {
    mergedSelection._groups = mergedSelection._groups.concat(
      selections[i]._groups
    );
  }

  return mergedSelection;
}

export function allTransitionsEnded (transition, callback) {
  if (transition.size() === 0) {
    callback();
  }
  let n = 0;
  transition
    .each(() => ++n)
    .on('end', function (...args) {
      if (!--n) callback.apply(this, args);
    });
}

Adjust selection merge method to D3 v4.


let scheduler = null

export function setScheduler (customScheduler) {
  if (customScheduler) {
    scheduler = customScheduler
  } else {
    scheduler = new DefaultScheduler()
  }
}

export function getScheduler () {
  return scheduler
}

class DefaultScheduler {
  constructor () {
    this.updateRequests = []
    this.frameRequested = false
    this.performUpdates = this.performUpdates.bind(this)
  }

  updateDocument (fn) {
    this.updateRequests.push(fn)
    if (!this.frameRequested) {
      this.frameRequested = true
      window.requestAnimationFrame(this.performUpdates)
    }
  }

  performUpdates () {
    this.frameRequested = false

    while (this.updateRequests.length > 0) {
      this.updateRequests.shift()()
    }
  }
}

let scheduler = null

export function setScheduler (customScheduler) {
  scheduler = customScheduler
}

export function getScheduler () {
  if (!scheduler) {
    scheduler = new DefaultScheduler()
  }
  return scheduler
}

class DefaultScheduler {
  constructor () {
    this.updateRequests = []
    this.frameRequested = false
    this.performUpdates = this.performUpdates.bind(this)
  }

  updateDocument (fn) {
    this.updateRequests.push(fn)
    if (!this.frameRequested) {
      this.frameRequested = true
      window.requestAnimationFrame(this.performUpdates)
    }
  }

  performUpdates () {
    this.frameRequested = false

    while (this.updateRequests.length > 0) {
      this.updateRequests.shift()()
    }
  }
}

Use the DefaultScheduler if none is assigned


/*
 * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
 *
 * 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.
 */

Ext.define('Traccar.store.MapTypes', {
    extend: 'Ext.data.Store',
    fields: ['key', 'name'],
    data: [
        {'key': 'osm', 'name': strings.mapOsm},
        {'key': 'bingRoad', 'name': strings.mapBingRoad},
        {'key': 'bingAerial', 'name': strings.mapBingAerial},
        {'key': 'custom', 'name': strings.mapCustom},
    ]
});

/*
 * Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
 *
 * 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.
 */

Ext.define('Traccar.store.MapTypes', {
    extend: 'Ext.data.Store',
    fields: ['key', 'name'],

    data: [{
        key: 'osm',
        name: strings.mapOsm
    }, {
        key: 'bingRoad',
        name: strings.mapBingRoad
    }, {
        key: 'bingAerial',
        name: strings.mapBingAerial
    }, {
        key: 'custom',
        name: strings.mapCustom
    }]
});

Fix map types class formatting


/*
 * Exporst function that checks if given emails of users are shown
 * on the Teamview page. And if so how they are rendered: as text or link.
 *
 * It does not check exact emails, just count numbers.
 *
 * */

'use strict';

var
  By             = require('selenium-webdriver').By,
  expect         = require('chai').expect,
  open_page_func = require('../lib/open_page'),
  bluebird        = require("bluebird");

module.exports = bluebird.promisify( function(args, callback){

  var
    result_callback = callback,
    driver          = args.driver,
    emails          = args.emails || [],
    is_link         = args.is_link || false,
    application_host = args.application_host || 'http://localhost:3000/';

  if ( ! driver ) {
    throw "'driver' was not passed into the teamview_check_user!";
  }

  return open_page_func({
    url    : application_host + 'calendar/teamview/',
    driver : driver,
  })

  .then(function(data){
    return data.driver
      .findElements(By.css( 'tr.teamview-user-list-row > td > ' + (is_link ? 'a' : 'span') ))
      .then(function(elements){
        expect(elements.length).to.be.equal( emails.length );
        return bluebird.resolve(data);
      });
  })

  .then(function(data){
    // "export" current driver
    result_callback(
      null,
      {
        driver : data.driver,
      }
    );
  });

});

/*
 * Exporst function that checks if given emails of users are shown
 * on the Teamview page. And if so how they are rendered: as text or link.
 *
 * It does not check exact emails, just count numbers.
 *
 * */

'use strict';

var
  By             = require('selenium-webdriver').By,
  expect         = require('chai').expect,
  open_page_func = require('./open_page'),
  config         = require('./config'),
  bluebird        = require("bluebird");

module.exports = bluebird.promisify( function(args, callback){

  var
    result_callback = callback,
    driver          = args.driver,
    emails          = args.emails || [],
    is_link         = args.is_link || false,
    application_host = args.application_host || config.get_application_host();

  if ( ! driver ) {
    throw "'driver' was not passed into the teamview_check_user!";
  }

  return open_page_func({
    url    : application_host + 'calendar/teamview/',
    driver : driver,
  })

  .then(function(data){
    return data.driver
      .findElements(By.css( 'tr.teamview-user-list-row > td > ' + (is_link ? 'a' : 'span') ))
      .then(function(elements){
        expect(elements.length).to.be.equal( emails.length );
        return bluebird.resolve(data);
      });
  })

  .then(function(data){
    // "export" current driver
    result_callback(
      null,
      {
        driver : data.driver,
      }
    );
  });

});

Remove hardcoded localhost in one more place.


import {
  moduleForModel,
  test
} from 'ember-qunit';

moduleForModel('employee', {
  // Specify the other units that are required for this test.
  needs: []
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});

import DS from 'ember-data';
import Ember from 'ember';
import { test, moduleForModel } from 'ember-qunit';

//import startApp from '../../helpers/start-app';

//var App;

moduleForModel('employee', {
  // Specify the other units that are required for this test.
    needs: []//,
    //setup: function(){
    //    App = startApp();
    //},
    //teardown: function(){
    //    Ember.run(App, 'destroy');
    //}
});

test('it exists', function(assert) {
  var model = this.subject();
  // var store = this.store();
  assert.ok(!!model);
});

test('it returns fields', function(assert) {
  var model = this.subject({ firstName: "Ivanov", lastName: "Ivan" });
  var store = this.store();
  assert.ok(model);
  assert.ok(model instanceof DS.Model);
  assert.equal(model.get('firstName'), "Ivanov");
  assert.equal(model.get('lastName'), "Ivan");

  // set a relationship
  Ember.run(function() {
    model.set('reportsTo', store.createRecord('employee', { firstName: "Sidorov", lastName: "Sidor" }));
  });

  var reportsToEmployee = model.get('reportsTo');
  assert.ok(reportsToEmployee);
  assert.equal(reportsToEmployee.get('firstName'), "Sidorov");
  assert.equal(reportsToEmployee.get('lastName'), "Sidor");
});

Add simple test on employee relation


"use strict";

var _ = require('underscore')
  , Project = require('./project')

/*
 * Mixin for models which require a project to be set.
 *
 * Looks for attribute, collection, and explicit passing in options. Will raise
 * an error if no project is found, or if different projects are found.
 */
module.exports = {
  constructor: function (attributes, options) {
    var candidates, results, slug;

    candidates = {
      options: options && options.project,
      collection: options && options.collection && options.collection.project,
      attributes: attributes && attributes.project
    }

    if (candidates.attributes) {
      slug = candidates.attributes.url.match(/[^\/]+/g).slice(-1);
      candidates.attributes = new Project({
        name: candidates.attributes.name,
        slug: slug
      });
    }

    results = _.chain(candidates).filter(function (p) { return p instanceof Project });

    if (!results.value().length) {
      throw new Error('Must pass a project object, either in options, collection, or attributes.');
    }

    if (results.map(function (p) { return p.get('slug') }).uniq().value().length > 1) {
      throw new Error('Two different projects passed. Not possible.')
    }

    // Take the first result
    this.project = results.first().value();
  }
}

"use strict";

var _ = require('underscore')
  , Project = require('./project')

/*
 * Mixin for models which require a project to be set.
 *
 * Looks for attribute, collection, and explicit passing in options. Will raise
 * an error if no project is found, or if different projects are found.
 */
module.exports = {
  constructor: function (attributes, options) {
    var candidates, results, slug;

    candidates = {
      options: options && options.project,
      collection: options && options.collection && options.collection.project,
      attributes: attributes && attributes.project
    }

    if (candidates.attributes) {
      slug = candidates.attributes.url.match(/[^\/]+/g).slice(-1);
      candidates.attributes = new Project({
        name: candidates.attributes.name,
        slug: slug
      });
    }

    results = _.chain(candidates).filter(function (p) { return p instanceof Project });

    if (!results.value().length) {
      throw new Error('Must pass a project object, either in options, collection, or attributes.');
    }

    if (results.map(function (p) { return p.get('slug') }).flatten().uniq().value().length > 1) {
      throw new Error('Two different projects passed.')
    }

    // Take the first result
    this.project = results.first().value();
  }
}

Fix bug in project-specific backbone model mixin


var vows = require('vows'),
    assert = require('assert'),
    namedColorSamples = require('./samples'),
    spaces = [
        'rgb',
        'hsl',
        'hsv'
    ];

function createTest(bundleFileName) {
    var Color = require(bundleFileName),
        batch = {};

    Object.keys(namedColorSamples).forEach(function (namedColor) {
        var sub = batch[namedColor + ': ' + namedColorSamples[namedColor]] = {
            topic: Color(namedColorSamples[namedColor])
        };
        spaces.forEach(function (space) {
            sub[space.toUpperCase() + ' hex string comparison'] = function (topic) {
                assert.equal(topic[space]().hex(), topic.hex());
            };
            /*
            sub[space.toUpperCase() + ' strict comparison'] = function (topic) {
                assert.ok(topic.equals(topic[space]()));
            };*/
        });
    });

    return batch;
}
/*
vows.describe('Color').addBatch({
    'base, debug': createTest('../one-color-debug'),
    'base, minified': createTest('../one-color')
}).export(module);
*/
spaces.push(
    'cmyk',
    'xyz'/*,
    'lab'*/
);

vows.describe('Color-all').addBatch({
    //'all, debug': createTest('../one-color-all-debug'),
    'all, minified': createTest('../one-color-all')
}).export(module);

var vows = require('vows'),
    assert = require('assert'),
    namedColorSamples = require('./samples'),
    spaces = [
        'rgb',
        'hsl',
        'hsv'
    ];

function createTest(bundleFileName) {
    var Color = require(bundleFileName),
        batch = {};

    Object.keys(namedColorSamples).forEach(function (namedColor) {
        var sub = batch[namedColor + ': ' + namedColorSamples[namedColor]] = {
            topic: Color(namedColorSamples[namedColor])
        };
        spaces.forEach(function (space) {
            sub[space.toUpperCase() + ' hex string comparison'] = function (topic) {
                assert.equal(topic[space]().hex(), topic.hex());
            };
            /*
            sub[space.toUpperCase() + ' strict comparison'] = function (topic) {
                assert.ok(topic.equals(topic[space]()));
            };*/
        });
    });

    return batch;
}
/*
vows.describe('Color').addBatch({
    'base, debug': createTest('../one-color-debug'),
    'base, minified': createTest('../one-color')
}).export(module);
*/
spaces.push(
    'cmyk'/*,
    'xyz',
    'lab'*/
);

vows.describe('Color-all').addBatch({
    //'all, debug': createTest('../one-color-all-debug'),
    'all, minified': createTest('../one-color-all')
}).export(module);

Disable XYZ testing. Unclear if the tests or the implementation is wrong


'use strict';

const assert = require('assert');

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

const dataSchema = new mongoose.Schema({
    'contents': String
});

dataSchema.plugin(require('../../index'));

const dataModel = mongoose.model('data', dataSchema);

describe('createOrUpdate', () => {

    let dataId = null;

    before(done => {

        mongoose.connect('mongodb://localhost/test');

        dataModel.find().remove(done);

    });

    after(done => {

        dataModel.find().remove(() => {

            mongoose.connection.close(done);

        });

    });

    it('create without document', done => {

        dataModel.createOrUpdate({
            '_id': dataId
        }, {
            'contents': 'Lorem ipsum dolor sit amet'
        }).then(data => {

            dataId = data._id;

            done();

        }).catch(err => {

            console.log(err);

        });

    });

    it('update with existing document', done => {

        dataModel.createOrUpdate({
            '_id': dataId
        }, {
            'contents': 'Hello, world!'
        }).then(data => {

            assert.equal(data._id, dataId);
            assert.equal(data.contents, 'Hello, world!');

            done();

        }).catch(err => {

            console.log(err);

        });

    });

});

'use strict';

const assert = require('assert');

const mongoose = require('mongoose');

mongoose.Promise = global.Promise;

const dataSchema = new mongoose.Schema({
    'contents': String
});

dataSchema.plugin(require('../../index'));

const dataModel = mongoose.model('data', dataSchema);

describe('createOrUpdate', () => {

    let dataId = null;

    before(done => {

        mongoose.connect('mongodb://localhost/test');

        dataModel.find().remove(done);

    });

    after(done => {

        dataModel.find().remove(() => {

            mongoose.connection.close(done);

        });

    });

    it('create without document', done => {

        dataModel.createOrUpdate({
            '_id': dataId
        }, {
            'contents': 'Lorem ipsum dolor sit amet'
        }).then(data => {

            dataId = data._id.toString();

            done();

        }).catch(err => {

            console.log(err);

        });

    });

    it('update with existing document', done => {

        dataModel.createOrUpdate({
            '_id': dataId
        }, {
            'contents': 'Hello, world!'
        }).then(data => {

            assert.equal(data._id.toString(), dataId);
            assert.equal(data.contents, 'Hello, world!');

            done();

        }).catch(err => {

            console.log(err);

        });

    });

});

Test against string version of ID.


/*global after, before, describe, it*/
'use strict';
var assert  = require('assert');
var grunt = require('grunt');
var path = require('path');
var sinon = require('sinon');

var statici18n = require('../tasks/statici18n');
statici18n(grunt);

describe('exists', function() {
  after(function() {
    grunt.log.warn.restore();
  });
  it('should nag and filter if the file is missing', function() {
    sinon.stub(grunt.log, 'warn');
    assert.equal(false, statici18n.exists('some/fake/file.txt'));
    sinon.assert.calledOnce(grunt.log.warn);
  });
  it('returns true with some real file', function() {
    var readme = path.join(__dirname, '..', 'README.md');
    assert.ok(statici18n.exists(readme));
  });
});

describe('static i18n task', function() {
  it('should create a file for french', function() {
    var i18n = path.join(__dirname, 'fixtures', 'app', 'i18n');
    var f = path.join(i18n, 'fr', 'static', 'data.json');
    assert.ok(grunt.file.exists(f), 'Not found: ' + f);
  });
});

Test for a french file (fails)


import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import angular from 'rollup-plugin-angular';
import typescript from 'rollup-plugin-typescript';
var sass = require('node-sass');
import {nameLibrary,PATH_SRC,PATH_DIST} from './config-library.js';
export default {
  entry: PATH_SRC+nameLibrary+'.ts',
  format: 'umd',
  moduleName: nameLibrary,
  external: [
    '@angular/core',
    "@angular/platform-browser",
    "rxjs/Rx",
    "@angular/forms"
  ],
  sourceMap:true,
  dest:PATH_DIST+nameLibrary+".umd.js",
  plugins: [
    angular(
      {
      preprocessors:{
        template:template => template,
        style: scss => {
            let css;
            if(scss){
              css = sass.renderSync({ data: scss }).css.toString();
              console.log(css);
            }else{
              css = '';
            }

            return css;
        },
      }
    }
    ),
    typescript({
      typescript:require('typescript')
    }),
    resolve({
      module: true,
      main: true
    }),
     commonjs({
      include: 'node_modules/**',
     })
  ],
   onwarn: warning => {
    const skip_codes = [
      'THIS_IS_UNDEFINED',
      'MISSING_GLOBAL_NAME'
    ];
    if (skip_codes.indexOf(warning.code) != -1) return;
    console.error(warning);
  }
};

import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import angular from 'rollup-plugin-angular';
import typescript from 'rollup-plugin-typescript';
var sass = require('node-sass');
import {nameLibrary,PATH_SRC,PATH_DIST} from './config-library.js';
export default {
  input: PATH_SRC+nameLibrary+'.ts',
  output: {
    name: nameLibrary,
    format: 'umd',
    file: PATH_DIST+nameLibrary+".umd.js",
    sourcemap:true,
  },
  external: [
    '@angular/core',
    "@angular/platform-browser",
    "rxjs/Rx",
    "@angular/forms"
  ],
  plugins: [
    angular(
      {
      preprocessors:{
        template:template => template,
        style: scss => {
            let css;
            if(scss){
              css = sass.renderSync({ data: scss }).css.toString();
              console.log(css);
            }else{
              css = '';
            }

            return css;
        },
      }
    }
    ),
    typescript({
      typescript:require('typescript')
    }),
    resolve({
      module: true,
      main: true
    }),
     commonjs({
      include: 'node_modules/**',
     })
  ],
   onwarn: warning => {
    const skip_codes = [
      'THIS_IS_UNDEFINED',
      'MISSING_GLOBAL_NAME'
    ];
    if (skip_codes.indexOf(warning.code) != -1) return;
    console.error(warning);
  }
};

Change deprecated config for USM


import test from 'ava';
import 'babel-core/register';

import AnalyzerResult from '../src/lib/analyzer-result';

test('addMessage adds expected message', t => {
  const testMessageType = 'test';
  const testMessageText = 'test-message';
  const result = new AnalyzerResult();

  result.addMessage(testMessageType, testMessageText);

  t.is(result.getMessage(testMessageType).text, testMessageText);

  // TODO: Add tests for line and column after changing what getMessage returns
});

test('getMessage returns null if message type does not exist', t => {
  const result = new AnalyzerResult();

  const message = result.getMessage('does-not-exist');

  t.is(message, null);
});

test('getMessage returns expected message text if it exists', t => {
  const testMessageType = 'test';
  const testMessageText = 'test-message';

  const result = new AnalyzerResult();
  result.addMessage(testMessageType, testMessageText);

  const messageText = result.getMessage(testMessageType).text;

  t.is(messageText, testMessageText);
});

import test from 'ava';
import 'babel-core/register';

import AnalyzerResult from '../src/lib/analyzer-result';

test('addMessage adds expected message', t => {
  const testMessageType = 'test';
  const testMessageText = 'test-message';
  const result = new AnalyzerResult();

  result.addMessage(testMessageType, testMessageText);

  t.is(result.getMessage(testMessageType).text, testMessageText);
});

test('addMessage adds expected line', t => {
  const testMessageType = 'test';
  const testMessageLine = 3;
  const result = new AnalyzerResult();

  result.addMessage(testMessageType, 'test-message', testMessageLine);

  t.is(result.getMessage(testMessageType).line, testMessageLine);
});

test('addMessage adds expected column', t => {
  const testMessageType = 'test';
  const testMessageColumn = 7;
  const result = new AnalyzerResult();

  result.addMessage(testMessageType, 'test-message', 3, testMessageColumn);

  t.is(result.getMessage(testMessageType).column, testMessageColumn);
});

test('getMessage returns null if message type does not exist', t => {
  const result = new AnalyzerResult();

  const message = result.getMessage('does-not-exist');

  t.is(message, null);
});

test('getMessage returns expected message text if it exists', t => {
  const testMessageType = 'test';
  const testMessageText = 'test-message';

  const result = new AnalyzerResult();
  result.addMessage(testMessageType, testMessageText);

  const messageText = result.getMessage(testMessageType).text;

  t.is(messageText, testMessageText);
});

Add tests to implement TODO comment


// @flow

import * as React from "react";
import css from "styled-jsx/css";

const promptStyle = css`
  .prompt {
    font-family: monospace;
    font-size: 12px;
    line-height: 22px;

    width: var(--prompt-width, 50px);
    padding: 9px 0;

    text-align: center;

    color: var(--theme-cell-prompt-fg, black);
    background-color: var(--theme-cell-prompt-bg, #fafafa);
  }
`;

// Totally fake component for consistency with indents of the editor area

export function promptText(props: PromptProps) {
  if (props.running) {
    return "[*]";
  }
  if (props.queued) {
    return "[…]";
  }
  if (typeof props.counter === "number") {
    return `[${props.counter}]`;
  }
  return "[ ]";
}

type PromptProps = {
  counter: number | null,
  running: boolean,
  queued: boolean
};

export class Prompt extends React.Component<PromptProps, null> {
  static defaultProps = {
    counter: null,
    running: false,
    queued: false
  };

  render() {
    return (
      <React.Fragment>

{promptText(this.props)}

      </React.Fragment>
    );
  }
}

export class PromptBuffer extends React.Component<any, null> {
  render() {
    return (
      <React.Fragment>

      </React.Fragment>
    );
  }
}

// @flow
import * as React from "react";

/**
 * Generate what text goes inside the prompt based on the props to the prompt
 */
export function promptText(props: PromptProps): string {
  if (props.running) {
    return "[*]";
  }
  if (props.queued) {
    return "[…]";
  }
  if (typeof props.counter === "number") {
    return `[${props.counter}]`;
  }
  return "[ ]";
}

type PromptProps = {
  counter: number | null,
  running: boolean,
  queued: boolean,
  blank: boolean
};

export class Prompt extends React.Component<PromptProps, null> {
  static defaultProps = {
    counter: null,
    running: false,
    queued: false,
    blank: false
  };

  render() {
    return (
      <React.Fragment>
        <div className="prompt">
          {this.props.blank ? null : promptText(this.props)}
        </div>
        <style jsx>{`
          .prompt {
            font-family: monospace;
            font-size: 12px;
            line-height: 22px;

            width: var(--prompt-width, 50px);
            padding: 9px 0;

            text-align: center;

            color: var(--theme-cell-prompt-fg, black);
            background-color: var(--theme-cell-prompt-bg, #fafafa);
          }
        `}</style>
      </React.Fragment>
    );
  }
}

export const PromptBuffer = () => <Prompt blank />;

Make <PromptBuffer> a special case of <Prompt>


const mongoose = require('mongoose')
const middleware = require('./middleware/Feed.js')
const path = require('path')
const fs = require('fs')
const packageVersion = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'))).version

const schema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  url: {
    type: String,
    required: true
  },
  guild: {
    type: String,
    required: true
  },
  channel: {
    type: String,
    required: true
  },
  webhook: {
    id: String,
    name: String,
    avatar: String
  },
  split: {
    char: String,
    prepend: String,
    append: String,
    maxLength: Number
  },
  disabled: String,
  checkTitles: Boolean,
  checkDates: Boolean,
  imgPreviews: Boolean,
  imgLinksExistence: Boolean,
  formatTables: Boolean,
  toggleRoleMentions: Boolean,
  version: {
    type: String,
    default: packageVersion
  },
  addedAt: {
    type: Date,
    default: Date.now
  }
})

schema.pre('findOneAndUpdate', middleware.findOneAndUpdate)
schema.pre('remove', middleware.remove)
schema.pre('save', middleware.save)

exports.schema = schema
exports.model = mongoose.model('Feed', schema)

const mongoose = require('mongoose')
const middleware = require('./middleware/Feed.js')
const path = require('path')
const fs = require('fs')
const packageVersion = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'))).version

const schema = new mongoose.Schema({
  title: {
    type: String,
    required: true
  },
  url: {
    type: String,
    required: true
  },
  guild: {
    type: String,
    required: true
  },
  channel: {
    type: String,
    required: true
  },
  webhook: {
    id: String,
    name: String,
    avatar: String
  },
  split: {
    enabled: Boolean,
    char: String,
    prepend: String,
    append: String,
    maxLength: Number
  },
  disabled: String,
  checkTitles: Boolean,
  checkDates: Boolean,
  imgPreviews: Boolean,
  imgLinksExistence: Boolean,
  formatTables: Boolean,
  toggleRoleMentions: Boolean,
  version: {
    type: String,
    default: packageVersion
  },
  addedAt: {
    type: Date,
    default: Date.now
  }
})

schema.pre('findOneAndUpdate', middleware.findOneAndUpdate)
schema.pre('remove', middleware.remove)
schema.pre('save', middleware.save)

exports.schema = schema
exports.model = mongoose.model('Feed', schema)

Add enabled key, and if all other keys are empty use default vals


#!/usr/bin/env node

var fs = require('fs')
var path = require('path')
var chalk = require('chalk')

function show (result) {
  Object.keys(result).sort().reverse().forEach(file => {
    var test = file.replace(/\.test\.js\.snap$/, '')
    result[file].split('exports[`')
      .filter(str => str.indexOf('// ') !== 0)
      .forEach(str => {
        if (str.trim().length === 0) return
        var parts = str.replace(/"\s*`;\s*$/, '').split(/`] = `\s*"/)
        process.stdout.write(
          chalk.gray(`${ test } ${ parts[0].replace(/ 1$/, '') }:\n\n`))
        process.stdout.write(parts[1])
      })
  })
}

fs.readdir(__dirname, (err, list) => {
  if (err) throw err
  var snaps = list.filter(i => /\.snap$/.test(i))

  var result = { }
  snaps.forEach(file => {
    fs.readFile(path.join(__dirname, file), (err2, content) => {
      if (err2) throw err2
      result[file] = content.toString()
      if (Object.keys(result).length === snaps.length) show(result)
    })
  })
})

#!/usr/bin/env node

var fs = require('fs')
var path = require('path')
var chalk = require('chalk')

var filter = process.argv[2]

function show (result) {
  Object.keys(result).sort().reverse().forEach(file => {
    var test = file.replace(/\.test\.js\.snap$/, '')
    result[file].split('exports[`')
      .filter(str => str.indexOf('// ') !== 0)
      .filter(str => !filter || str.indexOf(filter) !== -1)
      .forEach(str => {
        if (str.trim().length === 0) return
        var parts = str.replace(/"\s*`;\s*$/, '').split(/`] = `\s*"/)
        process.stdout.write(
          chalk.gray(`${ test } ${ parts[0].replace(/ 1$/, '') }:\n\n`))
        process.stdout.write(parts[1])
      })
  })
}

fs.readdir(__dirname, (err, list) => {
  if (err) throw err
  var snaps = list.filter(i => /\.snap$/.test(i))

  var result = { }
  snaps.forEach(file => {
    fs.readFile(path.join(__dirname, file), (err2, content) => {
      if (err2) throw err2
      result[file] = content.toString()
      if (Object.keys(result).length === snaps.length) show(result)
    })
  })
})

Add filters to snapshot preview


var bot = require( 'nodemw' ),
	readline = require( 'readline' ),
	rl = readline.createInterface( {
		input: process.stdin,
		output: process.stdout
	} ),
	client = new Bot( {
		protocol: 'https',
		server: 'dev.fandom.com',
		path: ''
	} ),
	params = {
		action: 'scribunto-console',
		title: 'Module:CLI/testcases/title',
		clear: true
	};

function session( err, content ) {
	params.content = content;
	rl.on( 'line', cli );
}

function cli( input ) {
	params.question = input;
	client.api.call( params, call );
}

function call( err, info, next, data ) {
	if ( err ) {
		console.error( err );
	} else if ( data.type === 'error' ) {
		console.error( data.message );
	} else {
		console.log( data.print );
	}
}

client.getArticle( params.title, session );

var Bot = require( 'nodemw' ),
	readline = require( 'readline' ),
	rl = readline.createInterface( {
		input: process.stdin,
		output: process.stdout
	} ),
	client = new Bot( {
		protocol: 'https',
		server: 'dev.fandom.com',
		path: ''
	} ),
	params = {
		action: 'scribunto-console',
		title: 'Module:CLI/testcases/title',
		clear: true
	};

function session( err, content ) {
	params.content = content;
	rl.on( 'line', cli );
}

function cli( input ) {
	params.question = input;
	client.api.call( params, call );
}

function call( err, info, next, data ) {
	if ( err ) {
		console.error( err );
	} else if ( data.type === 'error' ) {
		console.error( data.message );
	} else {
		console.log( data.print );
	}
}

client.getArticle( params.title, session );

Fix unused and undefined vars


module.exports = {
  // Autoprefixer
  autoprefixer: {
    // https://github.com/postcss/autoprefixer#browsers
    browsers: [
      'Explorer >= 10',
      'ExplorerMobile >= 10',
      'Firefox >= 30',
      'Chrome >= 34',
      'Safari >= 7',
      'Opera >= 23',
      'iOS >= 7',
      'Android >= 4.4',
      'BlackBerry >= 10'
    ]
  },
  // BrowserSync
  browserSync: {
    browser: 'default', // or ["google chrome", "firefox"]
    https: false, // Enable https for localhost development.
    notify: false, // The small pop-over notifications in the browser.
    port: 9000
  },
  // GitHub Pages
  ghPages: {
    branch: 'gh-pages',
    domain: 'polymer-starter-kit.startpolymer.org', // change it!
    origin: 'origin2' // default is 'origin'
  },
  // PageSpeed Insights
  // Please feel free to use the `nokey` option to try out PageSpeed
  // Insights as part of your build process. For more frequent use,
  // we recommend registering for your own API key. For more info:
  // https://developers.google.com/speed/docs/insights/v1/getting_started
  pageSpeed: {
    key: '', // need uncomment in task
    nokey: true,
    site: 'http://polymer-starter-kit.startpolymer.org', // change it!
    strategy: 'mobile' // or desktop
  }
};

module.exports = {
  // Autoprefixer
  autoprefixer: {
    // https://github.com/postcss/autoprefixer#browsers
    browsers: [
      'Explorer >= 10',
      'ExplorerMobile >= 10',
      'Firefox >= 30',
      'Chrome >= 34',
      'Safari >= 7',
      'Opera >= 23',
      'iOS >= 7',
      'Android >= 4.4',
      'BlackBerry >= 10'
    ]
  },
  // BrowserSync
  browserSync: {
    browser: 'default', // or ["google chrome", "firefox"]
    https: false, // Enable https for localhost development.
    notify: false, // The small pop-over notifications in the browser.
    port: 9000
  },
  // GitHub Pages
  ghPages: {
    branch: 'gh-pages',
    domain: 'polymer-starter-kit.startpolymer.org', // change it!
    origin: 'origin'
  },
  // PageSpeed Insights
  // Please feel free to use the `nokey` option to try out PageSpeed
  // Insights as part of your build process. For more frequent use,
  // we recommend registering for your own API key. For more info:
  // https://developers.google.com/speed/docs/insights/v1/getting_started
  pageSpeed: {
    key: '', // need uncomment in task
    nokey: true,
    site: 'http://polymer-starter-kit.startpolymer.org', // change it!
    strategy: 'mobile' // or desktop
  }
};

Revert remote origin to 'origin' for deploy github pages


const utils = require('../lib/utils')
const challenges = require('../data/datacache').challenges
const db = require('../data/mongodb')

module.exports = function trackOrder () {
  return (req, res) => {
    const id = insecurity.sanitizeProcessExit(utils.trunc(decodeURIComponent(req.params.id), 40))
    if (utils.notSolved(challenges.reflectedXssChallenge) && utils.contains(id, '<iframe src="javascript:alert(`xss`)">')) {
      utils.solve(challenges.reflectedXssChallenge)
    }
    db.orders.find({ $where: "this.orderId === '" + id + "'" }).then(order => {
      const result = utils.queryResultToJson(order)
      if (utils.notSolved(challenges.noSqlOrdersChallenge) && result.data.length > 1) {
        utils.solve(challenges.noSqlOrdersChallenge)
      }
      if (result.data[0] === undefined) {
        result.data[0] = { orderId: id }
      }
      res.json(result)
    }, () => {
      res.status(400).json({ error: 'Wrong Param' })
    })
  }
}

const utils = require('../lib/utils')
const insecurity = require('../lib/insecurity')
const challenges = require('../data/datacache').challenges
const db = require('../data/mongodb')

module.exports = function trackOrder () {
  return (req, res) => {
    const id = insecurity.sanitizeProcessExit(utils.trunc(decodeURIComponent(req.params.id), 40))
    if (utils.notSolved(challenges.reflectedXssChallenge) && utils.contains(id, '<iframe src="javascript:alert(`xss`)">')) {
      utils.solve(challenges.reflectedXssChallenge)
    }
    db.orders.find({ $where: "this.orderId === '" + id + "'" }).then(order => {
      const result = utils.queryResultToJson(order)
      if (utils.notSolved(challenges.noSqlOrdersChallenge) && result.data.length > 1) {
        utils.solve(challenges.noSqlOrdersChallenge)
      }
      if (result.data[0] === undefined) {
        result.data[0] = { orderId: id }
      }
      res.json(result)
    }, () => {
      res.status(400).json({ error: 'Wrong Param' })
    })
  }
}

Add missing import of insecurity lib


var keystone = require('keystone'),
	_ = require('underscore');

// Load models to allow fetching of slideshow data
var Slideshow = keystone.list('Slideshow'),
	SlideshowItems = keystone.list('Slideshow Item');

exports = module.exports = function(req, res) {
	'use strict';

	var view = new keystone.View(req, res),
		locals = res.locals;

	Slideshow.model.find()
		.where('title', 'Main Page Slideshow')
		.exec()
		.then(function (slideshow) {

			var slideshowId = slideshow[0].get('_id');

			SlideshowItems.model.find()
				.where('parent', slideshowId)
				.exec()
				.then(function (slides) {

					locals.slides = _.sortBy(slides, function(slide) { return +slide.order; });
					console.log(locals.slides);

					view.render('main');
				});

		});//.then(function() {

		// 	view.render('main');

		// });

	// TODO: Get the featured models
};

var keystone = require('keystone'),
	_ = require('underscore');

// Load models to allow fetching of slideshow data
var Slideshow = keystone.list('Slideshow'),
	SlideshowItems = keystone.list('Slideshow Item');

exports = module.exports = function(req, res) {
	'use strict';

	var view = new keystone.View(req, res),
		locals = res.locals;

	Slideshow.model.find()
		.where('title', 'Main Page Slideshow')
		.exec()
		.then(function (slideshow) {

			var slideshowId = slideshow[0].get('_id');

			SlideshowItems.model.find()
				.where('parent', slideshowId)
				.exec()
				.then(function (slides) {

					locals.slides = _.sortBy(slides, function(slide) { return +slide.order; });

					view.render('main');
				});

		});//.then(function() {

		// 	view.render('main');

		// });

	// TODO: Get the featured models
};

Remove logging messages cluttering the output log.


import React from "react";
import { Chance }from "chance";

import WriteMessage from "./components/WriteMessage";
import Messages from "./components/Messages";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { user: chance.name(), messages: [] }
  }

  componentDidMount() {
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    this.chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    this.chatsock.onmessage = (message) => {
      console.log(message);
      let messages = this.state.messages.slice();
      messages.push(JSON.parse(message.data));
      this.setState({messages: messages})
    };
  }

  sendMessage(msg) {
    const payload = {
      handle: this.state.user,
      message: msg
    };
    this.chatsock.send(JSON.stringify(payload));
  }

  render() {
    return (

M O O N Y

        <Messages
          messages={this.state.messages}
        />
        <WriteMessage
          sendMessage={this.sendMessage.bind(this)}
        />

    )
  }
}

import React from "react";
import { Chance }from "chance";

import WriteMessage from "./components/WriteMessage";
import Messages from "./components/Messages";

export default class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { user: chance.name(), messages: [], connected: false }
  }

  componentDidMount() {
    var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
    this.chatsock = new ReconnectingWebSocket(ws_scheme + '://' + window.location.host + "/chat" + window.location.pathname);

    this.chatsock.onopen = event => {
      this.setState({
        connected: true
      })
      console.log(this.chatsock);
    };

    this.chatsock.onclose = event => {
      this.setState({
        connected: false
      })
    };

    this.chatsock.onmessage = (message) => {
      console.log(message);
      let messages = this.state.messages.slice();
      messages.push(JSON.parse(message.data));
      this.setState({messages: messages})
    };
  }

  sendMessage(msg) {
    const payload = {
      handle: this.state.user,
      message: msg
    };
    this.chatsock.send(JSON.stringify(payload));
  }

  render() {
    return (

M O O N Y ({this.state.connected ? 'connected' : 'disconnected'})

        <Messages
          messages={this.state.messages}
        />
        <WriteMessage
          sendMessage={this.sendMessage.bind(this)}
        />

    )
  }
}

Put a connected visual help


import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import './Button.scss';

export default class Button extends Component {
  static propTypes = {
    onClick: PropTypes.func,
    type: PropTypes.oneOf(['button', 'submit', 'reset']),
    kind: PropTypes.oneOf(['yes', 'no', 'subtle']),
    disabled: PropTypes.bool,
    children: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
    small: PropTypes.bool,
    big: PropTypes.bool,
  }

  static defaultProps = {
    onClick: () => {},
    type: 'button',
    kind: null,
    disabled: false,
    small: false,
    big: false,
  }

  render() {
    const { kind, type, onClick, disabled, children, small, big } = this.props;
    const classes = classnames(
      'btn',
      { [`btn--${kind}`]: kind },
      { 'btn--small': small },
      { 'btn--big': big },
    );

    return (
      <button
        className={classes}
        type={type}
        onClick={onClick}
        disabled={disabled}
      >
        {children}
      </button>
    );
  }
}

import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import './Button.scss';

export default class Button extends Component {
  static propTypes = {
    onClick: PropTypes.func,
    type: PropTypes.oneOf(['button', 'submit', 'reset']),
    kind: PropTypes.oneOf(['yes', 'no', 'subtle']),
    disabled: PropTypes.bool,
    children: PropTypes.oneOfType([PropTypes.object, PropTypes.string]).isRequired,
    small: PropTypes.bool,
    big: PropTypes.bool,
  }

  static defaultProps = {
    onClick: () => {},
    type: 'button',
    kind: null,
    disabled: false,
    small: false,
    big: false,
  }

  render() {
    const { kind, type, onClick, disabled, children, small, big } = this.props;
    const classes = classnames(
      'btn',
      { [`btn--${kind}`]: kind },
      { 'btn--small': small },
      { 'btn--big': big },
    );

    if (type === 'submit') {
      return <input type="submit" disabled={disabled} className={classes} value={children} />;
    }

    return (
      <button
        className={classes}
        type={type}
        onClick={onClick}
        disabled={disabled}
      >
        {children}
      </button>
    );
  }
}

Improve semantics of submit button


exports.listeners = {

  wield: function (l10n) {
    return function (location, player, players) {
      player.say('You ready the weighty cleaver.');
      player.combat.addToHitMod({
        name: 'cleaver ' + this.getUuid(),
        effect: toHit => toHit + 1
      });
    }
  },

  remove: function (l10n) {
    return function (player) {
      player.say('You place the bulky cleaver in your pack.');
      player.combat.deleteAllMods('cleaver' + this.getUuid());
    }
  },

  hit: function (l10n) {
		return function (player) {
			player.say('<bold>The blade of your cleaver <red>does its job.</red></bold>');
      player.combat.addDamageMod({
        name: 'cleaver' + this.getUuid(),
        effect: damage => damage + .5
      });
		}
	}
};

exports.listeners = {

  wield: function (l10n) {
    return function (location, player, players) {
      player.say('You ready the weighty cleaver.');
      player.combat.addToHitMod({
        name: 'cleaver ' + this.getUuid(),
        effect: toHit => toHit + 1
      });
      player.combat.addToDodgeMod({
        name: 'cleaver ' + this.getUuid(),
        effect: dodge => dodge - 1
      });
    }
  },

  remove: function (l10n) {
    return function (player) {
      player.say('You place the bulky cleaver in your pack.');
      player.combat.deleteAllMods('cleaver' + this.getUuid());
    }
  },

  hit: function (l10n) {
		return function (player) {
			player.say('<bold>The blade of your cleaver <red>does its job.</red></bold>');
      player.combat.addDamageMod({
        name: 'cleaver' + this.getUuid(),
        effect: damage => damage + .5
      });
		}
	},

  parry: function(l10n) {
    return function (player) {
      player.say('<bold><white>The blade of your cleaver halts their attack.</white></bold>');
      player.combat.addDamageMod({
        name: 'cleaver' + this.getUuid(),
        effect: damage => damage - .5
      });
    }
  }
};

Add balancing for cleaver scripts.


const initialState = {
	profile: { data: null },
	name: { data: null },
	image: { data: null },
	barcode: { data: null }
}

function studentProfileReducer(state = initialState, action) {
	const newState = { ...state }
	switch (action.type) {
		case 'SET_STUDENT_PROFILE':
			newState.profile.data = action.profile
			return newState
		case 'SET_STUDENT_NAME':
			newState.name.data = action.name
			return newState
		case 'SET_STUDENT_PHOTO':
			newState.image.data = action.image
			return newState
		case 'SET_STUDENT_BARCODE':
			newState.barcode.data = action.barcode
			return newState
		case 'CLEAR_STUDENT_PROFILE_DATA':
			return initialState
		default:
			return state
	}
}

module.exports = studentProfileReducer

const initialState = {
	profile: { data: null },
	name: { data: null },
	image: { data: null },
	barcode: { data: null }
}

function studentProfileReducer(state = initialState, action) {
	const newState = { ...state }
	switch (action.type) {
		case 'SET_STUDENT_PROFILE':
			newState.profile.data = action.profile
			return newState
		case 'SET_STUDENT_NAME':
			newState.name.data = action.name
			return newState
		case 'SET_STUDENT_PHOTO':
			newState.image.data = action.image
			return newState
		case 'SET_STUDENT_BARCODE':
			newState.barcode.data = action.barcode
			return newState
		case 'CLEAR_STUDENT_PROFILE_DATA':
			return {
				profile: { data: null },
				name: { data: null },
				image: { data: null },
				barcode: { data: null }
			}
		default:
			return state
	}
}

module.exports = studentProfileReducer

Fix issue where data was not being cleared upon logout


import test from 'ava';
import TweetCardContent from '../lib/tweet-card-content';

const META_SECTION = "Tweet should be about";

test("Test static exports", (t) => {
    t.true("TWEET_CONTENT" in TweetCardContent);
    t.true("RETWEET" in TweetCardContent);
    t.true("SCHEDULED" in TweetCardContent);
});

test("Create card", (t) => {
    const meta = "test";
    const card = TweetCardContent.createCard(meta);
    t.true(card instanceof TweetCardContent);

    t.is(meta, card.getSection(META_SECTION));
    t.false(card.isRetweet);
    t.true(card.hasSection(TweetCardContent.TWEET_CONTENT));
    t.false(card.isValid);
});

test("Retweet", (t) => {
    const meta = "test";
    const card = TweetCardContent.createCard(meta, true);
    t.true(card instanceof TweetCardContent);

    t.is(meta, card.getSection(META_SECTION));
    t.true(card.isRetweet);
    t.true(card.hasSection(TweetCardContent.RETWEET));
    t.false(card.isValid;
});

test.todo("Test setSection");
test.todo("Test tweet length");
test.todo("Test with valid RT url");
test.todo("Test due date/SCHEDULED");
test.todo("Test error messages");

import test from 'ava';
import TweetCardContent from '../lib/tweet-card-content';

const META_SECTION = "Tweet should be about";

test("Test static exports", (t) => {
    t.true("TWEET_CONTENT" in TweetCardContent);
    t.true("RETWEET" in TweetCardContent);
    t.true("SCHEDULED" in TweetCardContent);
});

test("Create card", (t) => {
    const meta = "test";
    const card = TweetCardContent.createCard(meta);
    t.true(card instanceof TweetCardContent);

    t.is(meta, card.getSection(META_SECTION));
    t.false(card.isRetweet);
    t.true(card.hasSection(TweetCardContent.TWEET_CONTENT));
    t.false(card.isValid);
});

test("Retweet", (t) => {
    const meta = "test";
    const card = TweetCardContent.createCard(meta, true);
    t.true(card instanceof TweetCardContent);

    t.is(meta, card.getSection(META_SECTION));
    t.true(card.isRetweet);
    t.true(card.hasSection(TweetCardContent.RETWEET));
    t.false(card.isValid);
});

test.todo("Test setSection");
test.todo("Test tweet length");
test.todo("Test with valid RT url");
test.todo("Test due date/SCHEDULED");
test.todo("Test error messages");

Add closing ) that got removed by acident2


import { connect } from 'react-redux';
import Timeline from '../components/map/timeline';
import { updateFilters } from '../actions/filters';

const mapStateToProps = state => {
  return {
    filters: state.filters
  };
};

const mapDispatchToProps = dispatch => {
  return {
    updateFilters: filters => {
      // console.log('t:mapDispatchToProps', filters)
      dispatch(updateFilters(filters));
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Timeline);

import { connect } from 'react-redux';
import Timeline from '../components/map/Timeline';
import { updateFilters } from '../actions/filters';

const mapStateToProps = state => {
  return {
    filters: state.filters
  };
};

const mapDispatchToProps = dispatch => {
  return {
    updateFilters: filters => {
      // console.log('t:mapDispatchToProps', filters)
      dispatch(updateFilters(filters));
    }
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Timeline);

Fix casing in file import


import _ from 'lodash';

export const unexistedUID = '00000000-0000-0000-C000-000000000046';

export function initObject(classDef, attrs, id, params) {
  return new classDef({ ...attrs, id, ...params });
}

export function prepareModelPayload(payload, namesMapping, valuesMapping) {
  const result = {};
  const keys = _.intersection(Object.keys(payload), Object.keys(namesMapping));

  for (const key of keys) {
    const mappedKey = namesMapping[key];
    const mappedVal = valuesMapping[key] ? valuesMapping[key](payload[key]) : payload[key];
    result[mappedKey] = mappedVal;
  }

  return result;
}

import _ from 'lodash';
import pgFormat from 'pg-format';

import { List } from '../open-lists';

export const unexistedUID = '00000000-0000-0000-C000-000000000046';

export function initObject(classDef, attrs, id, params) {
  return new classDef({ ...attrs, id, ...params });
}

export function prepareModelPayload(payload, namesMapping, valuesMapping) {
  const result = {};
  const keys = _.intersection(Object.keys(payload), Object.keys(namesMapping));

  for (const key of keys) {
    const mappedKey = namesMapping[key];
    const mappedVal = valuesMapping[key] ? valuesMapping[key](payload[key]) : payload[key];
    result[mappedKey] = mappedVal;
  }

  return result;
}

// These helpers allow to use the IN operator with the empty list of values.
// 'IN <empty list>' always returns 'false' and 'NOT IN <empty list>' always returns 'true'.
// We don't escape 'field' here because pgFormat escaping doesn't work properly with dot-joined
// identifiers (as in 'table.field').

// export const sqlIn = (field, list) => list.length === 0 ? 'false' : pgFormat(`${field} in (%L)`, list);
// export const sqlNotIn = (field, list) => list.length === 0 ? 'true' : pgFormat(`${field} not in (%L)`, list);

export function sqlIn(field, list) {
  list = List.from(list);

  if (list.isEmpty()) {
    return 'false';
  } else if (list.isEverything()) {
    return 'true';
  }

  return pgFormat(`${field} ${list.inclusive ? 'in' : 'not in'} (%L)`, list.items);
}

export function sqlNotIn(field, list) {
  return sqlIn(field, List.difference(List.everything(), list));
}

export function sqlIntarrayIn(field, list) {
  list = new List(list);

  if (list.isEmpty()) {
    return 'false';
  } else if (list.isEverything()) {
    return 'true';
  }

  return pgFormat(`(${list.inclusive ? '' : 'not '}${field} && %L)`, `{${list.items.join(',')}}`);
}

Add helpers functions to generate SQL for 'field [NOT] IN somelist'


export default function authRequired(req, res, next) {
  if (req.user.isAdmin) {
    next();
  } else {
    res.status(403);
    res.json({
      id: 'AUTH_FORBIDDEN',
      message: 'You need admin privilege to run this command.'
    });
  }
}

export default function adminRequired(req, res, next) {
  if (req.user && req.user.isAdmin) {
    next();
  } else {
    res.status(403);
    res.json({
      id: 'AUTH_FORBIDDEN',
      message: 'You need admin privilege to run this command.'
    });
  }
}

Fix admin checking throwing error if not logged in