// @flow
import callAPI from 'app/actions/callAPI';
import { Tag } from './ActionTypes';
import type { Thunk } from 'app/types';
import { tagSchema } from 'app/reducers';

export function fetch(id: string): Thunk<*> {
  return callAPI({
    types: Tag.FETCH,
    endpoint: `/tags/${id}/`,
    schema: tagSchema,
    meta: {
      errorMessage: 'Henting av tag feilet',
    },
    propagateError: true,
  });
}

export function fetchPopular(): Thunk<*> {
  return callAPI({
    types: Tag.POPULAR,
    endpoint: `/tags/popular/`,
    meta: {
      errorMessage: 'Henting av populære tags feilet',
    },
    propagateError: false,
  });
}

export function fetchAll({ next = false }: { next: boolean } = {}): Thunk<*> {
  return (dispatch, getState) => {
    const cursor = next ? getState().tags.pagination.next : {};
    return dispatch(
      callAPI({
        types: Tag.FETCH,
        endpoint: '/tags/',
        schema: [tagSchema],
        query: {
          ...cursor,
        },
        meta: {
          errorMessage: 'Henting av tags feilet',
        },
        propagateError: true,
      })
    );
  };
}

// @flow
import callAPI from 'app/actions/callAPI';
import { Tag } from './ActionTypes';
import type { Thunk } from 'app/types';
import { tagSchema } from 'app/reducers';

export function fetch(id: string): Thunk<*> {
  return callAPI({
    types: Tag.FETCH,
    endpoint: `/tags/${id}/`,
    schema: tagSchema,
    meta: {
      errorMessage: 'Henting av tag feilet',
    },
    propagateError: true,
  });
}

export function fetchPopular(): Thunk<*> {
  return callAPI({
    types: Tag.POPULAR,
    endpoint: `/tags/popular/`,
    meta: {
      errorMessage: 'Henting av populære tags feilet',
    },
    propagateError: false,
  });
}

export function fetchAll({ next = false }: { next: boolean } = {}): Thunk<*> {
  return callAPI({
    types: Tag.FETCH,
    endpoint: '/tags/',
    schema: [tagSchema],
    pagination: {
      fetchNext: next,
    },
    meta: {
      errorMessage: 'Henting av tags feilet',
    },
    propagateError: true,
  });
}

Move tags to new pagination


'use strict';

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

class TableLocation extends Node
{
	constructor(complexIdent)
	{
		super();

		const source = complexIdent.fragments.shift();

		if (source !== '@') {
			throw new Error('Invalid table location');
		}

		this.fragments = complexIdent.fragments;
	}

	getFragments()
	{
		return this.fragments;
	}
}

module.exports = TableLocation;

'use strict';

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

class TableLocation extends ComplexIdent
{
	constructor(complexIdent)
	{
		super([]);

		const fragments = complexIdent.fragments.slice();
		const source = fragments.shift();

		if (source !== '@') {
			throw new Error('Invalid table location');
		}

		this.fragments = fragments;
	}
}

module.exports = TableLocation;

Make binding working in table location (JOIN)


function populateMarkers(mapData) {
	console.log(mapData[0]);
}

function initMap() {
	var element = document.createElement('div');
	var mapDiv = document.getElementById('map-hider').appendChild(element);
	mapDiv.id = 'map';
	mapDiv.style.cssText = 'width:100%; height:750px; margin: auto';
	var map = new google.maps.Map(mapDiv, {
		center: {lat: 54.2774, lng: -1.7126},
		zoom: 7
	});

	marker = new google.maps.Marker({
	  map: map,
	  animation: google.maps.Animation.DROP,
	  position: {lat: 54.2774, lng: -1.7126}
	});

	var mapdata = Papa.parse("https://rawcdn.githack.com/WearyWanderer/wearywanderer.github.io/master/assets/csv/wanderlustvids.csv", {
		download: true,
		complete: function(results) {
			console.log(results);
			populateMarkers(results);
		}
	});
}

window.onload = initMap;

function populateMarkers(mapData) {
	console.log(mapData[0]);
}

function initMap() {
	var element = document.createElement('div');
	var mapDiv = document.getElementById('map-hider').appendChild(element);
	mapDiv.id = 'map';
	mapDiv.style.cssText = 'width:100%; height:750px; margin: auto';
	var map = new google.maps.Map(mapDiv, {
		center: {lat: 54.2774, lng: -1.7126},
		zoom: 7
	});

	marker = new google.maps.Marker({
	  map: map,
	  animation: google.maps.Animation.DROP,
	  position: {lat: 54.2774, lng: -1.7126}
	});

	var mapdata = Papa.parse("https://rawcdn.githack.com/WearyWanderer/wearywanderer.github.io/master/assets/csv/wanderlustvids.csv", {
		download: true,
		complete: function(results) {
			console.log(results);
			populateMarkers(results.data);
		}
	});
}

window.onload = initMap;

Access data of object instead


/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      dziBaseUrl: '//s3-us-west-2.amazonaws.com/media.incrossada.org',
      title: 'la incrossada'
    }
  };

  if (environment === 'development') {
    // LOG_MODULE_RESOLVER is needed for pre-1.6.0
    ENV.LOG_MODULE_RESOLVER = true;

    ENV.APP.LOG_RESOLVER = true;
    ENV.APP.LOG_ACTIVE_GENERATION = true;
    ENV.APP.LOG_MODULE_RESOLVER = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      dziBaseUrl: '//s3-us-west-2.amazonaws.com/media.incrossada.org',
      title: 'la incrossada'
    }
  };

  if (environment === 'development') {
    // LOG_MODULE_RESOLVER is needed for pre-1.6.0
    ENV.LOG_MODULE_RESOLVER = true;

    ENV.APP.LOG_RESOLVER = false;
    ENV.APP.LOG_ACTIVE_GENERATION = true;
    ENV.APP.LOG_MODULE_RESOLVER = false;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'production') {

  }

  return ENV;
};

Reduce chattiness of dev debug logging


'use strict';

export {default as OCLE} from 'https://www.lactame.com/lib/openchemlib-extended/1.13.0/openchemlib-extended.js';
export {default as SD} from 'https://www.lactame.com/lib/spectra-data/2.1.0/spectra-data.js';
export {default as CCE} from 'https://www.lactame.com/lib/chemcalc-extended/1.27.0/chemcalc-extended.js';
export {default as elnPlugin} from 'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js';

'use strict';

export {default as OCLE} from 'https://www.lactame.com/lib/openchemlib-extended/1.13.0/openchemlib-extended.js';
//export {default as SD} from 'https://www.lactame.com/lib/spectra-data/2.1.0/spectra-data.js';
export {default as SD} from 'http://www.lactame.com/lib/spectra-data/HEAD/spectra-data.js';
export {default as CCE} from 'https://www.lactame.com/lib/chemcalc-extended/1.27.0/chemcalc-extended.js';
export {default as elnPlugin} from 'https://www.lactame.com/lib/eln-plugin/0.0.2/eln-plugin.js';

Change spectra-data to HEAD version for testing


'use strict';

var React = require('react-native');

var {
  requireNativeComponent,
  DeviceEventEmitter,
  View
} = React;

var Component = requireNativeComponent('RSSignatureView', null);

var styles = {
  signatureBox: {
    flex: 1
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'stretch',
    backgroundColor: '#F5FCFF',
  }
};

var saveEvent, cancelEvent;

var SignatureCapture = React.createClass({
  propTypes: {
    pitchEnabled: React.PropTypes.bool
  },

  componentDidMount: function() {
    saveEvent = DeviceEventEmitter.addListener('onSaveEvent', this.props.onSaveEvent);
    cancelEvent = DeviceEventEmitter.addListener('onCancelEvent', this.props.onCancelEvent);
  },

  componentWillUnmount: function() {
    saveEvent.remove();
    cancelEvent.remove();
  },

  render: function() {
    return (
      <View style={styles.container}>
        <Component style={styles.signatureBox} />
      </View>
    )
  }
});

module.exports = SignatureCapture;

'use strict';

var React = require('react');

var {
  requireNativeComponent,
  DeviceEventEmitter,
  View
} = require('react-native');

var Component = requireNativeComponent('RSSignatureView', null);

var styles = {
  signatureBox: {
    flex: 1
  },
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'stretch',
    backgroundColor: '#F5FCFF',
  }
};

var saveEvent, cancelEvent;

var SignatureCapture = React.createClass({
  propTypes: {
    pitchEnabled: React.PropTypes.bool
  },

  componentDidMount: function() {
    saveEvent = DeviceEventEmitter.addListener('onSaveEvent', this.props.onSaveEvent);
    cancelEvent = DeviceEventEmitter.addListener('onCancelEvent', this.props.onCancelEvent);
  },

  componentWillUnmount: function() {
    saveEvent.remove();
    cancelEvent.remove();
  },

  render: function() {
    return (
      <View style={styles.container}>
        <Component style={styles.signatureBox} />
      </View>
    )
  }
});

module.exports = SignatureCapture;

Update require signature for React and React Native


test('script_error_fallback.php', function (assert, document) {
    var expected = [
        'inline',
        'deferred inline',
        'synchronous external',
        'second inline',
        'deferred external'
    ];
    assert.ok(document.defaultView.doesNotExistSrc, 'window.doesNotExistSrc is defined');
    assert.equal(document.defaultView.doesNotExistSrc, 'does-not-exist.js', 'window.doesNotExistSrc is not correct')
});

test('script_error_fallback.php', function (assert, document) {
    assert.ok(document.defaultView.doesNotExistSrc, 'window.doesNotExistSrc is defined');
    assert.equal(document.defaultView.doesNotExistSrc, 'does-not-exist.js', 'window.doesNotExistSrc is not correct')
});

Remove dead code from test


import Vue from 'vue';
import Vuex from 'vuex';

import modules from './module';

Vue.use(Vuex);

// global state
const state = {
  paginationLimit: 20
}

// global mutations
const mutations = {
  setPaginationLimit(state, limit) {
    state.paginationLimit = limit;
  }
}

// global actions
const actions = {
}

const store = new Vuex.Store({
  actions,
  mutations,
  state,
  modules
})

export default store

import Vue from 'vue';
import Vuex from 'vuex';

import modules from './module';

Vue.use(Vuex);

// global state
const state = {
  paginationLimit: 20
}

// global mutations
const mutations = {
  setPaginationLimit(state, limit) {
    state.paginationLimit = Number(limit);
  }
}

// global actions
const actions = {
}

const store = new Vuex.Store({
  actions,
  mutations,
  state,
  modules
})

export default store

Fix wrong pagination limit data type


var gulp = require('gulp');
var less = require('gulp-less');
var path = require('path');
var minifyCSS = require('gulp-minify-css');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');

// spawn-sync polyfill for nodejs < 0.12
var spawn = require('spawn-sync');
// var spawn = require('child_process').spawnSync;

gulp.task('css', function (cb) {
  var p = spawn('python', ['-c',
    "import os,jupyter_notebook; print(os.path.join(jupyter_notebook.DEFAULT_STATIC_FILES_PATH))"]);
  var nb_static_path = p.stdout.toString().trim();
  return gulp.src('./ipython_widgets/static/widgets/less/widgets.less')
    .pipe(sourcemaps.init())
    .pipe(less({
      paths: [nb_static_path],
    }))
    .pipe(minifyCSS())
    .pipe(rename({
            dirname: path.join('..', 'css'),
            suffix: '.min'
        }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./ipython_widgets/static/widgets/css/'));
});

var gulp = require('gulp');
var less = require('gulp-less');
var path = require('path');
var minifyCSS = require('gulp-minify-css');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');

// spawn-sync polyfill for nodejs < 0.12
var spawn = require('spawn-sync');
// var spawn = require('child_process').spawnSync;

// Default task set.
gulp.task('default', ['css']);

// Watch for changes.
gulp.task('watch', function() {
    gulp.watch('./ipython_widgets/static/**/*.less', ['css']);
});

// Compile less into css.
gulp.task('css', function (cb) {
  var p = spawn('python', ['-c',
    "import os,jupyter_notebook; print(os.path.join(jupyter_notebook.DEFAULT_STATIC_FILES_PATH))"]);
  var nb_static_path = p.stdout.toString().trim();
  return gulp.src('./ipython_widgets/static/widgets/less/widgets.less')
    .pipe(sourcemaps.init())
    .pipe(less({
      paths: [nb_static_path],
    }))
    .pipe(minifyCSS())
    .pipe(rename({
            dirname: path.join('..', 'css'),
            suffix: '.min'
        }))
    .pipe(sourcemaps.write('./'))
    .pipe(gulp.dest('./ipython_widgets/static/widgets/css/'));
});

Improve the gulp file. Adds watch and default commands.


(function(bitflux) {
    'use strict';

    angular.module('openfin.showcase')
        .directive('showcase', ['quandlService', 'configService', (quandlService, configService) => {
            return {
                restrict: 'E',
                templateUrl: 'showcase/showcase.html',
                scope: {
                    selection: '&'
                },
                link: (scope, element) => {
                    var chart = bitflux.app().quandlApiKey(quandlService.apiKey()),
                        firstRun = true;

                    chart.periodsOfDataToFetch(configService.getBitfluxStockAmount());
                    chart.proportionOfDataToDisplayByDefault(configService.getInitialBitfluxProportion());

                    scope.$watch('selection()', (newSelection, previousSelection) => {
                        if (newSelection !== '') {
                            if (firstRun) {
                                firstRun = false;
                                chart.run(element[0].children[0]);
                            }

                            if (newSelection !== previousSelection) {
                                chart.changeQuandlProduct(newSelection);
                            }
                        }
                    });
                }
            };
        }]);
}(bitflux));

(function(bitflux) {
    'use strict';

    angular.module('openfin.showcase')
        .directive('showcase', ['quandlService', 'configService', (quandlService, configService) => {
            return {
                restrict: 'E',
                templateUrl: 'showcase/showcase.html',
                scope: {
                    selection: '&'
                },
                link: (scope, element) => {
                    var chart = bitflux.app().quandlApiKey(quandlService.apiKey()),
                        firstRun = true;

                    chart.periodsOfDataToFetch(configService.getBitfluxStockAmount());
                    chart.proportionOfDataToDisplayByDefault(configService.getInitialBitfluxProportion());

                    // If there's already a selection, run the chart and use that.
                    // This occurs when the user selects a stock in compact view
                    // and it expands.
                    if (scope.selection && scope.selection()) {
                        firstRun = false;
                        chart.run(element[0].children[0]);
                        chart.changeQuandlProduct(scope.selection());
                    }

                    scope.$watch('selection()', (newSelection, previousSelection) => {
                        if (newSelection !== '') {
                            if (firstRun) {
                                firstRun = false;
                                chart.run(element[0].children[0]);
                            }

                            if (newSelection !== previousSelection) {
                                chart.changeQuandlProduct(newSelection);
                            }
                        }
                    });
                }
            };
        }]);
}(bitflux));

Fix selection not occurring on compact select+expand


import React from 'react';
import ReactDOM from 'react-dom';
import $ from 'jquery';
import App from './app.setup.js';

describe('App', function() {
  describe('adding new todos', function() {
    let $component;

    beforeEach(function() {
      const component = ReactDOM.render(<App />,
                                        document.getElementById('test-area'));

      $component = $(ReactDOM.findDOMNode(component));
    });

    it('should focus on the todo input', function() {
      expect(document.activeElement).to.equal(
        $component.find('.new-todo')[0]);
    });
  });
});

import React from 'react';
import ReactDOM from 'react-dom';
import { Simulate } from 'react-addons-test-utils';
import $ from 'jquery';
import App from './app.setup.js';

const ENTER = 13;

describe('App', function() {
  describe('adding new todos', function() {
    let $component;

    beforeEach(function() {
      const component = ReactDOM.render(<App />,
                                        document.getElementById('test-area'));

      $component = $(ReactDOM.findDOMNode(component));
    });

    it('should focus on the new todo input when the page loads', function() {
      expect(document.activeElement).to.equal(
        $component.find('.new-todo')[0]);
    });

    it('should add a new todo when pressing enter', function() {
      const node = $component.find('.new-todo')[0];

      // TODO: this exposes too much of the internals; figure out a way to write
      // tests without knowing all of this
      Simulate.change(node, { target: { value: 'buy milk' } });
      Simulate.keyDown(node, { keyCode: ENTER });

      expect($component.find('.todo')).to.have.length(1);
      expect($component.find('.todo').text()).to.equal('buy milk');
    });
  });
});

Check that adding a new todo works


import {computed} from '@ember/object';
import Service from '@ember/service';

export default class Fw extends Service {

  @computed()
  get isBs3() {
    return window.location.href.includes('/v.3/bs3/');
  }

  @computed()
  get isBs4() {
    return window.location.href.includes('/v.3/bs4/');
  }

  @computed()
  get isSemanticUI() {
    return window.location.href.includes('/v.3/semantic/');
  }

}

import {computed} from '@ember/object';
import Service from '@ember/service';

export default class Fw extends Service {

  @computed()
  get isBs3() {
    return window.location.href.includes('/v.3/bs3/') || window.location.href.includes('localhost');
  }

  @computed()
  get isBs4() {
    return window.location.href.includes('/v.3/bs4/');
  }

  @computed()
  get isSemanticUI() {
    return window.location.href.includes('/v.3/semantic/');
  }

}

Use bs for localhost (needed for tests)


var joi = require("joi");

module.exports = {
  host: joi.string().hostname().required(),
  serviceType: joi.string().min(1).required(),
  metadata: joi.object(),
  serviceUri: joi.string().regex(/http(s)?:\/\/[A-Za-z0-9-\/+]+/i),
  onError: joi.func()
};

var joi = require("joi");

module.exports = {
  host: joi.string().required(),
  serviceType: joi.string().min(1).required(),
  metadata: joi.object(),
  serviceUri: joi.string().regex(/http(s)?:\/\/[A-Za-z0-9-\/+]+/i),
  onError: joi.func()
};

Allow port in host specification


'use strict';

var gulp = require('gulp');
var imagemin = require('gulp-imagemin');

gulp.task('minimizeImages', function() {
  return gulp.src('img/*.gif')
    .pipe(imagemin())
    .pipe(gulp.dest('build'));
});

'use strict';

var gulp = require('gulp');
var imagemin = require('gulp-imagemin');
var changed = require('gulp-changed');

gulp.task('minimizeImages', function() {
  return gulp.src('img/*.gif')
    .pipe(changed('build'))
    .pipe(imagemin())
    .pipe(gulp.dest('build'));
});

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

Add gulp-changed to improve build performance in minimizing images


if (!chai) {
  var chai = require('..');
}

var assert = chai.assert;

suite('assert-config', function () {

  function fooThrows () {
    assert.equal('foo', 'bar');
  }

  test('Assertion.includeStack is true, stack trace available', function () {
    chai.Assertion.includeStack = true;
    try {
      fooThrows();
      assert.ok(false, 'should not get here because error thrown');
    } catch (err) {
      assert.include(err.stack, 'at fooThrows', 'should have stack trace in error message');
    }
  });

  test('Assertion.includeStack is false, stack trace not available', function () {
    chai.Assertion.includeStack = false;
    try {
      fooThrows();
      assert.ok(false, 'should not get here because error thrown');
    } catch (err) {
      assert.equal(err.stack.indexOf('at fooThrows'), -1, 'should not have stack trace in error message');
    }
  });

});

if (!chai) {
  var chai = require('..');
}

var assert = chai.assert;

suite('assert-config', function () {

  function fooThrows () {
    assert.equal('foo', 'bar');
  }

  test('Assertion.includeStack is true, stack trace available', function () {
    chai.Assertion.includeStack = true;
    try {
      fooThrows();
      assert.ok(false, 'should not get here because error thrown');
    } catch (err) {
      if (typeof(err.stack) !== 'undefined') {  // not all browsers support err.stack
        assert.include(err.stack, 'at fooThrows', 'should have stack trace in error message');
      }
    }
  });

  test('Assertion.includeStack is false, stack trace not available', function () {
    chai.Assertion.includeStack = false;
    try {
      fooThrows();
      assert.ok(false, 'should not get here because error thrown');
    } catch (err) {
      assert.ok(!err.stack || err.stack.indexOf('at fooThrows') === -1, 'should not have stack trace in error message');
    }
  });

});

Update test to be compatible with browsers that do not support err.stack


'use strict';

(function() {

angular.requires('//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js', function() {
    return typeof window.$ !== 'undefined';
});

var mod = angular.module('subdir.my_mod', []);

mod.factory('Factory', function() {
    return {
        value: 'Hello World!',
        isJQueryLoaded: (typeof $ == 'function')
    };
});

})();

'use strict';

(function() {

angular.requires('//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js', '$');

var mod = angular.module('subdir.my_mod', []);

mod.factory('Factory', function() {
    return {
        value: 'Hello World!',
        isJQueryLoaded: (typeof $ == 'function')
    };
});

})();

Use a string to represent the name of a variable to check.


// Copyright (c) 2011 David Benjamin. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

// Initialize default settings:
function initDefaultSettings() {
    var defaultSettings = {
        commandPattern: 'emacs --parent-id $WINDOW -- $PATH',
        triggerAltX: true,
        triggerDoubleClick: false
    };
    for (var k in defaultSettings) {
        if (localStorage[k] === undefined)
            localStorage[k] = defaultSettings[k];
    }
}

// Copyright (c) 2011 David Benjamin. All rights reserved.
// Use of this source code is governed by an MIT-style license that can be
// found in the LICENSE file.

// Initialize default settings:
function initDefaultSettings() {
    var defaultSettings = {
        editorType: "emacs",
        triggerAltX: true,
        triggerDoubleClick: false
    };
    for (var k in defaultSettings) {
        if (localStorage[k] === undefined)
            localStorage[k] = defaultSettings[k];
    }
}

Set a default value for editorType


//= require moment
//= require bootstrap-datetimepicker

$(function() {
  $(document).on('ready page:change', function() {
    $('input.datetime_picker').datetimepicker();
  });
});

//= require moment
//= require bootstrap-datetimepicker

$(document).on('ready page:change', function() {
  $('input.datetime_picker').datetimepicker();
  $('.input-group.datetime_picker .input-group-btn').on('click', function() {
    $(this).prev('input.datetime_picker').focus().click();
  });
});

Update datetime_picker.js so that the calendar icon works on click too.


import $ from 'jquery';

import versionInfo from 'girder/version';
import View from 'girder/views/View';
import { cancelRestRequests, getApiRoot } from 'girder/rest';
import events from 'girder/events';
import { getCurrentUser } from 'girder/auth';

import FrontPageTemplate from 'girder/templates/body/frontPage.pug';

import 'girder/stylesheets/body/frontPage.styl';

/**
 * This is the view for the front page of the app.
 */
var FrontPageView = View.extend({
    events: {
        'click .g-register-link': function () {
            events.trigger('g:registerUi');
        },
        'click .g-login-link': function () {
            events.trigger('g:loginUi');
        },
        'click .g-quicksearch-link': function () {
            $('.g-quick-search-container .g-search-field').focus();
        }
    },

    initialize: function (settings) {
        cancelRestRequests('fetch');
        this.brandName = settings.brandName || 'Girder';
        this.render();
    },

    render: function () {
        this.$el.html(FrontPageTemplate({
            apiRoot: getApiRoot(),
            currentUser: getCurrentUser(),
            versionInfo: versionInfo,
            brandName: this.brandName
        }));

        return this;
    }
});

export default FrontPageView;

import $ from 'jquery';

// TODO: redo version injection
// import versionInfo from 'girder/version';
import View from 'girder/views/View';
import { cancelRestRequests, getApiRoot } from 'girder/rest';
import events from 'girder/events';
import { getCurrentUser } from 'girder/auth';

import FrontPageTemplate from 'girder/templates/body/frontPage.pug';

import 'girder/stylesheets/body/frontPage.styl';

/**
 * This is the view for the front page of the app.
 */
var FrontPageView = View.extend({
    events: {
        'click .g-register-link': function () {
            events.trigger('g:registerUi');
        },
        'click .g-login-link': function () {
            events.trigger('g:loginUi');
        },
        'click .g-quicksearch-link': function () {
            $('.g-quick-search-container .g-search-field').focus();
        }
    },

    initialize: function (settings) {
        cancelRestRequests('fetch');
        this.brandName = settings.brandName || 'Girder';
        this.render();
    },

    render: function () {
        this.$el.html(FrontPageTemplate({
            apiRoot: getApiRoot(),
            currentUser: getCurrentUser(),
            versionInfo: {},
            brandName: this.brandName
        }));

        return this;
    }
});

export default FrontPageView;

Comment out client version injection for now


"use strict";

export default function getReplies(topicId) {
  return new Promise(function () {
    _getRepliesFromTopic(topicId, function (data) {
      let replies = data.replies;

      if (replies) {

      } else {
        let error = new Error("An error occurred");
      }
    });
  });
}

"use strict";

export default function getReplies(topicId) {
  return new Promise(function (resolve, reject) {
    _getRepliesFromTopic(topicId, function (data) {
      let replies = data.replies;

      if (replies) {
        resolve(replies);
      } else {
        let error = new Error("An error occurred");

        reject(error);
      }
    });
  });
}

Add resolve, reject handlers. Try to work with them


const {
    assemble,
    writeFile,
    unicodeVersion
} = require('./utils.js');

// This intentially includes only the binary properties required by UTS 18 Level 1 RL1.2 for Unicode
// regex support, minus `Assigned` which has special handling since it is the inverse of Unicode
// category `Unassigned` (`Cn`). To include all binary properties, change this to:
// `const properties = require(`${unicodeVersion}`).Binary_Property;`
const properties = [
    'ASCII',
    'Alphabetic',
    'Any',
    'Assigned',
    'Default_Ignorable_Code_Point',
    'Lowercase',
    'Noncharacter_Code_Point',
    'Uppercase',
    'White_Space'
];

const result = [];
for (const property of properties) {
    const codePoints = require(`${unicodeVersion}/Binary_Property/${property}/code-points.js`);
    result.push(assemble({
        name: property,
        codePoints
    }));
}
writeFile('properties.js', result);

const {
    assemble,
    writeFile,
    unicodeVersion
} = require('./utils.js');

// This intentially includes only the binary properties required by UTS 18 Level 1 RL1.2 for Unicode
// regex support. To include all binary properties, change this to:
// `const properties = require(`${unicodeVersion}`).Binary_Property;`
const properties = [
    'ASCII',
    'Alphabetic',
    'Any',
    'Assigned',
    'Default_Ignorable_Code_Point',
    'Lowercase',
    'Noncharacter_Code_Point',
    'Uppercase',
    'White_Space'
];

const result = [];
for (const property of properties) {
    const codePoints = require(`${unicodeVersion}/Binary_Property/${property}/code-points.js`);
    result.push(assemble({
        name: property,
        codePoints
    }));
}
writeFile('properties.js', result);

Fix comment about Assigned Unicode property


var self = require('sdk/self');

// a dummy function, to show how tests work.
// to see how to test this function, look at test/test-index.js
function dummy(text, callback) {
  callback(text);
}

exports.dummy = dummy;

var buttons = require('sdk/ui/button/action');
var tabs = require("sdk/tabs");

var button = buttons.ActionButton({
  id: "idea-town-link",
  label: "Idea Town",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

function handleClick(state) {
  tabs.open("http://developer.mozilla.org/");
}

var self = require('sdk/self');

// a dummy function, to show how tests work.
// to see how to test this function, look at test/test-index.js
function dummy(text, callback) {
  callback(text);
}

exports.dummy = dummy;

var buttons = require('sdk/ui/button/action');
var tabs = require("sdk/tabs");

var button = buttons.ActionButton({
  id: "idea-town-link",
  label: "Idea Town",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

function handleClick(state) {
  tabs.open("https://ideatown.firefox.com/");
}

Update the idea town URL


/**
 * Server root
 *
 * Collects all routes and starts the server
 */
const glob = require('glob-promise');
const express = require('express');
const { partial } = require('lodash');
const bodyParser = require('body-parser');

const server = express();

/* Setup the application server */
server.use(bodyParser.json());

/* Building blocks */
const findRoutes = partial(glob, './routes/**/*.js');
const findMiddlewares = partial(glob, './middlewares/**/*.js');
const requireAndIntegrate = function(files, app) {
    files.forEach(file => {
        const fn = require(file);

        if ('function' === typeof fn) fn(app);
    });
};

/* Start ✨ */
findRoutes()
    .then(routes => {
        requireAndIntegrate(routes, server);
        return findMiddlewares();
    })
    .then(middlewares => {
        requireAndIntegrate(middlewares);
    })
    .then(function() {
        server.listen(3000);
    });

Add the first part of the server core


/**
 * Manages items that the player can buy.
 * @type {Object}
 */
const itemManager = {

  /**
   * All the items available for purchase.
   * @type {Object}
   */
  ITEMS: [
    {
      name: 'potato',
      price: 1
    },
    {
      name: 'lemon',
      price: 4
    }
  ],

  /**
   * Give the given player an item if it has enough money.
   * @param {Number} itemId
   */
  buyItem(player, itemId) {
    if (player.coins >= this.ITEMS[itemId].price) {
      player.coins -= 1;
      player.addItem(itemId);
    } else {
      console.error(`You can't buy a ${this.ITEMS[itemId].name}, ya dingus! You need $${this.ITEMS[itemId].price} and only have $${player.coins}!`);
    }
  }
};

/**
 * The player.
 * @type {Object}
 */
const player = {

  /**
   * The number of bitcoins the player currently has.
   * @type {Number}
   */
  coins: 1,

  /**
   * The items that the player currently has.
   * @type {Object}
   */
  items: [
    {
      name: 'potato',
      amount: 0
    },
    {
      name: 'lemon',
      amount: 0
    }
  ],

  /**
   * The upgrades that the player has purchased.
   * @type {Object}
   */
  upgrades: {},

  addItem(itemId) {
    this.items[itemId].amount++;
  }

};

/**
 * Represents the entire game.
 * @type {Object}
 */
const game = {

  purchasePototoButton: null,
  purchaseLemonButton: null,

  init() {
    this.purchasePotatoButton = document.getElementById('purchasePotato');
    this.purchaseLemonButton = document.getElementById('purchaseLemon');

    this.purchasePotatoButton.addEventListener('click', this.buyPotato);
    this.purchaseLemonButton.addEventListener('click', this.buyLemon);
  },

  buyPotato() {
    itemManager.buyItem(player, 0);
  },

  buyLemon() {
    itemManager.buyItem(player, 1);
  }

};

game.init();

Add ability to purchase potatoes and lemons


/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var config = require('../config')
var dbServer = require('fxa-auth-db-server')
var error = dbServer.errors
var log = require('../log')(config.logLevel, 'db-api')
var DB = require('../db/mysql')(log, error)

module.exports = function () {
  return DB.connect(config)
    .then(function (db) {
      return dbServer.createServer(db)
    })
}

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var config = require('./config')
var dbServer = require('fxa-auth-db-server')
var error = dbServer.errors
var log = require('./log')(config.logLevel, 'db-api')
var DB = require('./db/mysql')(log, error)

module.exports = function () {
  return DB.connect(config)
    .then(function (db) {
      return dbServer.createServer(db)
    })
}

Fix requires if being used as a library


var express = require('express');
var eventStream = require('express-eventsource')();
var clientSSDP = require('./clients/ssdp');
var clientMDNS = require('./clients/mdns');

var app      = express(),
    messages = [];

// Serve all static files in /public
app.use(require('serve-static')('public'));

// Shared eventsource
// To send data call: eventStream.send(dataObj, 'eventName');
app.use('/events', eventStream.middleware());

// Perform a scan, sending results
// through the event stream
app.get('/scan', function (req, res) {
  ssdp.search();
  mdns.start();
  res.send();
});

// Return all previous messages
app.get('/cache', function (req, res) {
  res.send( JSON.stringify(messages) );
});

var ssdp = clientSSDP.create();
ssdp.on('*', function (msg) {
  console.log(log(msg));
  eventStream.send(msg);
  messages.push(msg);
});
ssdp.search();

var mdns = clientMDNS.create();
mdns.on('*', function (msg) {
  console.log(log(msg));
  eventStream.send(msg);
  messages.push(msg);
});

function log(msg) {
  return msg.protocol + ':\t\t' + msg.state + '\t' + msg.type + '\t\t\t' + msg.id;
}

app.listen(process.env.PORT || 3000);

var express = require('express');
var eventStream = require('express-eventsource')();
var clientSSDP = require('./clients/ssdp');
var clientMDNS = require('./clients/mdns');

var app      = express(),
    messages = [];

// Serve all static files in /public
app.use(require('serve-static')('public'));

// Shared eventsource
// To send data call: eventStream.send(dataObj, 'eventName');
app.use('/events', eventStream.middleware());

// Perform a scan, sending results
// through the event stream
app.get('/scan', function (req, res) {
  ssdp.search();
  mdns.start();
  res.send();
});

// Return all previous messages
app.get('/cache', function (req, res) {
  res.send( JSON.stringify(messages.slice(-50)) );
});

var ssdp = clientSSDP.create();
ssdp.on('*', function (msg) {
  console.log(log(msg));
  eventStream.send(msg);
  messages.push(msg);
});
ssdp.search();

var mdns = clientMDNS.create();
mdns.on('*', function (msg) {
  console.log(log(msg));
  eventStream.send(msg);
  messages.push(msg);
});

function log(msg) {
  return msg.protocol + ':\t\t' + msg.state + '\t' + msg.type + '\t\t\t' + msg.id;
}

app.listen(process.env.PORT || 3000);

Return last 50 messages only from cache


'use strict';
var request = require('request');
var xray = require('x-ray')();
var tabletojson = require('tabletojson');

module.exports.get = function get(url) {
  return new Promise(function(resolve, reject) {
    request.get(url, function(err, response, body) {
      if (err) {
        return reject(err);
      }
      if (response.statusCode >= 400) {
        return reject(new Error('The website requested returned an error!'));
      }
      xray(body, ['table@html'])(function (conversionError, tableHtmlList) {
        if (conversionError) {
          return reject(conversionError);
        }
        resolve(tableHtmlList.map(function(table) {
          // xray returns the html inside each table tag, and tabletojson
          // expects a valid html table, so we need to re-wrap the table.
          // Returning the first element in the converted array because
          // we should only ever be parsing one table at a time within this map.
          return tabletojson.convert('<table>' + table + '</table>')[0];
        }));
      });
    })
  });
};

'use strict';
var request = require('request');
var xray = require('x-ray')();
var tabletojson = require('tabletojson');

module.exports.get = function get(url, options={}) {
  return new Promise(function(resolve, reject) {
    const requestOptions = {
      ...options,
      method: 'GET',
      url: url,
    }
    request.get(requestOptions, function(err, response, body) {
      if (err) {
        return reject(err);
      }
      if (response.statusCode >= 400) {
        return reject(new Error('The website requested returned an error!'));
      }
      xray(body, ['table@html'])(function (conversionError, tableHtmlList) {
        if (conversionError) {
          return reject(conversionError);
        }
        resolve(tableHtmlList.map(function(table) {
          // xray returns the html inside each table tag, and tabletojson
          // expects a valid html table, so we need to re-wrap the table.
          // Returning the first element in the converted array because
          // we should only ever be parsing one table at a time within this map.
          return tabletojson.convert('<table>' + table + '</table>')[0];
        }));
      });
    })
  });
};

Allow passing options to request lib


import Watchable from './watchable';

export default class JobSummaryAdapter extends Watchable {
  urlForFindRecord(id, type, hash) {
    const [name, namespace] = JSON.parse(id);
    let url = super.urlForFindRecord(name, 'job', hash) + '/summary';
    if (namespace && namespace !== 'default') {
      url += `?namespace=${namespace}`;
    }
    return url;
  }
}

import WatchableNamespaceIDs from './watchable-namespace-ids';

export default class JobSummaryAdapter extends WatchableNamespaceIDs {}

Refactor job summary adapter to use the namespace ID base class


const express = require('express');
const helmet = require('helmet');
const winston = require('winston');
const bodyParser = require('body-parser');
const env = require('./src/env');

var server = express();
var router = require('./src/router');
var PORT = env.PORT || 8000;

server.use(bodyParser.urlencoded({ extended: false }));
server.use(helmet());
server.use('/review', router);

function _get() {
  return server;
}

function run(fn) {

  fn = fn || function _defaultStart() {
    winston.info('Listening at ' + PORT);
  };

  return server.listen(PORT, fn);
}

if (require.main === module) {
  run();
}

module.exports = {
  _get: _get,
  run: run
};

const express = require('express');
const helmet = require('helmet');
const winston = require('winston');
const bodyParser = require('body-parser');
const env = require('./src/env');

var server = express();
var router = require('./src/router');
var PORT = env.PORT || 8000;

server.use(bodyParser.urlencoded({ extended: false }));
server.use(helmet());
server.use('/', router);

function _get() {
  return server;
}

function run(fn) {

  fn = fn || function _defaultStart() {
    winston.info('Listening at ' + PORT);
  };

  return server.listen(PORT, fn);
}

if (require.main === module) {
  run();
}

module.exports = {
  _get: _get,
  run: run
};

Allow router to handle root routes


function newXHR() {
  if (window.ActiveXObject)
    return new ActiveXObject('Microsoft.XMLHTTP');
  else if (window.XMLHttpRequest)
    return new XMLHttpRequest();
  return null;
};

module.exports = function(url, callback, postBody) {
  var xhr = newXHR();

  if (!xhr)
    return;

  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4)
      callback(xhr.responseText);
  };

  if (postBody) {
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  }
  else
    xhr.open('GET', url, true);

  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  xhr.send(this.postBody);
};

function newXHR() {
  if (window.ActiveXObject)
    return new ActiveXObject('Microsoft.XMLHTTP');
  else if (window.XMLHttpRequest)
    return new XMLHttpRequest();
  return null;
};

module.exports = function(url, callback, postBody) {
  var xhr = newXHR();

  if (!xhr)
    throw new Error('No XMLHttpRequest object available.');

  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4)
      callback(xhr.responseText);
  };

  if (postBody) {
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
  }
  else
    xhr.open('GET', url, true);

  xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
  xhr.send(this.postBody);
};

Throw when no XHR object available.


'use strict';

var babel = require('babel-core');

exports.name = 'babel';
exports.inputFormats = ['es6', 'babel'];
exports.outputFormat = 'js';

/**
 * Babel's available options.
 */
var availableOptions = Object.keys(babel.options);

exports.render = function(str, options, locals) {
  // Remove any invalid options.
  var opts = {};
  var name = null;
  options = options || {};
  for (var index in availableOptions) {
    name = availableOptions[index];
    if (name in options) {
      opts[name] = options[name];
    }
  }

  // Process the new options with Babel.
  return babel.transform(str, opts).code;
};

'use strict';

var babel = require('babel-core');

exports.name = 'babel';
exports.inputFormats = ['es6', 'babel', 'js'];
exports.outputFormat = 'js';

/**
 * Babel's available options.
 */
var availableOptions = Object.keys(babel.options);

exports.render = function(str, options, locals) {
  // Remove any invalid options.
  var opts = {};
  var name = null;
  options = options || {};
  for (var index in availableOptions) {
    name = availableOptions[index];
    if (name in options) {
      opts[name] = options[name];
    }
  }

  // Process the new options with Babel.
  return babel.transform(str, opts).code;
};

Add js as input format


var fs = require("fs"),
    path = require("path");

module.exports = new Function("d3", fs.readFileSync(path.join(__dirname, "d3.geo.projection.js"), "utf-8"));

var fs = require("fs");
var path = require("path");

module.exports = new Function("d3", fs.readFileSync(path.join(__dirname, "d3.geo.projection.js"), "utf-8"));

Fix failing brfs browserify transform


const Discord = require('discord.io');

const bot = new Discord.Client({
  token: process.env.DISCORD_TOKEN,
  autorun: true,
});

const previousMessages = [];

bot.on('ready', () => {
  console.log('Logged in as %s - %s\n', bot.username, bot.id);
});

bot.on('disconnect', () => {
  bot.connect();
});

bot.on('message', (user, userId, channelId, message, event) => {
  if (message === 'ping') {
    bot.sendMessage({
      to: channelId,
      message: 'pong',
    });
  } else if (user !== bot.username) {
    if (previousMessages.includes(message)) {
      bot.deleteMessage({
        channelID: channelId,
        messageID: event.d.id,
      }, (err) => {
        console.log(err);
      });
    } else {
      previousMessages.push(message);
    }
  }
});

const Discord = require('discord.io');

const bot = new Discord.Client({
  token: process.env.DISCORD_TOKEN,
  autorun: true,
});

const previousMessages = [];

bot.on('ready', () => {
  console.log('Logged in as %s - %s\n', bot.username, bot.id);
});

bot.on('disconnect', () => {
  bot.connect();
});

bot.on('message', (user, userId, channelId, message, event) => {
  if (message === '!ping') {
    bot.sendMessage({
      to: channelId,
      message: 'pong',
    });
  } else if (user !== bot.username) {
    if (previousMessages.includes(message)) {
      bot.deleteMessage({
        channelID: channelId,
        messageID: event.d.id,
      }, (err) => {
        console.log(err);
      });
    } else {
      previousMessages.push(message);
    }
  }
});

Change ping trigger to need exclaimation point


var utilConfig = {
	regexList : [
		{
			type : "attr",
			attrName : "ng-model",
			match :  /[b|B]y\.model\(\s*['|"](.*?)['|"]\s*\)/gi
		},
		{
			type : "attr",
			attrName : "ng-repeat",
			match : /[b|B]y\.repeater\(\s*['|"](.*?)['|"]\s*\)/gi
		},
		{
			type : "cssAttr",
			match : /[b|B]y\.css\(['|"]\[(.+=.+)\]['|"]\)/gi
		},
		{
			type : "attr",
			attrName : "ng-bind",
			match : /[b|B]y\.binding\(\s*['|"](.*?)['|"]\s*\)/gi
		}
	],

	getRegexList : function(){
		return this.regexList;
	}
};

module.exports = utilConfig;

var utilConfig = {
	regexList : [
		{
			type : "attr",
			attrName : "ng-model",
			match :  /[b|B]y\.model\(\s*['|"](.*?)['|"]\s*\)/gi
		},
		{
			type : "attr",
			attrName : "ng-repeat",
			match : /[b|B]y\.repeater\(\s*['|"](.*?)['|"]\s*\)/gi
		},
		{
			type : "cssAttr",
			match : /[b|B]y\.css\(['|"]\[(.+=.+)\]['|"]\)/gi
		},
		{
			type : "attr",
			attrName : "ng-bind",
			match : /[b|B]y\.binding\(\s*['|"](.*?)['|"]\s*\)/gi
		},
        {
            type: "attr",
            attrName : "ng-repeat",
            match: /[b|B]y\.repeater\(\s*['|"](.*? in .*?)['|"]\s*\)/gi
        }
	],

	getRegexList : function(){
		return this.regexList;
	}
};

module.exports = utilConfig;

Add regex rule for repeater selector


const gulp = require('gulp');
const sync = require('browser-sync').create();

// Server

gulp.task('default', [], () => {
	sync.init({
		ui: false,
		notify: false,
		server: {
			baseDir: './slides',
			index: 'index.html'
		}
	});

	gulp.watch('index.html').on('change', sync.reload);
});

const gulp = require('gulp');
const sync = require('browser-sync').create();

// Server

gulp.task('default', [], () => {
	sync.init({
		ui: false,
		notify: false,
		server: {
			baseDir: './slides',
			index: 'index.html'
		}
	});

	gulp.watch('./slides/index.html').on('change', sync.reload);
});

Fix gulp watch file path


var fs = require('fs');
var async = require('async');

module.exports = function (path, data, callback) {

  function load (callback) {
    fs.readFile(path, 'utf8', callback);
  }

  function parse (content, callback) {
    try {
      var json_data = JSON.parse(content);
      callback(null, json_data);
    } catch (error) {
      callback(error);
    }
  }

  function update (json_data, callback) {
    for (key in data) {
      json_data[key] = data[key];
    }
    callback(null, json_data);
  }

  function save (json_data, callback) {
    var content = JSON.stringify(json_data, null, '  ');
    fs.writeFile(path, content, 'utf8', callback);
  }

  async.waterfall([
    load,
    parse,
    update,
    save
  ], function (error, result) {
    callback(error);
  });

};

var fs = require('fs');
var async = require('async');
var os = require('os');

module.exports = function (path, data, callback) {

  function load (callback) {
    fs.readFile(path, 'utf8', callback);
  }

  function parse (content, callback) {
    try {
      var json_data = JSON.parse(content);
      callback(null, json_data);
    } catch (error) {
      callback(error);
    }
  }

  function update (json_data, callback) {
    for (key in data) {
      json_data[key] = data[key];
    }
    callback(null, json_data);
  }

  function save (json_data, callback) {
    var content = JSON.stringify(json_data, null, '  ') + os.EOL;
    fs.writeFile(path, content, 'utf8', callback);
  }

  async.waterfall([
    load,
    parse,
    update,
    save
  ], function (error, result) {
    callback(error);
  });

};

Add POSIX compliant newline at end of generated JSON file.


// Shim to avoid requiring Velocity in Node environments, since it
// requires window. Note that this just no-ops the components so
// that they'll render, rather than doing something clever like
// statically rendering the end state of any provided animations.
//
// TODO(finneganh): Circle back on jsdom to see if we can run full
// Velocity with it in place. This come up in:
// https://github.com/twitter-fabric/velocity-react/issues/119
// but there may have been different loading issues in that case,
// not a global incompatibility with jsdom.
if (typeof window === 'undefined' || navigator.userAgent.indexOf("Node.js") !== -1 || navigator.userAgent.indexOf("jsdom") !== -1) {

  var Velocity = function() {};
  Velocity.Utilities = {};
  Velocity.Utilities.removeData = function() {};
  Velocity.velocityReactServerShim = true;
  module.exports = Velocity;

} else {
  // this is how velocity-ui finds the Velocity instance, so lets make sure we find the right instance
  var g = (window.jQuery || window.Zepto || window);

  // require Velocity if it doesn't already exist
  module.exports = g.Velocity ? g.Velocity : require('velocity-animate');

}

// Shim to avoid requiring Velocity in Node environments, since it
// requires window. Note that this just no-ops the components so
// that they'll render, rather than doing something clever like
// statically rendering the end state of any provided animations.
//
// TODO(finneganh): Circle back on jsdom to see if we can run full
// Velocity with it in place. This come up in:
// https://github.com/twitter-fabric/velocity-react/issues/119
// but there may have been different loading issues in that case,
// not a global incompatibility with jsdom.
if (typeof window === 'undefined' || typeof navigator === 'undefined' || navigator.userAgent.indexOf("Node.js") !== -1 || navigator.userAgent.indexOf("jsdom") !== -1) {

  var Velocity = function() {};
  Velocity.Utilities = {};
  Velocity.Utilities.removeData = function() {};
  Velocity.velocityReactServerShim = true;
  module.exports = Velocity;

} else {
  // this is how velocity-ui finds the Velocity instance, so lets make sure we find the right instance
  var g = (window.jQuery || window.Zepto || window);

  // require Velocity if it doesn't already exist
  module.exports = g.Velocity ? g.Velocity : require('velocity-animate');

}

Check for navigator before checking its properties.


angular.module('qtip2', [])
  .directive('qtip', function($rootScope, $timeout, $window) {
    return {
      restrict: 'A',
      link: function(scope, element, attrs) {
        var my = attrs.my || 'bottom center'
          , at = attrs.at || 'top center'

        element.qtip({
          content: attrs.content,
          position: {
            my: my,
            at: at,
            target: element
          },
          hide: {
            fixed : true,
            delay : 100
          },
          style: 'qtip'
        })
      }
    }
  })

!function($) {

  'use strict';

  angular.module('qtip2', [])
    .directive('qtip', function() {
      return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          var my = attrs.my || 'bottom center'
            , at = attrs.at || 'top center'

          $(element).qtip({
            content: attrs.content,
            position: {
              my: my,
              at: at,
              target: element
            },
            hide: {
              fixed : true,
              delay : 100
            },
            style: 'qtip'
          })
        }
      }
    })

}(window.jQuery);

Remove useless variables + iife


const path = require('path');

module.exports = {
  entry: [
    './playground/client' // Your appʼs entry point
  ],
  output: {
    publicPath: 'http://localhost:8080/build/',
    path: path.join(__dirname, 'build'),
    filename: './react-pic.js'
  },
  module: {
    loaders: [
      {
        test: /.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  }
};

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

module.exports = {
  entry: [
    './playground/client' // Your appʼs entry point
  ],
  target: 'node',
  output: {
    publicPath: 'http://localhost:8080/build/',
    path: path.join(__dirname, 'build'),
    filename: './react-pic.js'
  },
  plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development')
      }
    })
  ],
  module: {
    loaders: [
      {
        test: /.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: {
          presets: ['es2015', 'react']
        }
      }
    ]
  }
};

Fix playground webpack so that target is `node`


(function (window) {
  "use strict";

  window.GOVUK = window.GOVUK || {};

  const trackingId = 'UA-26179049-1';

  // Disable analytics by default
  window[`ga-disable-${trackingId}`] = true;

  const initAnalytics = function () {

    // guard against being called more than once
    if (!('analytics' in window.GOVUK)) {

      window[`ga-disable-${trackingId}`] = false;

      // Load Google Analytics libraries
      window.GOVUK.Analytics.load();

      // Configure profiles and make interface public
      // for custom dimensions, virtual pageviews and events
      window.GOVUK.analytics = new GOVUK.Analytics({
        trackingId: trackingId,
        cookieDomain: 'auto',
        anonymizeIp: true,
        displayFeaturesTask: null,
        transport: 'beacon',
        name: 'GOVUK.analytics',
        expires: 365
      });

      // Track initial pageview
      window.GOVUK.analytics.trackPageview();

    }

  };

  window.GOVUK.initAnalytics = initAnalytics;
})(window);

(function (window) {
  "use strict";

  window.GOVUK = window.GOVUK || {};

  const trackingId = 'UA-75215134-1';

  // Disable analytics by default
  window[`ga-disable-${trackingId}`] = true;

  const initAnalytics = function () {

    // guard against being called more than once
    if (!('analytics' in window.GOVUK)) {

      window[`ga-disable-${trackingId}`] = false;

      // Load Google Analytics libraries
      window.GOVUK.Analytics.load();

      // Configure profiles and make interface public
      // for custom dimensions, virtual pageviews and events
      window.GOVUK.analytics = new GOVUK.Analytics({
        trackingId: trackingId,
        cookieDomain: 'auto',
        anonymizeIp: true,
        displayFeaturesTask: null,
        transport: 'beacon',
        name: 'GOVUK.analytics',
        expires: 365
      });

      // Track initial pageview
      window.GOVUK.analytics.trackPageview();

    }

  };

  window.GOVUK.initAnalytics = initAnalytics;
})(window);

Fix Google Analytics tracking code


if (typeof Kwf == 'undefined') Kwf = {};
Kwf.loadDeferred = function(fn) {
    if (!Kwf._loadDeferred) Kwf._loadDeferred = [];
    if (Kwf._loadDeferred === 'done') {
        fn();
    } else {
        Kwf._loadDeferred.push(fn);
    }
};

document.write('<!--[if lt IE 9]><script type="text/javascript" src="/assets/html5shiv/dist/html5shiv.min.js"><' + '/script><![endif]-->');

Remove load_deferred, not needed anymore


import React, { useState } from 'react'
import Dictaphone from './Dictaphone'

const DictaphoneWidgetA = () => {
  const [message, setMessage] = useState('')
  const commands = [
    {
      command: 'I would like to order *',
      callback: (food) => setMessage(`Your order is for: ${food}`),
      matchInterim: true
    },
    {
      command: 'The weather is :condition today',
      callback: (condition) => setMessage(`Today, the weather is ${condition}`)
    },
    {
      command: 'Hello',
      callback: () => setMessage('Hi there'),
      matchInterim: true
    },
    {
      command: 'Beijing',
      callback: (command, spokenPhrase, similarityRatio) => setMessage(`${command} and ${spokenPhrase} are ${similarityRatio * 100}% similar`),
      // If the spokenPhrase is "Benji", the message would be "Beijing and Benji are 40% similar"
      isFuzzyMatch: true,
      fuzzyMatchingThreshold: 0.2
    },
    {
      command: 'clear',
      callback: ({ resetTranscript }) => resetTranscript(),
      matchInterim: true
    },
  ]

  return (

Dictaphone A

{message}

      <Dictaphone commands={commands} />

  )
}

export default DictaphoneWidgetA

import React, { useState } from 'react'
import Dictaphone from './Dictaphone'

const DictaphoneWidgetA = () => {
  const [message, setMessage] = useState('')
  const commands = [
    {
      command: 'I would like to order *',
      callback: (food) => setMessage(`Your order is for: ${food}`),
      matchInterim: true
    },
    {
      command: 'The weather is :condition today',
      callback: (condition) => setMessage(`Today, the weather is ${condition}`)
    },
    {
      command: ['Hello', 'Hi'],
      callback: () => setMessage('Hi there'),
      matchInterim: true
    },
    {
      command: 'Beijing',
      callback: (command, spokenPhrase, similarityRatio) => setMessage(`${command} and ${spokenPhrase} are ${similarityRatio * 100}% similar`),
      // If the spokenPhrase is "Benji", the message would be "Beijing and Benji are 40% similar"
      isFuzzyMatch: true,
      fuzzyMatchingThreshold: 0.2
    },
    {
      command: 'clear',
      callback: ({ resetTranscript }) => resetTranscript(),
      matchInterim: true
    },
  ]

  return (

Dictaphone A

{message}

      <Dictaphone commands={commands} />

  )
}

export default DictaphoneWidgetA

Add array-based command to example


import React, { useState } from 'react'
import Dictaphone from './Dictaphone'

const DictaphoneWidgetA = () => {
  const [message, setMessage] = useState('')
  const commands = [
    {
      command: 'I would like to order *',
      callback: (food) => setMessage(`Your order is for: ${food}`),
      matchInterim: true
    },
    {
      command: 'The weather is :condition today',
      callback: (condition) => setMessage(`Today, the weather is ${condition}`)
    },
    {
      command: 'Hello',
      callback: () => setMessage('Hi there'),
      matchInterim: true
    },
    {
      command: 'Beijing',
      callback: (command, spokenPhrase, similarityRatio) => setMessage(`${command} and ${spokenPhrase} are ${similarityRatio * 100}% similar`),
      // If the spokenPhrase is "Benji", the message would be "Beijing and Benji are 40% similar"
      isFuzzyMatch: true,
      fuzzyMatchingThreshold: 0.2
    }
  ]

  return (

Dictaphone A

{message}

      <Dictaphone commands={commands} />

  )
}

export default DictaphoneWidgetA

import React, { useState } from 'react'
import Dictaphone from './Dictaphone'

const DictaphoneWidgetA = () => {
  const [message, setMessage] = useState('')
  const commands = [
    {
      command: 'I would like to order *',
      callback: (food) => setMessage(`Your order is for: ${food}`),
      matchInterim: true
    },
    {
      command: 'The weather is :condition today',
      callback: (condition) => setMessage(`Today, the weather is ${condition}`)
    },
    {
      command: 'Hello',
      callback: () => setMessage('Hi there'),
      matchInterim: true
    },
    {
      command: 'Beijing',
      callback: (command, spokenPhrase, similarityRatio) => setMessage(`${command} and ${spokenPhrase} are ${similarityRatio * 100}% similar`),
      // If the spokenPhrase is "Benji", the message would be "Beijing and Benji are 40% similar"
      isFuzzyMatch: true,
      fuzzyMatchingThreshold: 0.2
    },
    {
      command: 'clear',
      callback: ({ resetTranscript }) => resetTranscript(),
      matchInterim: true
    },
  ]

  return (

Dictaphone A

{message}

      <Dictaphone commands={commands} />

  )
}

export default DictaphoneWidgetA

Add clear command to example


import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),
  intl: Ember.inject.service(),
  queryParams: ['page', 'perPage', 'sort', 'q', 'medium', 'station'],
  sort: 'random',
  q: null,
  medium: null,
  station: null,

  page: 1,
  perPage: 6,
  totalPages: Ember.computed.alias("content.broadcasts.totalPages"),

  positiveImpressionsWithoutAmount: Ember.computed.filterBy('model.impressions','needsAmount', true),

  actions: {
    searchAction(query){
      this.send('setQuery', query);
      this.set('page', 1);
    },
    browse(step){
      this.set('page', step);
    },
    respond(broadcast){
      broadcast.get('impressions.firstObject').save();
    },
    loginAction(){
      this.send('login');
    },
    sortBroadcasts(direction) {
      this.set('sort', direction);
      this.get('filterParams').sort = direction;
    },
  }
});

import Ember from 'ember';

export default Ember.Controller.extend({
  session: Ember.inject.service('session'),
  intl: Ember.inject.service(),
  queryParams: ['mark_as_seen', 'page', 'perPage', 'sort', 'q', 'medium', 'station'],
  sort: 'random',
  q: null,
  medium: null,
  station: null,
  mark_as_seen: true,

  page: 1,
  perPage: 6,
  totalPages: Ember.computed.alias("content.broadcasts.totalPages"),

  positiveImpressionsWithoutAmount: Ember.computed.filterBy('model.impressions','needsAmount', true),

  actions: {
    searchAction(query){
      this.send('setQuery', query);
      this.set('page', 1);
    },
    browse(step){
      this.set('page', step);
    },
    respond(broadcast){
      broadcast.get('impressions.firstObject').save();
    },
    loginAction(){
      this.send('login');
    },
    sortBroadcasts(direction) {
      this.set('sort', direction);
      this.get('filterParams').sort = direction;
    },
  }
});

Send query param to backend


// import AJAX from 'utils/ajax';

export function getDashboards() {
  // return AJAX({
    // method: 'GET',
    // url: `/chronograf/v1/dashboards`,
  // });
  return {
    then(cb) {
      cb([
        {name: "Goldeneye System Status"},
        {name: "Carver Media Group Broadcast System Status"},
        {name: "Icarus Space Program Status"},
      ]);
    },
  };
}

import AJAX from 'utils/ajax';

export function getDashboards() {
  return AJAX({
    method: 'GET',
    url: `/chronograf/v1/dashboards`,
  });
}

Make dashboard list fetch from API


document.addEventListener("DOMContentLoaded", function (event) {
    // redirect to 7777 port
    // ping golang counter
    getRequest("localhost:7777/count", function (request) {
        var response = request.currentTarget.response || request.target.responseText;
        console.log(response);
    })
});

function getRequest(url, success) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = success;
    xhr.send();
    return xhr;
}

document.addEventListener("DOMContentLoaded", function (event) {
    // redirect to 7777 port
    // ping golang counter
    getRequest("http://www.aracki.me:7777/count", function (request) {
        var response = request.currentTarget.response || request.target.responseText;
        console.log(response);
    })
});

function getRequest(url, success) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onload = success;
    xhr.send();
    return xhr;
}

Fix url for get request


import Ember from 'ember';
import config from '../config/environment';

export default Ember.Component.extend({

  foundation: null,
  isMobileApp: config.cordova.enabled,

  currentClassName: Ember.computed("className", function(){
    return this.get("className") ? `.${this.get('className')}` : document;
  }),

  click() {
    Ember.run.later(function() {
      let mobileApp = this.get("isMobileApp");
      if($('.off-canvas-wrap.move-right')[0]) {
        mobileApp ? $('body').css('overflow', 'hidden') : $('html').css('overflow', 'hidden');
      } else {
        mobileApp ? $('body').css('overflow', 'auto') : $('html').css('overflow', 'auto');
      }
    }, 100);
  },

  didInsertElement() {
    var className = this.get("currentClassName");
    var _this = this;

    this._super();

    Ember.run.debounce(this, function(){
      var clientHeight = $( window ).height();
      $('.inner-wrap').css('min-height', clientHeight);
    }, 1000);

    Ember.run.scheduleOnce('afterRender', this, function(){
      var initFoundation = Ember.$(className).foundation({
        offcanvas: { close_on_click: true }
      });
      _this.set("foundation", initFoundation);
    });
  }

  // TODO: Breaks sometime on menu-bar
  // willDestroyElement() {
  //   this.get("foundation").foundation("destroy");
  // }

});

import Ember from 'ember';

export default Ember.Component.extend({

  foundation: null,

  currentClassName: Ember.computed("className", function(){
    return this.get("className") ? `.${this.get('className')}` : document;
  }),

  click() {
    Ember.run.later(function() {
      if($('.off-canvas-wrap.move-right')[0]) {
        $('html').css('overflow', 'hidden');
      } else {
        $('html').css('overflow', 'auto');
      }
    }, 100);
  },

  didInsertElement() {
    var className = this.get("currentClassName");
    var _this = this;

    this._super();

    Ember.run.debounce(this, function(){
      var clientHeight = $( window ).height();
      $('.inner-wrap').css('min-height', clientHeight);
    }, 1000);

    Ember.run.scheduleOnce('afterRender', this, function(){
      var initFoundation = Ember.$(className).foundation({
        offcanvas: { close_on_click: true }
      });
      _this.set("foundation", initFoundation);
    });
  }

  // TODO: Breaks sometime on menu-bar
  // willDestroyElement() {
  //   this.get("foundation").foundation("destroy");
  // }

});

Revert "GCW-1826 Disable scroll when menu is open"


/**
The following batches are equivalent:

var beautify_js = require('js-beautify');
var beautify_js = require('js-beautify').js;
var beautify_js = require('js-beautify').js_beautify;

var beautify_css = require('js-beautify').css;
var beautify_css = require('js-beautify').css_beautify;

var beautify_html = require('js-beautify').html;
var beautify_html = require('js-beautify').html_beautify;

All methods returned accept two arguments, the source string and an options object.
**/
var js_beautify = require('./beautify').js_beautify;
var css_beautify = require('./beautify-css').css_beautify;
var html_beautify = require('./beautify-html').html_beautify;

// the default is js
var beautify = function (src, config) {
    return js_beautify(src, config);
};

// short aliases
beautify.js   = js_beautify;
beautify.css  = css_beautify;
beautify.html = html_beautify;

// legacy aliases
beautify.js_beautify   = js_beautify;
beautify.css_beautify  = css_beautify;
beautify.html_beautify = html_beautify;

module.exports = beautify;

/**
The following batches are equivalent:

var beautify_js = require('js-beautify');
var beautify_js = require('js-beautify').js;
var beautify_js = require('js-beautify').js_beautify;

var beautify_css = require('js-beautify').css;
var beautify_css = require('js-beautify').css_beautify;

var beautify_html = require('js-beautify').html;
var beautify_html = require('js-beautify').html_beautify;

All methods returned accept two arguments, the source string and an options object.
**/
var js_beautify = require('./lib/beautify').js_beautify;
var css_beautify = require('./lib/beautify-css').css_beautify;
var html_beautify = require('./lib/beautify-html').html_beautify;

// the default is js
var beautify = function (src, config) {
    return js_beautify(src, config);
};

// short aliases
beautify.js   = js_beautify;
beautify.css  = css_beautify;
beautify.html = html_beautify;

// legacy aliases
beautify.js_beautify   = js_beautify;
beautify.css_beautify  = css_beautify;
beautify.html_beautify = html_beautify;

module.exports = beautify;

Fix path to beautify libs.


module.exports = {
  testPathIgnorePatterns: ['<rootDir>[/\\\\](dist|node_modules)[/\\\\]'],
  moduleNameMapper: {
    '(seek-style-guide/react|.(css|less)$)': require.resolve(
      'identity-obj-proxy'
    ),
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|svg)$': require.resolve(
      './fileMock'
    )
  },
  transform: {
    '^.+\\.js$': require.resolve('./babelTransform.js')
  }
};

module.exports = {
  prettierPath: require.resolve('prettier'),
  testPathIgnorePatterns: ['<rootDir>[/\\\\](dist|node_modules)[/\\\\]'],
  moduleNameMapper: {
    '(seek-style-guide/react|.(css|less)$)': require.resolve(
      'identity-obj-proxy'
    ),
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|svg)$': require.resolve(
      './fileMock'
    )
  },
  transform: {
    '^.+\\.js$': require.resolve('./babelTransform.js')
  }
};

Add prettierPath to Jest config


function Messages(clear, empty, firstMessage, displayMessage, displayMessageLong) {
	this.messages = [];
	this.clear = clear;
	this.empty = empty;
	this.firstMessage = firstMessage;
	this.displayMessage = displayMessage;
	this.displayMessageLong = displayMessageLong;
}

Messages.prototype.hasMessages = function () {
	return this.messages.length > 0;
}

Messages.prototype.showMessage = function () {
	var message = this.messages[0];
	var display = message.length > 16 ? this.displayMessageLong : this.displayMessage;

	this.clear();
	display(message);
}

Messages.prototype.nextMessage = function () {
	if (this.messages.length < 1) return;

	this.messages.splice(0, 1);
	if (this.messages.length > 0) this.showMessage();
	else { this.clear(); this.empty(); }
}

Messages.prototype.receive = function (message) {
	var firstMessage = this.messages.length === 0;

	this.messages.push(message);

	if (firstMessage) {
		this.firstMessage();
		this.showMessage();
	}
}
module.exports = Messages;

function Messages(clear, empty, firstMessage, displayMessage, displayMessageLong) {
	this.messages = [];
	this.clear = clear;
	this.empty = empty;
	this.firstMessage = firstMessage;
	this.displayMessage = displayMessage;
	this.displayMessageLong = displayMessageLong;
}

Messages.prototype.hasMessages = function () {
	return this.messages.length > 0;
}

Messages.prototype.showMessage = function () {
	var message = this.messages[0];
	var display = message.length > 16 ? this.displayMessageLong : this.displayMessage;

	this.clear();
	setImmediate(function() { display(message); });
}

Messages.prototype.nextMessage = function () {
	if (this.messages.length < 1) return;

	this.messages.splice(0, 1);
	if (this.messages.length > 0) this.showMessage();
	else { this.clear(); this.empty(); }
}

Messages.prototype.receive = function (message) {
	var firstMessage = this.messages.length === 0;

	this.messages.push(message);

	if (firstMessage) {
		this.firstMessage();
		this.showMessage();
	}
}
module.exports = Messages;

Make LCD behave a bit better


export default function (adId) {
  var mockNetworkDelayMs = 0
  const useMockDelay = false
  if (useMockDelay) {
    mockNetworkDelayMs = Math.random() * (1500 - 900) + 900
  }

  // Mock returning an ad.
  setTimeout(() => {
    const elem = document.getElementById(adId)
    if (!elem) {
      return
    }
    elem.setAttribute('style', `
      color: white;
      background: repeating-linear-gradient(
        -55deg,
        #222,
        #222 20px,
        #333 20px,
        #333 40px
      );
      width: 100%;
      height: 100%;
    `)
  }, mockNetworkDelayMs)
}

import {
  VERTICAL_AD_SLOT_DOM_ID,
  SECOND_VERTICAL_AD_SLOT_DOM_ID,
  HORIZONTAL_AD_SLOT_DOM_ID
} from 'js/ads/adSettings'

export default function (adId) {
  var mockNetworkDelayMs = 0
  const useMockDelay = false
  if (useMockDelay) {
    mockNetworkDelayMs = Math.random() * (1500 - 900) + 900
  }
  const mapDOMIdToHeight = {
    [VERTICAL_AD_SLOT_DOM_ID]: 250,
    [SECOND_VERTICAL_AD_SLOT_DOM_ID]: 250,
    [HORIZONTAL_AD_SLOT_DOM_ID]: 90
  }
  const height = mapDOMIdToHeight[adId]

  // Mock returning an ad.
  setTimeout(() => {
    const elem = document.getElementById(adId)
    if (!elem) {
      return
    }
    elem.setAttribute('style', `
      color: white;
      background: repeating-linear-gradient(
        -55deg,
        #222,
        #222 20px,
        #333 20px,
        #333 40px
      );
      width: 100%;
      height: ${height}px;
    `)
  }, mockNetworkDelayMs)
}

Fix mock ads for development


var camelCase = require('camel-case');
var snakeCase = require('snake-case');
var paramCase = require('param-case');

var changeKeys = function changeKeys(transformer, obj) {
    if (Object.prototype.toString.call(obj) === '[object Array]') {
        var r = [];
        for (var i = 0; i < obj.length; i++) {
            console.log(obj[i]);
            r.push(changeKeys(transformer, obj[i]));
        }
        return r;
    } else if (typeof obj === 'object') {
        var objectKeys = Object.keys(obj);
        return objectKeys.map(function keysMap(key) {
            return transformer(key);
        }).reduce(function keysReducer(object, changedKey, index) {
            var objValue = obj[objectKeys[index]];

            var transformedValue = changeKeys(transformer, objValue);
            object[changedKey] = transformedValue;
            return object;
        }, {});
    }
    else {
        return obj;
    }

};

var changeCaseObject = {};
changeCaseObject.camel = changeCaseObject.camelCase = function camelCaseObject(obj) {
  return changeKeys(camelCase, obj);
};

changeCaseObject.snake = changeCaseObject.snakeCase = function snakeCaseObject(obj) {
  return changeKeys(snakeCase, obj);
};

changeCaseObject.param = changeCaseObject.paramCase = function paramCaseObject(obj) {
  return changeKeys(paramCase, obj);
};

module.exports = changeCaseObject;

var camelCase = require('camel-case');
var snakeCase = require('snake-case');
var paramCase = require('param-case');

var changeKeys = function changeKeys(transformer, obj) {
     if (Array.isArray(obj)) {
        var r = [];
        for (var i = 0; i < obj.length; i++) {
            console.log(obj[i]);
            r.push(changeKeys(transformer, obj[i]));
        }
        return r;
    } else if (typeof obj === 'object') {
        var objectKeys = Object.keys(obj);
        return objectKeys.map(function keysMap(key) {
            return transformer(key);
        }).reduce(function keysReducer(object, changedKey, index) {
            var objValue = obj[objectKeys[index]];

            var transformedValue = changeKeys(transformer, objValue);
            object[changedKey] = transformedValue;
            return object;
        }, {});
    }
    else {
        return obj;
    }

};

var changeCaseObject = {};
changeCaseObject.camel = changeCaseObject.camelCase = function camelCaseObject(obj) {
  return changeKeys(camelCase, obj);
};

changeCaseObject.snake = changeCaseObject.snakeCase = function snakeCaseObject(obj) {
  return changeKeys(snakeCase, obj);
};

changeCaseObject.param = changeCaseObject.paramCase = function paramCaseObject(obj) {
  return changeKeys(paramCase, obj);
};

module.exports = changeCaseObject;

Change Array check using Array.isArray


#!/usr/local/bin/node

var program = require('commander');
var http = require('http');
var fs = require('fs');

var version = require('./package.json').version;

program
  .command('install [license]')
  .description('Installs a license')
  .version(version)
  .option("-y, --year <year>", 'The year to use. Example: 2014.')
  .option("-n, --fullname <fullname>", 'Your fullname.')
  .action(function(license, options){
    // Use provided year or default to current year.
    var year = options.year || new Date().getUTCFullYear();

    // Create a LICENSE file.
    var file = fs.createWriteStream('LICENSE');

    // Copy appropriate license.
    fs.createReadStream('./licenses/' + license + '.txt').pipe(file);
  });

program.parse(process.argv);

#!/usr/local/bin/node

var program = require('commander');
var http = require('http');
var fs = require('fs');

var version = require('./package.json').version;

program
  .command('install [license]')
  .description('Installs a license')
  .version(version)
  .option("-y, --year <year>", 'The year to use. Example: 2014.')
  .option("-n, --fullname <fullname>", 'Your fullname.')
  .action(function(license, options){
    // Use provided year or default to current year.
    var year = options.year || new Date().getUTCFullYear();

    // Use provided name or default to blank.
    var fullname = options.fullname || '';

    // Create a LICENSE file.
    var license_file = './licenses/' + license + '.txt';
    fs.readFile(license_file, 'utf8', function (err,data) {
      if (err) {
        return console.log(err);
      }

      // Make replacements for year and fullname.
      var result = data
                    .replace(/\[year\]/g, year)
                    .replace(/\[fullname\]/g, fullname);

      fs.writeFile('./LICENSE', result, 'utf8', function (err) {
         if (err) return console.log(err);
      });
    });
  });

program.parse(process.argv);

Make replacements for [year] and


'use strict';

var express      = require('express');
var morgan       = require('morgan');
var compression  = require('compression');
var bodyParser   = require('body-parser');
var cookieParser = require('cookie-parser');
var passport     = require('passport');
var config       = require('./environment');

module.exports = function(app) {
    var env = app.get('env');

    app.use(function(req, res, next) {
        res.header('Access-Control-Allow-Credentials', true);
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
        res.header('Access-Control-Allow-Headers', 'X-HTTP-Method-Override, Content-Type, Accept');
        if ('OPTIONS' === req.method) {
             res.send(200);
         } else {
             next();
         }
    });
    app.use(compression());

    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
    app.use(cookieParser());

    // passport config
    app.use(passport.initialize());
    app.use(passport.session());

    // serve the files out of ./dist as our main files
    app.use(express.static(__dirname + config.server.staticDir, { maxAge: '1d' }));

    if ('development' === env || 'test' === env) {
        app.use(morgan('dev'));
    }
};

'use strict';

var express      = require('express');
var morgan       = require('morgan');
var compression  = require('compression');
var bodyParser   = require('body-parser');
var cookieParser = require('cookie-parser');
var passport     = require('passport');
var config       = require('./environment');

module.exports = function(app) {
    var env = app.get('env');

    app.use(function(req, res, next) {
        res.header('Access-Control-Allow-Credentials', true);
        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
        res.header('Access-Control-Allow-Headers', 'X-HTTP-Method-Override, Content-Type, Accept');
        if ('OPTIONS' === req.method) {
             res.send(200);
         } else {
             next();
         }
    });
    app.use(compression());

    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
    app.use(cookieParser());

    // passport config
    app.use(passport.initialize());
    app.use(passport.session());

    // serve the files out of ./dist as our main files
    app.use(express.static(__dirname + config.server.staticDir, { maxAge: '7d' }));

    if ('development' === env || 'test' === env) {
        app.use(morgan('dev'));
    }
};

Enhance cache to one week


/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var files = [
  'stdlib',
  'io',
  'writer',
  'socket',
  'hash',
  'base64',
  'encodings',
  'utf8',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'context',
  'FOAM',
  'JSONParser',
  'TemplateUtil',
  'FObject',
  'BootstrapModel',
  'mm1Model',
  'mm2Property',
  'mm3Types',
  'mm4Method',
  'mm5Misc',
  'mm6Protobuf',
  'mlang',
  'QueryParser',
  'search',
  'async',
  'visitor',
  'messaging',
  'dao',
  'arrayDAO',
  'ClientDAO',
  'diff',
  'SplitDAO',
  'index',
  'experimental/protobufparser',
  'experimental/protobuf',
  'models',
  'oauth'
];

/**
 * @license
 * Copyright 2012 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var files = [
  'stdlib',
  'io',
  'writer',
  'socket',
  'hash',
  'base64',
  'encodings',
  'utf8',
  'parse',
  'event',
  'JSONUtil',
  'XMLUtil',
  'HTMLParser',
  'context',
  'FOAM',
  'JSONParser',
  'TemplateUtil',
  'FObject',
  'BootstrapModel',
  'mm1Model',
  'mm2Property',
  'mm3Types',
  'mm4Method',
  'mm5Misc',
  'mm6Protobuf',
  'mlang',
  'QueryParser',
  'search',
  'async',
  'visitor',
  'messaging',
  'dao',
  'arrayDAO',
  'ClientDAO',
  'diff',
  'SplitDAO',
  'index',
  'experimental/protobufparser',
  'experimental/protobuf',
  'models',
  'oauth'
];

Add HTMLParser to viewless mdoels.


import React from 'react'
import { PropTypes } from 'prop-types'
import Odometer from 'react-odometerjs'
import Col from 'react-bootstrap/lib/Col'

export default class Stat extends React.PureComponent {
  static propTypes = {
    title: PropTypes.string.isRequired,
    value: PropTypes.any.isRequired,
    emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    prefix: PropTypes.string,
    format: PropTypes.string
  }

  static defaultProps = {
    prefix: ''
  }

  render () {
    return (
      <Col lg={4} md={6} xs={12} className='stat'>
        {this.props.title}:

          {this.props.prefix}
          {this.props.value === 0
            ? 0
            : <Odometer value={this.props.value} options={{format: this.props.format}} />}

{this.props.emoji}

      </Col>
    )
  }
}

import React from 'react'
import { PropTypes } from 'prop-types'
import Odometer from 'react-odometerjs'
import Col from 'react-bootstrap/lib/Col'

export default class Stat extends React.PureComponent {
  static propTypes = {
    title: PropTypes.string.isRequired,
    value: PropTypes.any.isRequired,
    emoji: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
    prefix: PropTypes.string,
    format: PropTypes.string
  }

  static defaultProps = {
    prefix: ''
  }

  render () {
    return (
      <Col lg={4} md={6} xs={12} className='stat'>
        {this.props.title}:

            {this.props.prefix}
            {this.props.value === 0
              ? 0
              : (<Odometer value={this.props.value} options={{format: this.props.format}} />)}

{this.props.emoji}

      </Col>
    )
  }
}

Fix odometer spacing on smaller screen sizes


var CleanWebpackPlugin = require('clean-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');

var debug = '&debug=true'

module.exports = {
  entry: './src/index.js',

  output: {
    path: 'dist',
    filename: 'index.js'
  },

  resolve: {
    modulesDirectories: ['node_modules'],
    extensions: ['', '.js', '.elm']
  },

  module: {
    loaders: [
      {
        test: /\.html$/,
        exclude: /node_modules/,
        loader: 'file?name=[name].[ext]'
      },
      {
        test: /\.elm$/,
        exclude: [/elm-stuff/, /node_modules/],
        loader: 'elm-hot!elm-webpack?verbose=true&warn=true&debug=true'
      }
    ],

    noParse: /\.elm$/
  },

  plugins: [
    new CleanWebpackPlugin(['dist'], {
      root: __dirname,
      verbose: true,
      dry: false
    }),
    new CopyWebpackPlugin([
      { from: 'src/assets', to: 'assets'}
    ])
  ],

  devServer: {
    stats: 'errors-only',
    historyApiFallback: true
  }
};

var CleanWebpackPlugin = require('clean-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');

var debug = '&debug=true'

module.exports = {
  entry: './src/index.js',

  output: {
    path: 'dist',
    filename: 'index.js'
  },

  resolve: {
    modulesDirectories: ['node_modules'],
    extensions: ['', '.js', '.elm']
  },

  module: {
    loaders: [
      {
        test: /\.html$/,
        exclude: /node_modules/,
        loader: 'file?name=[name].[ext]'
      },
      {
        test: /\.elm$/,
        exclude: [/elm-stuff/, /node_modules/],
        loader: 'elm-hot!elm-webpack?verbose=true&warn=true&debug=true'
      }
    ],

    noParse: /\.elm$/
  },

  plugins: [
    new CleanWebpackPlugin(['dist'], {
      root: __dirname,
      verbose: true,
      dry: false
    }),
    new CopyWebpackPlugin([
      { from: 'src/assets', to: 'assets'}
    ])
  ],

  devServer: {
    stats: 'errors-only',
    host: '0.0.0.0',
    historyApiFallback: true
  }
};

Allow testing with ip for dev


'use strict';

var path = require('path');
var webpack = require('webpack');
var prod = process.env.NODE_ENV === 'production';

var config = {
    devtool: prod ? null : 'eval',

    entry: [
        path.join(__dirname, 'demo', 'src', 'demo.js')
    ],

    output: {
        path: path.join(__dirname, 'demo', 'dist', 'js'),
        filename: 'demo.js',
        publicPath: '/demo/dist'
    },

    externals: {
        'react': {
            root: 'React',
            commonjs: 'react',
            commonjs2: 'react',
            amd: 'react'
        },
        'react-dom': {
            root: 'ReactDOM',
            commonjs: 'react-dom',
            commonjs2: 'react-dom',
            amd: 'react-dom'
        }
    },

    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel',
            exclude: /node_modules/,
            query: {
                cacheDirectory: true,
                presets: ['react']
            }
        }, {
            test: /\.json$/,
            loader: 'json'
        }]
    },

    plugins: [
        new webpack.NoErrorsPlugin()
    ]
};

if (prod) {
    config.plugins.push(new webpack.optimize.DedupePlugin());
    config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true));
    config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

module.exports = config;

'use strict';

var path = require('path');
var webpack = require('webpack');
var prod = process.env.NODE_ENV === 'production';

var config = {
    devtool: prod ? null : 'eval',

    entry: [
        path.join(__dirname, 'demo', 'src', 'demo.js')
    ],

    output: {
        path: path.join(__dirname, 'demo', 'dist', 'js'),
        filename: 'demo.js',
        publicPath: '/demo/dist',
        libraryTarget: 'umd'
    },

    externals: {
        'react': {
            root: 'React',
            commonjs: 'react',
            commonjs2: 'react',
            amd: 'react'
        },
        'react-dom': {
            root: 'ReactDOM',
            commonjs: 'react-dom',
            commonjs2: 'react-dom',
            amd: 'react-dom'
        }
    },

    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel',
            exclude: /node_modules/,
            query: {
                cacheDirectory: true,
                presets: ['react']
            }
        }, {
            test: /\.json$/,
            loader: 'json'
        }]
    },

    plugins: [
        new webpack.NoErrorsPlugin()
    ]
};

if (prod) {
    config.plugins.push(new webpack.optimize.DedupePlugin());
    config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true));
    config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

module.exports = config;

Set output target as UMD


import { extend } from 'flarum/extend';
import app from 'flarum/app';
import PermissionGrid from 'flarum/components/PermissionGrid';

app.initializers.add('flarum-approval', () => {
  extend(app, 'getRequiredPermissions', function(required, permission) {
    if (permission === 'discussion.startWithoutApproval') {
      required.push('startDiscussion');
    }
    if (permission === 'discussion.replyWithoutApproval') {
      required.push('discussion.reply');
    }
  });

  extend(PermissionGrid.prototype, 'startItems', items => {
    items.add('startDiscussionsWithoutApproval', {
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),
      permission: 'discussion.startWithoutApproval'
    }, 95);
  });

  extend(PermissionGrid.prototype, 'replyItems', items => {
    items.add('replyWithoutApproval', {
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),
      permission: 'discussion.replyWithoutApproval'
    }, 95);
  });

  extend(PermissionGrid.prototype, 'moderateItems', items => {
    items.add('approvePosts', {
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),
      permission: 'discussion.approvePosts'
    }, 65);
  });
});

import { extend } from 'flarum/extend';
import app from 'flarum/app';

app.initializers.add('flarum-approval', () => {
  extend(app, 'getRequiredPermissions', function (required, permission) {
    if (permission === 'discussion.startWithoutApproval') {
      required.push('startDiscussion');
    }
    if (permission === 'discussion.replyWithoutApproval') {
      required.push('discussion.reply');
    }
  });

  app.extensionData
    .for('flarum-approval')
    .registerPermission({
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.start_discussions_without_approval_label'),
      permission: 'discussion.startWithoutApproval'
    }, 'start', 95)
    .registerPermission({
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.reply_without_approval_label'),
      permission: 'discussion.replyWithoutApproval'
    }, 'reply', 95)
    .registerPermission({
      icon: 'fas fa-check',
      label: app.translator.trans('flarum-approval.admin.permissions.approve_posts_label'),
      permission: 'discussion.approvePosts'
    }, 'moderate', 65);
});

Update admin js for new admin UX


var webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  output: {
    path: __dirname + '/lib',
    filename: 'index.browser.js'
  },
  module: {
    loaders: [
      {test: /\.js$/, loader: 'babel', exclude: /node_modules/}
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'typeof window': JSON.stringify('object')
    }),
    new webpack.optimize.UglifyJsPlugin({
      sourceMap: false
    }),

    // Ignore jsdom in src/parseTable,
    //        http, https and url in src/fetchDoc
    //
    new webpack.IgnorePlugin(/^(?:jsdom|http|https|url)$/)
  ],
  debug: false
};

var webpack = require('webpack');
var isProduction = process.env['NODE_ENV'] === 'production';

module.exports = {
  entry: './src/index.js',
  output: {
    path: __dirname + '/lib',
    filename: 'index.browser.js',
    library: 'hacktablParser'
  },
  module: {
    loaders: [
      {test: /\.js$/, loader: 'babel?optional[]=runtime', exclude: /node_modules/}
    ]
  },
  plugins: [
    new webpack.DefinePlugin({
      'typeof window': JSON.stringify('object')
    }),

    // Ignore jsdom in src/parseTable,
    //        http, https and url in src/fetchDoc
    //
    new webpack.IgnorePlugin(/^(?:jsdom|http|https|url)$/)
  ],
  debug: !isProduction
};

if(isProduction) {
  module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin({
    sourceMap: false
  }))
}

Disable uglifier and enable debugging in non-production mode


var js = require('atomify-js')
  , css = require('atomify-css')
  , server = require('./lib/server')

module.exports = atomify

function atomify (opts, cb) {
  if (opts.css) css(opts.css, callback(cb, 'css'))
  if (opts.js) js(opts.js, callback(cb, 'js'))
}

atomify.js = js
atomify.css = css
atomify.server = server

function callback (cb, type) {
  return function (err, src) {
    cb(err, src, type)
  }
}

var js = require('atomify-js')
  , css = require('atomify-css')
  , server = require('./lib/server')

module.exports = atomify

function atomify (opts, cb) {
  if (opts.assets && opts.css) opts.css.assets = opts.assets
  if (opts.assets && opts.js) opts.js.assets = opts.assets

  if (opts.css) css(opts.css, callback(cb, 'css'))
  if (opts.js) js(opts.js, callback(cb, 'js'))
}

atomify.js = js
atomify.css = css
atomify.server = server

function callback (cb, type) {
  return function (err, src) {
    cb(err, src, type)
  }
}

Enable top level assets config


module.exports = {
  entry: './docs/App.jsx',
  output: {
    filename: './docs/bundle.js'
  },
  devServer: {
    inline: true
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: [
            'react',
            'es2015'
          ],
          plugins: [
            'transform-class-properties',
            'transform-object-rest-spread',
            'transform-function-bind'
          ]
        }
      }
    ]
  }
};

module.exports = {
  entry: './docs/App.jsx',
  output: {
    filename: './docs/bundle.js'
  },
  devServer: {
    inline: true
  },
  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: [
            'react',
            'es2015'
          ],
          plugins: [
            'transform-class-properties',
            'transform-object-rest-spread',
            'transform-function-bind'
          ]
        }
      }
    ]
  },
  devtool: 'source-map'
};

Enable source maps in demo


const path = require('path')

module.exports = {
  context: __dirname,
  entry: './js/ClientApp.js',
  devtool: 'eval',
  output: {
    path: path.join(__dirname, '/public'),
    filename: 'bundle.js'
  },
  devServer: {
    publicPath: '/public/'
  },
  resolve: {
    extensions: ['.js', '.json']
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: true
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/
      },
      {
        include: path.resolve(__dirname, 'js'),
        test: /\.js$/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          }
        ]
      }
    ]
  }
}

const path = require('path')

module.exports = {
  context: __dirname,
  entry: './js/ClientApp.js',
  devtool: 'eval',
  output: {
    path: path.join(__dirname, '/public'),
    filename: 'bundle.js'
  },
  devServer: {
    publicPath: '/public/',
    historyApiFallback: true
  },
  resolve: {
    extensions: ['.js', '.json']
  },
  stats: {
    colors: true,
    reasons: true,
    chunks: true
  },
  module: {
    rules: [
      {
        enforce: 'pre',
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node_modules/
      },
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        include: path.resolve(__dirname, 'js'),
        test: /\.js$/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              url: false
            }
          }
        ]
      }
    ]
  }
}

Add json loader and add historyApiFallback true