import path from 'path';
import { all, promisifyAll, resolve } from 'bluebird';
import osLocale from 'os-locale';
import { curry, propOr, replace } from 'ramda';

const fs = promisifyAll(require('fs'));

/**
 * Returns the user locale. Firstly consider the env variable and, if it
 * doesn't exist, consider machine's locale
 *
 * @return {Promise}
 */
export function getLocale() {
    const { RUNG_LOCALE } = process.env;
    return resolve(RUNG_LOCALE ? RUNG_LOCALE : osLocale());
}

/**
 * Translates a string or fallback to the key
 *
 * @param {Object} map - Object containing extension strings
 * @param {String} key - Key to search in hashmap
 * @return {String}
 */
export const translator = curry((map, key, params = {}) => {
    const sentence = propOr(key, key, map);

    return replace(
        /{{(\w+)}}/g,
        (full, partial) => params[partial] || full,
        sentence
    );
});

/**
 * Reads the JSON file corresponding to a specific locale
 *
 * @return {Promise}
 */
export function getLocaleStrings() {
    return getLocale()
        .then(locale => {
            const localePath = path.join('locales', `${locale}.json`);
            return all([fs.lstatAsync(localePath), localePath]);
        })
        .spread((lstat, localePath) => lstat.isFile()
            ? fs.readFileAsync(localePath).then(JSON.parse)
            : {})
        .catchReturn({});
}

import path from 'path';
import fs from 'fs';
import { all, promisify, resolve } from 'bluebird';
import osLocale from 'os-locale';
import { curry, propOr, replace } from 'ramda';

const readFile = promisify(fs.readFile);

/**
 * Returns the user locale. Firstly consider the env variable and, if it
 * doesn't exist, consider machine's locale
 *
 * @return {Promise}
 */
export function getLocale() {
    const { RUNG_LOCALE } = process.env;
    return resolve(RUNG_LOCALE ? RUNG_LOCALE : osLocale());
}

/**
 * Translates a string or fallback to the key
 *
 * @param {Object} map - Object containing extension strings
 * @param {String} key - Key to search in hashmap
 * @return {String}
 */
export const translator = curry((map, key, params = {}) => {
    const sentence = propOr(key, key, map);

    return replace(
        /{{(\w+)}}/g,
        (full, partial) => params[partial] || full,
        sentence
    );
});

/**
 * Reads the JSON file corresponding to a specific locale
 *
 * @return {Promise}
 */
export function getLocaleStrings() {
    return getLocale()
        .then(locale => readFile(path.join('locales', `${locale}.json`)))
        .then(JSON.parse)
        .catchReturn({});
}

Remove unnecessary verification for locales


'use strict';

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

/**
 * FKit treats both arrays and strings as *lists*: an array is a list of
 * elements, and a string is a list of characters.
 *
 * Representing strings as lists may be a novel concept for some JavaScript
 * users, but it is quite common in other languages. This seemingly simple
 * abstractions yields a great deal of power: it allows you to apply the same
 * list combinators to both arrays and strings.
 *
 * @summary Working with Lists
 *
 * @module fkit/list
 * @mixes module:fkit/list/base
 * @mixes module:fkit/list/build
 * @mixes module:fkit/list/fold
 * @mixes module:fkit/list/map
 * @mixes module:fkit/list/search
 * @mixes module:fkit/list/set
 * @mixes module:fkit/list/sublist
 * @mixes module:fkit/list/zip
 * @author Josh Bassett
 */
module.exports = util.extend({}, [
  require('./list/base'),
  require('./list/build'),
  require('./list/fold'),
  require('./list/map'),
  require('./list/search'),
  require('./list/set'),
  require('./list/sublist'),
  require('./list/zip'),
]);

'use strict';

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

/**
 * FKit treats both arrays and strings as *lists*: an array is a list of
 * elements, and a string is a list of characters.
 *
 * Representing strings as lists may be a novel concept for some JavaScript
 * users, but it is quite common in other languages. This seemingly simple
 * abstractions yields a great deal of power: it allows you to apply the same
 * list combinators to both arrays and strings.
 *
 * @summary Working with Lists
 *
 * @module fkit/list
 * @mixes module:fkit/list/base
 * @mixes module:fkit/list/build
 * @mixes module:fkit/list/fold
 * @mixes module:fkit/list/map
 * @mixes module:fkit/list/search
 * @mixes module:fkit/list/set
 * @mixes module:fkit/list/sort
 * @mixes module:fkit/list/sublist
 * @mixes module:fkit/list/zip
 * @author Josh Bassett
 */
module.exports = util.extend({}, [
  require('./list/base'),
  require('./list/build'),
  require('./list/fold'),
  require('./list/map'),
  require('./list/search'),
  require('./list/set'),
  require('./list/sort'),
  require('./list/sublist'),
  require('./list/zip'),
]);

Fix an issue where the sort function weren't included in the fkit module.


import React from 'react';
import ReactDom from 'react-dom';
import {UltimatePagination} from 'react-ultimate-pagination';

ReactDom.render(<UltimatePagination currentPage={1} totalPages={10}/>, document.getElementById('main'));

import React from 'react';
import ReactDom from 'react-dom';
import {UltimatePagination} from 'react-ultimate-pagination';

class App extends React.Component {
  constructor() {
    super();

    this.onTotalPagesChange = this.onTotalPagesChange.bind(this);
    this.onCurrentPageChange = this.onCurrentPageChange.bind(this);

    this.state = {
      currentPage: 1,
      totalPages: 10
    };
  }

  onTotalPagesChange(event) {
    this.setState({totalPages: +event.target.value});
  }

  onCurrentPageChange(event) {
    this.setState({currentPage: +event.target.value});
  }

  render() {
    return (

          Total pages:
          <input
            type="number"
            id="totalPages"
            value={this.state.totalPages}
            min="1"
            onChange={this.onTotalPagesChange}
          />

          Current page:
          <input
            type="number"
            id="currentPage"
            value={this.state.currentPage}
            min="1"
            max={this.state.totalPages}
            onChange={this.onCurrentPageChange}
          />

        <UltimatePagination currentPage={this.state.currentPage} totalPages={this.state.totalPages}/>

    );
  }
}

ReactDom.render(<App />, document.getElementById('main'));

Add configuration form to an example


import React from 'react';
import PropTypes from 'prop-types';
import { withProps } from 'recompose';
import BandwidthThemeProvider from '../BandwidthThemeProvider';
import DefaultStyleRoot from './styles/StyleRoot';
import withDragDropContext from './withDragDropContext';
import DefaultDragLayer from '../DragLayer';
import './styles/global'; // injects a global stylesheet

const Provider = ({ StyleRoot, ThemeProvider, DragLayer, children }) => (
  <ThemeProvider>
    <StyleRoot>
      {children}
      <DragLayer />
    </StyleRoot>
  </ThemeProvider>
);

Provider.propTypes = {
  StyleRoot: PropTypes.func,
  ThemeProvider: PropTypes.func,
  DragLayer: PropTypes.func,
  children: PropTypes.node.isRequired,
};

Provider.defaultProps = {
  StyleRoot: DefaultStyleRoot,
  ThemeProvider: BandwidthThemeProvider,
  DragLayer: DefaultDragLayer,
};

export default withDragDropContext(Provider);

import React from 'react';
import PropTypes from 'prop-types';
import { withProps } from 'recompose';
import BandwidthThemeProvider from '../BandwidthThemeProvider';
import DefaultStyleRoot from './styles/StyleRoot';
import withDragDropContext from './withDragDropContext';
import DefaultDragLayer from '../DragLayer';
import './styles/global'; // injects a global stylesheet

class Provider extends React.PureComponent {
  static propTypes = {
    StyleRoot: PropTypes.func,
    ThemeProvider: PropTypes.func,
    DragLayer: PropTypes.func,
    children: PropTypes.node.isRequired,
  };

  static defaultProps = {
    StyleRoot: DefaultStyleRoot,
    ThemeProvider: BandwidthThemeProvider,
    DragLayer: DefaultDragLayer,
  };

  render() {
    const { StyleRoot, ThemeProvider, DragLayer, children } = this.props;
    return (
      <ThemeProvider>
        <StyleRoot>
          {children}
          <DragLayer />
        </StyleRoot>
      </ThemeProvider>
    );
  }
}

export default withDragDropContext(Provider);

Update drag context usage to avoid error about refs


// @flow

import React, { useCallback, useContext } from 'react';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import { BridgeContext, StoreContext } from '../context';

export default function ReloadAndProfileButton() {
  const bridge = useContext(BridgeContext);
  const store = useContext(StoreContext);

  const reloadAndProfile = useCallback(() => bridge.send('reloadAndProfile'), [
    bridge,
  ]);

  if (!store.supportsReloadAndProfile) {
    return null;
  }

  return (
    <Button onClick={reloadAndProfile} title="Reload and start profiling">
      <ButtonIcon type="reload" />
    </Button>
  );
}

// @flow

import React, { useCallback, useContext } from 'react';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
import { BridgeContext, StoreContext } from '../context';

export default function ReloadAndProfileButton() {
  const bridge = useContext(BridgeContext);
  const store = useContext(StoreContext);

  const reloadAndProfile = useCallback(() => bridge.send('reloadAndProfile'), [
    bridge,
  ]);

  if (!store.supportsReloadAndProfile) {
    return null;
  }

  return (
    <Button
      disabled={!store.supportsProfiling}
      onClick={reloadAndProfile}
      title="Reload and start profiling"
    >
      <ButtonIcon type="reload" />
    </Button>
  );
}

Disable reload-and-profile button if no renderers support profiling


const models = {
  page: require('../models/page'),
  user: require('../models/user')
}

const remove = [
  '_id',
  'id',
  'password',
  '__v'
]

exports.one = function *(type, _id) {
  const query = models[type].where({ _id })

  try {
    var item = yield query.findOne()
  } catch (err) {
    return log('Couldn\'t load ' + type + 's', err)
  }

  var attributes = item.toObject()

  for (var property of remove) {
    delete attributes[property]
  }

  return {
    id: _id,
    type: type.toLowerCase(),
    attributes
  }
}

exports.all = function *(type) {
  const plural = type + 's'

  try {
    var items = yield models[type].find()
  } catch (err) {
    return log('Couldn\'t load ' + plural, err)
  }

  var list = []

  for (var item in items) {
    var attributes = items[item].toObject()
    var id = attributes.id

    for (var property of remove) {
      delete attributes[property]
    }

    list.push({
      id,
      type: plural,
      attributes
    })
  }

  return list
}

const models = {
  page: require('../models/page'),
  user: require('../models/user')
}

const remove = [
  '_id',
  'id',
  'password',
  '__v'
]

exports.one = function *(type, _id) {
  const query = models[type].where({ _id })

  try {
    var item = yield query.findOne()
  } catch (err) {
    return log('Couldn\'t load ' + type + 's', err)
  }

  var attributes = item.toObject()

  for (var property of remove) {
    delete attributes[property]
  }

  return {
    id: _id,
    type: type.toLowerCase(),
    attributes
  }
}

exports.all = function *(type) {
  const plural = type + 's'

  try {
    var items = yield models[type].find()
  } catch (err) {
    return log('Couldn\'t load ' + plural, err)
  }

  var list = []

  for (var item in items) {
    var attributes = items[item].toObject()
    var id = attributes.id || attributes._id

    for (var property of remove) {
      delete attributes[property]
    }

    list.push({
      id,
      type: plural,
      attributes
    })
  }

  return list
}

Use _id if id is not set


/* eslint no-console: 0 */
'use strict';

const irc = require('irc');

const server = process.env.IRC_SERVER;
const user = process.env.IRC_USER;
const channel = process.env.IRC_CHANNEL;

const client = module.exports.client = new irc.Client(server, user, {
  autoConnect: false,
  autoRejoin: true,
  channels: [channel],
  showErrors: true,
});

client.connect(5, function() {
  console.log(new Date(), '[IRC]', 'Connected!');
});

if (process.env.NODE_ENV !== 'testing') {
  client.on('registered', function clientOnRegisterd(message) {
    console.log(new Date(), '[IRC]', message.args[1]);
  });
}

client.on('error', function clientOnError(error) {
  console.error(error);
  console.error('Shutting Down...');
  process.exit(1);
});

module.exports.notify = function ircPost(nodes, callback) {
  nodes.forEach(function nodesForEach(node) {
    // let name = `[${node.name}](${jenkins}/computer/${node.name})`;

    if (node.offline) {
      client.say(channel, `Jenkins slave ${node.name} is offline`);
    } else {
      client.say(channel, `Jenkins slave ${node.name} is online`);
    }
  });

  callback(null);
};

/* eslint no-console: 0 */
'use strict';

const irc = require('irc');

const server = process.env.IRC_SERVER;
const user = process.env.IRC_USER;
const channel = process.env.IRC_CHANNEL;

const client = module.exports.client = new irc.Client(server, user, {
  autoConnect: false,
  autoRejoin: true,
  channels: [channel],
  showErrors: true,
});

client.connect(5, function clientConnectCb() {
  console.log(new Date(), '[IRC]', 'Connected!');
});

if (process.env.NODE_ENV !== 'testing') {
  client.on('registered', function clientOnRegisterd(message) {
    console.log(new Date(), '[IRC]', message.args[1]);
  });
}

client.on('error', function clientOnError(error) {
  console.error(error);
  console.error('Shutting Down...');
  process.exit(1);
});

module.exports.notify = function ircPost(nodes, callback) {
  nodes.forEach(function nodesForEach(node) {
    // let name = `[${node.name}](${jenkins}/computer/${node.name})`;

    if (node.offline) {
      client.say(channel, `Jenkins slave ${node.name} is offline`);
    } else {
      client.say(channel, `Jenkins slave ${node.name} is online`);
    }
  });

  callback(null);
};

Add missing function expression name


/*jshint node:true*/
module.exports = {
  description: 'Add LiquidFire to the consumers app',

  // So we don't see the entity name error
  normalizeEntityName: function() {},

  afterInstall: function() {
    return this.addAddonToProject({
      name: 'liquid-fire',
      version: '0.22.1'
    });
  }
};

/*jshint node:true*/
module.exports = {
  description: 'Add LiquidFire to the consumers app',

  // So we don't see the entity name error
  normalizeEntityName: function() {},

  afterInstall: function() {
    return this.addAddonToProject({
      name: 'liquid-fire',
      version: '0.23.0'
    });
  }
};

Update liquid-fire version in blueprint


'use strict';

/*
 * Tanura main script.
 *
 * This script defines Tanura's high level features.
 */

/*
 * Check if an event exists.
 *
 * When given an event name, this function will check, if there is an entry in
 * tanura.eventHandler.events for that name, that has the methods required.
 */
tanura.eventHandler.check = function(_) {
    return !! this[_] && Array.isArray(this[_]);
}.bind(tanura.eventHandler.events)

/*
 * Safely perform something on an event.
 *
 * This will check if a given event exists and call a given function on it, if
 * it does. The return value indicates if the event was found.
 */
tanura.eventHandler.safe = function(_, f) {
    return this.check(_) && ! f(this.events[_]) || true;
}.bind(tanura.eventHandler)

/*
 * Fire an event.
 *
 * When given an event name, this function will run all callbacks for that
 * event. Exit is true on success, false otherwise.
 */
tanura.eventHandler.fire = (_) =>
    tanura.eventHandler.safe(_, (_) => _.forEach((i) => i()));

/*
 * Register a callback for an event.
 *
 * This will add a function to be called whenever a given event occurs. Exit is
 * true on success, false otherwise.
 */
tanura.eventHandler.register = (_, f) =>
    tanura.eventHandler.safe(_, (_) => _.push(f));

'use strict';

/*
 * Tanura main script.
 *
 * This script defines Tanura's high level features.
 */

/*
 * Check if an event exists.
 *
 * When given an event name, this function will check, if there is an entry in
 * tanura.eventHandler.events for that name, that has the methods required.
 */
tanura.eventHandler.check = function(_) {
    return !! this[_] && Array.isArray(this[_]);
}.bind(tanura.eventHandler.events)

/*
 * Safely perform something on an event.
 *
 * This will check if a given event exists and call a given function on it, if
 * it does. The return value indicates if the event was found.
 */
tanura.eventHandler.safe = function(_, f) {
    return this.check(_) && ! f(this.events[_]) || true;
}.bind(tanura.eventHandler)

/*
 * Fire an event.
 *
 * When given an event name, this function will run all callbacks for that
 * event. A single parameter for the callback may be passed. Exit is true on
 * success, false otherwise.
 */
tanura.eventHandler.fire = (_, x) =>
    tanura.eventHandler.safe(_, (_) => _.forEach((i) => i(x)));

/*
 * Register a callback for an event.
 *
 * This will add a function to be called whenever a given event occurs. Exit is
 * true on success, false otherwise.
 */
tanura.eventHandler.register = (_, f) =>
    tanura.eventHandler.safe(_, (_) => _.push(f));

Add a callback parameter to Tanura's events.


/*jslint bitwise: false, evil: true*/
/*global NoiseOverlay: true, Components: false, dump: false, gBrowser: false, toggleSidebar: true, gFindBar: true*/
if (!NoiseOverlay) {
  var NoiseOverlay = {};
}
Components.utils.import("resource://noise/noise.jsm");

NoiseOverlay = {
  player: null,
  enabled: false,

  init: function () {
    Noise.patchWindow(window);
    this.player = Noise.player;
    this.prefs = Noise.prefs;
    this.enabled = Noise.enabled;
    Noise.addEventHandlers(window);
  },

  uninit: function () {
    Noise.undoPatchWindow(window);
    Noise.removeEventHandlers(window);
    this.player = null;
  },

  reset: function (newMappings) {
    this.enabled = this.prefs.getBoolPref("extensions.noise.enabled");
    Noise.removeEventHandlers(window);
    Noise.addEventHandlers(window, newMappings);
  },

  toggle: function () {
    Noise.toggle();
  },

  play: function () {
    Noise.play.apply(Noise, arguments);
  },

  log: function (aMessage) {
    Noise.log(aMessage);
  }
};

window.addEventListener("load", function () {
  NoiseOverlay.init();
}, false);

window.addEventListener("unload", function () {
  NoiseOverlay.uninit();
}, false);

/*jslint bitwise: false, evil: true*/
/*global NoiseOverlay: true, Components: false, dump: false, gBrowser: false, toggleSidebar: true, gFindBar: true*/
if (!NoiseOverlay) {
  var NoiseOverlay = {};
}
Components.utils.import("resource://noise/noise.jsm");

NoiseOverlay = {
  init: function () {
    Noise.patchWindow(window);
    Noise.addEventHandlers(window);
  },

  uninit: function () {
    Noise.undoPatchWindow(window);
    Noise.removeEventHandlers(window);
  },

  reset: function (newMappings) {
    Noise.removeEventHandlers(window);
    Noise.addEventHandlers(window, newMappings);
  }
};

window.addEventListener("load", function () {
  NoiseOverlay.init();
}, false);

window.addEventListener("unload", function () {
  NoiseOverlay.uninit();
}, false);

Remove unused dummy functions in NoiseOverlay


var gulp = require('gulp');

var javascripts = [
  'Gulpfile.js',
  'index.js',
  'lib/**/*.js',
  'test/**/*.js'
];

gulp.task('jscs', function () {
  var jscs = require('gulp-jscs');
  return gulp.src(javascripts)
    .pipe(jscs({
      preset: 'yandex',
      disallowMultipleVarDecl: 'exceptUndefined'
    }));
});

gulp.task('lint', function () {
  var jshint = require('gulp-jshint');
  return gulp.src(javascripts)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'))
    .pipe(jshint.reporter('fail'));
});

gulp.task('test', function () {
  var mocha = require('gulp-mocha');
  return gulp.src('test/**/*.js', {
    read: false
  })
    .pipe(mocha({
      bail: true
    }));
});

gulp.task('watch', function () {
  return gulp.watch(javascripts, ['default']);
});

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

var gulp = require('gulp');

var javascripts = [
  'Gulpfile.js',
  'index.js',
  'lib/**/*.js',
  'test/**/*.js'
];

gulp.task('jscs', function () {
  var jscs = require('gulp-jscs');
  return gulp.src(javascripts)
    .pipe(jscs({
      preset: 'yandex',
      disallowMultipleVarDecl: 'exceptUndefined'
    }));
});

gulp.task('lint', function () {
  var jshint = require('gulp-jshint');
  return gulp.src(javascripts)
    .pipe(jshint())
    .pipe(jshint.reporter('jshint-stylish'))
    .pipe(jshint.reporter('fail'));
});

gulp.task('test', function () {
  var mocha = require('gulp-mocha');
  return gulp.src('test/**/*.js', {
    read: false
  })
    .pipe(mocha({
      bail: true
    }));
});

gulp.task('watch', function () {
  return gulp.watch(javascripts, ['default']);
});

gulp.task('default', ['lint', 'jscs', 'test']);

Add JSCS and JSHint to default task


'use strict';
var path = require('path');
var assert = require('yeoman-assert');
var helpers = require('yeoman-test');
// Var TestHelper = require('./test-helper');

describe('Testing constant with camelCase module', () => {
  beforeAll(() => {
    return helpers.run(path.join(__dirname, '../generators/constant'))
      .withArguments(['userAuth']);
  });

  const fileDir = 'app/components/user-auth/user-auth.constant.js';

  it('creates files', () => {
    assert.file([fileDir]);
  });

  it('define name', () =>
    assert.fileContent(
      fileDir,
      'export const UserAuthConstant = '
    )
  );
});

describe('Testing constant with succession modules', () => {
  beforeAll(() => {
    return helpers.run(path.join(__dirname, '../generators/constant'))
      .withArguments(['userAuth.foo.bar.fooBar']);
  });

  const fileDir = 'app/components/user-auth/foo/bar/foo-bar/foo-bar.constant.js';

  it('creates files', () => {
    assert.file([
      fileDir
    ]);
  });
});

describe('Testing constant with two arguments', () => {
  beforeAll(() => {
    return helpers.run(path.join(__dirname, '../generators/constant'))
      .withArguments(['userAuth', 'foobar']);
  });

  const fileDir = 'app/components/user-auth/user-auth.constant.js';

  it('define value', () =>
    assert.fileContent(
      fileDir,
      'export const UserAuthConstant = \'foobar\''
    )
  );
});

Test the value param implements


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

test.serial('first pass', t => {
	t.pass();
	return new Promise(resolve => setTimeout(resolve, 3000));
});

test.serial('second pass', t => {
	t.pass();
});

test('third pass', t => {
	t.pass();
});

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

test.serial('first pass', t => {
	t.pass();
	return new Promise(resolve => setTimeout(resolve, 60000));
});

test.serial('second pass', t => {
	t.pass();
});

test('third pass', t => {
	t.pass();
});

Increase timeout in fail-fast interrupt test


import Ember from 'ember';
import AjaxService from 'ember-ajax/services/ajax';

const {
    inject,
    computed
} = Ember;

export default AjaxService.extend({
    auth: inject.service(),

    contentType: 'application/json; charset=utf-8',

    trustedHosts: [
        /outlook.office.com/,
        /graph.microsoft.com/,
        /online.lync.com/
    ],

    headers: computed('auth.msftAccessToken', function () {
        let headers = {};
        const token = this.get('auth.msftAccessToken');
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }
        return headers;
    })
});

import Ember from 'ember';
import AjaxService from 'ember-ajax/services/ajax';

const {
    inject,
    computed
} = Ember;

export default AjaxService.extend({
    auth: inject.service(),

    contentType: 'application/json; charset=utf-8',

    trustedHosts: [
        /outlook.office.com/,
        /graph.microsoft.com/,
        /online.lync.com/,
        /api.(?:inindca|mypurecloud).(?:com|jp).?(?:ie|au)?/
    ],

    headers: computed('auth.msftAccessToken', function () {
        let headers = {};
        const token = this.get('auth.msftAccessToken');
        if (token) {
            headers['Authorization'] = `Bearer ${token}`;
        }
        return headers;
    })
});

Add purecloud hosts as trusted


import { PAUSE_STORAGE_KEY } from '..'

const getState = async () => (await browser.storage.local.get(PAUSE_STORAGE_KEY))[PAUSE_STORAGE_KEY] || false
const setState = state => browser.storage.local.set({ [PAUSE_STORAGE_KEY]: state })

/**
 * Main entrypoint for activity-logging pause from the popup. Keeps track of a running pause timeout
 * which will reset the pause flag in local storage.
 *
 * @return {(number?) => void} A function that allows pause state to be toggled, and optional
 *  specifying of a number of minutes for timeout.
 */
export default function initPauser() {
    const unpause = () => setState(false)
    let timeoutId
    setState(false) // Set default unpaused state in local storage flag

    // Either clears or sets the pause timeout depending on its running state as denoted by local storage flag
    return async timeoutMins => {
        const isPaused = await getState()
        setState(!isPaused) // Immediately toggle the local storage flag and continue on

        timeoutId = isPaused
            ? clearTimeout(timeoutId)
            : setTimeout(unpause, timeoutMins * 60000)
    }
}

import { PAUSE_STORAGE_KEY } from '..'

const getNotifOptions = (message, requireInteraction = false) => ({
    type: 'basic',
    iconUrl: '/overview/img/worldbrain-logo-narrow.png',
    title: 'WorldBrain Activity Logger',
    message,
    requireInteraction,
})

const getState = async () => (await browser.storage.local.get(PAUSE_STORAGE_KEY))[PAUSE_STORAGE_KEY] || false
const setState = state => browser.storage.local.set({ [PAUSE_STORAGE_KEY]: state })

/**
 * Main entrypoint for activity-logging pause from the popup. Keeps track of a running pause timeout
 * which will reset the pause flag in local storage.
 *
 * @return {(number?) => void} A function that allows pause state to be toggled, and optional
 *  specifying of a number of minutes for timeout.
 */
export default function initPauser() {
    let timeoutId
    setState(false) // Set default unpaused state in local storage flag

    const unpause = () => {
        browser.notifications.create(getNotifOptions('Activity logger now running in background again', true))
        setState(false)
    }

    // Either clears or sets the pause timeout depending on its running state as denoted by local storage flag
    return async timeoutMins => {
        const isPaused = await getState()
        setState(!isPaused) // Immediately toggle the local storage flag and continue on

        if (isPaused) { // Interrupt
            clearTimeout(timeoutId)
            unpause()
        } else { // New pause timeout request
            browser.notifications.create(getNotifOptions(`Activity logger now paused for ${timeoutMins} mins`))
            timeoutId = setTimeout(unpause, timeoutMins * 60000)
        }
    }
}

Set up browser/system notifs for pause recording events


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

models.init(function(err) {
    if (err) return console.log(err);
});

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

var products = [
    {
        name: 'Fancy dish',
        price: 1,
        stock: 20
    },
    {
        name: 'Healthy food',
        price: 2,
        stock: 20
    },
    {
        name: 'Feast for kings',
        price: 3,
        stock: 20
    }
];

models.init(function(err) {
    if (err) return console.log(err);

    products.forEach(function(product) {
        models.Product.create(product, function(err, product) {
            console.log('Initialized', product.name);
        });
    });
});

Add fixture data to the db for a faster set up


"use strict";

module.exports = {
    // location of Sqlite DB file
    Cache: `${process.cwd()}/themeparks.db`,
    // default time to cache any data
    DefaultCacheLength: 60 * 60 * 6, // 6 hours
    // default request timeout values
    OpenTimeout: 10000, // 10 seconds; timeout in milliseconds
    ReadTimeout: 0, // 0 seconds; timeout in milliseconds
    // cache settings (in seconds)
    CacheWaitTimesLength: 60 * 5, // 5 minutes
    CacheOpeningTimesLength: 60 * 60, // 1 hour
};

"use strict";

// shim promisify into older NodeJS versions (6)
const util = require("util");
if (util.promisify === undefined) {
    Object.defineProperty(util, "promisify", {
        configurable: true,
        enumerable: true,
        value: (func) => (...args) => new Promise((resolve, reject) => func(...args, (err, res) => err ? reject(err) : resolve(res))),
        writable: true
    });
}

module.exports = {
    // location of Sqlite DB file
    Cache: `${process.cwd()}/themeparks.db`,
    // default time to cache any data
    DefaultCacheLength: 60 * 60 * 6, // 6 hours
    // default request timeout values
    OpenTimeout: 10000, // 10 seconds; timeout in milliseconds
    ReadTimeout: 0, // 0 seconds; timeout in milliseconds
    // cache settings (in seconds)
    CacheWaitTimesLength: 60 * 5, // 5 minutes
    CacheOpeningTimesLength: 60 * 60, // 1 hour
};

Build a basic util.promisify shim for NodeJS 6


import React from 'react'
import Input from './input'

export default class CheckboxList extends Input {
  onChange(value) {
    this.setState({ value: [value] })
    this.onUpdate([value])
  }

  render() {
    return (

        {this.props.property.options.map((option) => {
          let checked = false

          for (let item in this.state.value || []) {
            if (item.value === option.value) {
              checked = true
            }
          }

          return (

              <input
                checked={checked}
                onChange={(e) => this.onChange([option.value])}
                name={this.props.property.id}
                type='checkbox'
                value={option.value} />
              {option.title}

          )
        })}

    )
  }
}

import React from 'react'
import Input from './input'

function isChecked(values, option) {
  for (let value of values || []) {
    if (option.value === value) {
      return true
    }
  }
}

export default class CheckboxList extends Input {
  onChange(e, value) {
    let values = [...this.state.value || []]

    if (e.target.checked) {
      values.push(value)
    }
    else {
      values.splice(values.indexOf(value), 1)
    }

    if (!values.length) {
      values = null
    }

    this.setState({ value: values })
    this.onUpdate(values)
  }

  render() {
    return (

        {this.props.property.options.map((option) => {
          return (

              <input
                checked={isChecked(this.state.value, option)}
                onChange={(e) => this.onChange(e, option.value)}
                name={this.props.property.id}
                type='checkbox'
                value={option.value} />
              {option.title}

          )
        })}

    )
  }
}

Add support for updating checkbox list values.


const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const ipcMain = electron.ipcMain;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
	// Create the browser window.
	mainWindow = new BrowserWindow({
		width: 870,
		height: 475,
		icon: __dirname + '../images/logo/logo.png'
	});

	// and load the index.html of the app.
	mainWindow.loadURL(`file://${__dirname}/../index.html`);

	// Emitted when the window is closed.
	mainWindow.on('closed', function() {
		// Dereference window object
		mainWindow = null;
	});
}

// Called when Electron has finished initialization.
app.on('ready', createWindow);

ipcMain.on('renderData', function(event, arg) {
	var dataWindow = new BrowserWindow({
		width: 1000,
		height: 500
	});
	// Load options page
	dataWindow.loadURL(`file://${__dirname}/../data.html`);

	dataWindow.on('closed', function() {
		// Dereference window object
		dataWindow = null;
	});
});

const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const ipcMain = electron.ipcMain;

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow() {
	// Create the browser window.
	mainWindow = new BrowserWindow({
		width: 750,
		height: 600,
		icon: __dirname + '../images/logo/logo.png'
	});

	// and load the index.html of the app.
	mainWindow.loadURL(`file://${__dirname}/../index.html`);

	// Emitted when the window is closed.
	mainWindow.on('closed', function() {
		// Dereference window object
		mainWindow = null;
	});
}

// Called when Electron has finished initialization.
app.on('ready', createWindow);

ipcMain.on('renderData', function(event, arg) {
	var dataWindow = new BrowserWindow({
		width: 1000,
		height: 500
	});
	// Load options page
	dataWindow.loadURL(`file://${__dirname}/../data.html`);

	dataWindow.on('closed', function() {
		// Dereference window object
		dataWindow = null;
	});
});

Change window size to fit content


import { NodeComponent } from 'substance'
import katex from 'katex'

export default class InlineFormulaComponent extends NodeComponent {

  render($$) {
    const node = this.props.node
    // TODO: Find out why node.find('tex-math') returns null here
    const texMath = node.findChild('tex-math').textContent
    // TODO: Use KaTeX

    const el = $$('span').addClass('sc-math')

    if (this.props.isolatedNodeState) {
      el.addClass('sm-'+this.props.isolatedNodeState)
    }

    try {
      el.append(
        $$('span').html(katex.renderToString(texMath))

      )
      let blockerEl = $$('div').addClass('se-blocker')
      el.append(blockerEl)
    } catch (error) {
      el.addClass('sm-error')
        .text(error.message)
    }

    return el
  }
}

import { NodeComponent } from 'substance'
import katex from 'katex'

export default class InlineFormulaComponent extends NodeComponent {

  render($$) {
    const node = this.props.node
    // TODO: Find out why node.find('tex-math') returns null here
    const texMath = node.findChild('tex-math')
    const el = $$('span').addClass('sc-inline-formula')
    el.append(
      $$(TexMathComponent, {
        node: texMath
      })
    )
    if (this.props.isolatedNodeState) {
      el.addClass('sm-'+this.props.isolatedNodeState)
    }
    return el
  }
}

class TexMathComponent extends NodeComponent {
  render($$) {
    const node = this.props.node
    const texMath = node.textContent
    const el = $$('span').addClass('sc-math')
    try {
      el.append(
        $$('span').html(katex.renderToString(texMath))

      )
      let blockerEl = $$('div').addClass('se-blocker')
      el.append(blockerEl)
    } catch (error) {
      el.addClass('sm-error')
        .text(error.message)
    }

    return el
  }
}

Use separate component for TexMath, so model changes lead to a rerender.


#!/usr/bin/env node

'use strict';

// description: git status across all repositories

var async = require('async');
var chalk = require('chalk');
var gift = require('gift');
var path = require('path');
var _ = require('lodash');

_.str = require('underscore.string');

var storage = require('../lib/storage.js');
var utilities = require('../lib/utilities.js');

utilities.programDefaultsParse('git-status');

storage.setup(function () {
  var projects = storage.allWithDirectory();

  async.eachSeries(projects, function (project, cbEach) {
    var repo = gift(utilities.expand(project.directory));

    repo.status(function (err, repoStatus) {
      if (repoStatus.clean) {
        return cbEach();
      }

      _.each(repoStatus.files, function (status, file) {
        var letter;
        var colorFn;

        if (!status.tracked) {
          letter = '??';
          colorFn = chalk.red;
        } else if (status.type) {
          if (status.staged) {
            letter = _.padRight(status.type, 2);
            colorFn = chalk.yellow;
          } else {
            letter = _.padLeft(status.type, 2);

            if (status.type === 'M') {
              colorFn = chalk.green;
            } else if (status.type === 'D') {
              colorFn = chalk.red;
            }
          }
        }

        console.log(letter, utilities.colorizePath(path.join(project.directory,
          file), colorFn));
      });

      cbEach(err);
    });
  });
});

#!/usr/bin/env node

'use strict';

// description: git status across all repositories

var async = require('async');
var chalk = require('chalk');
var gift = require('gift');
var path = require('path');
var _ = require('lodash');

var storage = require('../lib/storage.js');
var utilities = require('../lib/utilities.js');

utilities.programDefaultsParse('git-status');

storage.setup(function () {
  var projects = storage.allWithDirectory();

  async.eachSeries(projects, function (project, cbEach) {
    var repo = gift(utilities.expand(project.directory));

    repo.status(function (err, repoStatus) {
      if (repoStatus.clean) {
        return cbEach();
      }

      _.each(repoStatus.files, function (status, file) {
        var letter;
        var colorFn;

        if (!status.tracked) {
          letter = '??';
          colorFn = chalk.red;
        } else if (status.type) {
          if (status.staged) {
            letter = _.padRight(status.type, 2);
            colorFn = chalk.yellow;
          } else {
            letter = _.padLeft(status.type, 2);

            if (status.type === 'M') {
              colorFn = chalk.green;
            } else if (status.type === 'D') {
              colorFn = chalk.red;
            }
          }
        }

        console.log(letter, utilities.colorizePath(path.join(project.directory,
          file), colorFn));
      });

      cbEach(err);
    });
  });
});

Remove stray reference to underscore.string


/* global jasmine:true, beforeEach:true, jsc:true */
/* eslint strict:[2,"function"] */
beforeEach(function () {
  "use strict";
  jasmine.addMatchers({
    // Expects that property is synchronous
    toHold: function () {
      return {
        compare: function (actual) {

          /* global window */
          var quiet = window && !(/verbose=true/).test(window.location.search);

          var r = jsc.check(actual, { quiet: quiet });

          var pass = r === true;
          var message = "";

          if (pass) {
            message = "Expected property not to hold.";
          } else {
            message = "Expected property to hold. Counterexample found: " + r.counterexamplestr;
          }

          return {
            pass: pass,
            message: message,
          };
        },
      };
    },
  });
});

/* global jasmine:true, beforeEach:true, jsc:true, Promise:true */
/* eslint strict:[2,"function"] */
beforeEach(function () {
  "use strict";

  function message(r) {
    return "Expected property to hold. Counterexample found: " + r.counterexamplestr;
  }

  jasmine.addMatchers({
    toHold: function () {
      return {
        compare: function (actual, done) {
          var r = jsc.check(actual);
          if (done) {
            Promise.resolve().then(function () { return r; }).then(function (v) {
              if (v === true) {
                done();
              } else {
                done.fail(message(v));
              }
            });
            return {
              pass: true,
            };
          }
          return {
            pass: r === true,
            message: message(r),
          };
        },
      };
    },
  });
});

Support async tests in the Jasmine helper


const gulp = require('gulp');
const mocha = require('gulp-mocha');
const tests = require('../test/unit.test');

gulp.task('test', function() {
    return gulp
        .src(tests)
        .pipe(mocha({
            bail: true
        }))
        .once('end', function() {
            process.exit();
        });
});

const gulp = require('gulp');
const mocha = require('gulp-mocha');
const tests = require('../test/unit.test');

gulp.task('test', function() {
    return gulp
        .src(tests)
        .pipe(mocha({
            bail: true,
            "expose-gc": true
        }))
        .once('end', function() {
            process.exit();
        });
});

ADD harmony for gc in tests


var irc = require('irc');
var knex = require('knex')({
  client: process.env.CLIENT || 'sqlite3',
  connection: process.env.DATABASE_URL || { filename: 'dev.sqlite3' }
});

console.log(process.env.NC_CHANNEL_LIST.split(','));
var client = new irc.Client(process.env.NC_SERVER || 'chat.freenode.net',
  process.env.NC_NICK || 'nick-counter-bot',
  { channels:process.env.NC_CHANNEL_LIST.split(',') }
);

client.addListener('message', function (from, to, message) {
  console.log(from, to, message);
  knex.select('num_messages')
      .from('messages')
      .where( { nick:from } )
      .then(function(resp) {
        console.log(resp);
        if (resp.length) {
          knex('messages').where({nick:from})
            .update({nick:from, num_messages: resp.num_messages + 1})
            .catch(function (error) {
              console.log(error);
            });
        } else {
          knex('messages')
            .insert({nick:from, num_messages: 1})
            .catch(function (error) {
              console.log(error);
            });
        }
      });
});

var irc = require('irc');
var knex = require('knex')({
  client: process.env.CLIENT || 'sqlite3',
  connection: process.env.DATABASE_URL || { filename: 'dev.sqlite3' }
});

console.log(process.env.NC_CHANNEL_LIST.split(','));
var client = new irc.Client(process.env.NC_SERVER || 'chat.freenode.net',
  process.env.NC_NICK || 'nick-counter-bot',
  { channels:process.env.NC_CHANNEL_LIST.split(',') }
);

client.addListener('message', function (from, to, message) {
  knex.select('num_messages')
      .from('messages')
      .where( { nick:from } )
      .then(function(resp) {
        if (resp.length) {
          knex('messages').where({nick:from})
            .update({nick:from, num_messages: resp[0].num_messages + 1})
            .catch(function (error) {
              console.log(error);
            });
        } else {
          knex('messages')
            .insert({nick:from, num_messages: 1})
            .catch(function (error) {
              console.log(error);
            });
        }
      });
});

Access first element of the response first


var request = require('request')

var API_URL = 'https://api.digitalocean.com/v2/'

var api = {
  call: function (options, callback) {
    options.url = API_URL + options.action
    options.headers = {
      json: true,
      Authorization: 'Bearer ' + options.token
    }

    delete options.action
    delete options.token

    request(options, function (err, res, body) {
      if (err) return callback(err)
      if (res.statusCode >= 400) return callback(JSON.parse(body), body)

      callback(null, body)
    })
  }
}

module.exports = api

var request = require('request')

var API_URL = 'https://api.digitalocean.com/v2/'

var api = {
  call: function (options, callback) {
    options.url = API_URL + options.action
    options.headers = {
      json: true,
      Authorization: 'Bearer ' + options.token,
      "Content-Type": "application/json"
    }

    delete options.action
    delete options.token

    request(options, function (err, res, body) {
      if (err) return callback(err)
      if (res.statusCode >= 400) return callback(JSON.parse(body), body)

      callback(null, body)
    })
  }
}

module.exports = api

Add Content-Type json to headers


#!/usr/bin/env node

'use strict'

const path = require('path')
const flags = require('commander')

const markserv = require(path.join(__dirname, 'server'))
const pkg = require(path.join('..', 'package.json'))

const cwd = process.cwd()

flags.dir = cwd

flags.version(pkg.version)
	.usage('<file/dir>')
	.option('-p, --port [type]', 'HTTP port [port]', 8642)
	.option('-l, --livereloadport [type]', 'LiveReload port [livereloadport]', 35729)
	.option('-i, --silent [type]', 'Silent (no logs to CLI)', false)
	.option('-a, --address [type]', 'Serve on ip/address [address]', 'localhost')
	.option('-v, --verbose', 'verbose output')
	.action(serverPath => {
		flags.$pathProvided = true
		flags.dir = path.normalize(path.join(cwd, serverPath))
	}).parse(process.argv)

markserv.init(flags)

#!/usr/bin/env node

'use strict'

const path = require('path')
const flags = require('commander')

const markserv = require(path.join(__dirname, 'server'))
const pkg = require(path.join('..', 'package.json'))

const cwd = process.cwd()

flags.dir = cwd

flags.version(pkg.version)
	.usage('<file/dir>')
	.option('-p, --port [type]', 'HTTP port [port]', 8642)
	.option('-l, --livereloadport [type]', 'LiveReload port [livereloadport]', 35729)
	.option('-i, --silent [type]', 'Silent (no logs to CLI)', false)
	.option('-a, --address [type]', 'Serve on ip/address [address]', 'localhost')
	.option('-v, --verbose', 'verbose output')
	.action(serverPath => {
		flags.$pathProvided = true
		if (flags.dir[0] !== '/') {
			flags.dir = path.normalize(path.join(cwd, serverPath))
		}
	}).parse(process.argv)

markserv.init(flags)

Allow serving from root paths


DateUtilities = {

    addDay : function(date, days) {
        date.setHours(date.getHours() + 24*days);
    },

    roundToFollowingHalfHour : function(date) {
        date.setMilliseconds(0);
        date.setSeconds(0);

        if(date.getMinutes() < 30) {
            date.setMinutes(30);
        }

        if(date.getMinutes() > 30) {
            date.setMinutes(30);
            date.setHours(date.getHours() + 1);
        }
    },

    // TODO: handle time before opening
    nextOpenTime: function(date) {
        var changed = false;

        if(date.getHours() >= 20) {
            date.setHours(8 + 24);
            changed = true;
        }

        if(date.getDay() == 0) {
            date.setHours(date.getHours() + 24);
            changed = true;
        }

        return changed;
    }

};

DateUtilities = {

    addDay : function(date, days) {
        date.setHours(date.getHours() + 24*days);
    },

    roundToFollowingHalfHour : function(date) {
        date.setMilliseconds(0);
        date.setSeconds(0);

        if(date.getMinutes() < 30) {
            date.setMinutes(30);
        }

        if(date.getMinutes() > 30) {
            date.setMinutes(30);
            date.setHours(date.getHours() + 1);
        }
    },

    // TODO: handle time before opening
    nextOpenTime: function(date) {
        var changed = false;

        if(date.getHours() < 8) {
            date.setHours(8);
            changed = true;
        }

        if(date.getHours() >= 20) {
            date.setHours(8 + 24);
            changed = true;
        }

        if(date.getDay() == 0) {
            date.setHours(date.getHours() + 24);
            changed = true;
        }

        return changed;
    }

};

Fix function nextOpenTime to handle hours before opening.


var FileInfo = loadExtension("qbs.FileInfo");

function soname(product, outputFileName) {
    if (product.moduleProperty("qbs", "targetOS").contains("darwin")) {
        if (product.moduleProperty("bundle", "isBundle"))
            outputFileName = product.moduleProperty("bundle", "executablePath");
        var prefix = product.moduleProperty("cpp", "installNamePrefix");
        if (prefix)
            outputFileName = FileInfo.joinPaths(prefix, outputFileName);
        return outputFileName;
    }

    function majorVersion(version, defaultValue) {
        var n = parseInt(version, 10);
        return isNaN(n) ? defaultValue : n;
    }

    if (product.version) {
        var major = majorVersion(product.version);
        if (major) {
            return outputFileName.substr(0, outputFileName.length - product.version.length)
                    + major;
        }
    }
    return outputFileName;
}

var FileInfo = loadExtension("qbs.FileInfo");

function soname(product, outputFileName) {
    if (product.moduleProperty("qbs", "targetOS").contains("darwin")) {
        if (product.moduleProperty("bundle", "isBundle"))
            outputFileName = product.moduleProperty("bundle", "executablePath");
        var prefix = product.moduleProperty("cpp", "installNamePrefix");
        if (prefix)
            outputFileName = FileInfo.joinPaths(prefix, outputFileName);
        return outputFileName;
    }

    function majorVersion(version, defaultValue) {
        var n = parseInt(version, 10);
        return isNaN(n) ? defaultValue : n;
    }

    var version = product.moduleProperty("cpp", "internalVersion");
    if (version) {
        var major = majorVersion(version);
        if (major) {
            return outputFileName.substr(0, outputFileName.length - version.length)
                    + major;
        }
    }
    return outputFileName;
}

Fix soname generation on non-Darwin Unix platforms.


var path = require('path')

function clean (node) {
  if (node.source) {
    delete node.source.input.css
    node.source.input.file = path.basename(node.source.input.file)
  }

  delete node.indexes
  delete node.lastEach
  delete node.rawCache

  if (node.nodes) node.nodes = node.nodes.map(clean)

  return node
}

module.exports = function jsonify (node) {
  var cleaned = clean(node.toJSON())
  return JSON.stringify(cleaned, null, 2)
}

var path = require('path')

function clean (node) {
  if (node.source) {
    delete node.source.input.css
    delete node.source.input.hasBOM
    node.source.input.file = path.basename(node.source.input.file)
  }

  delete node.indexes
  delete node.lastEach
  delete node.rawCache

  if (node.nodes) node.nodes = node.nodes.map(clean)

  return node
}

module.exports = function jsonify (node) {
  var cleaned = clean(node.toJSON())
  return JSON.stringify(cleaned, null, 2)
}

Remove hasBOM from nodes before test


import Ember from 'ember';
import layout from '../templates/components/tag-input';

const KEY_CODES = {
  BACK_BUTTON: 8,
  COMMA: 188,
  ENTER: 13,
  SPACE: 32
};

export default Ember.Component.extend({
  layout,

  classNames: ['emberTagInput'],

  tagName: 'ul',

  tags: Ember.A(),

  didInsertElement() {
    let tagInput = this.$('.js-ember-tag-input-new');

    tagInput.on('keydown', (e) => {
      let tags = this.get('tags'),
        tagInputVal = tagInput.val().trim();

      if (e.which === KEY_CODES.COMMA || e.which === KEY_CODES.SPACE || e.which === KEY_CODES.ENTER) {
        if (tagInputVal.length > 0) {
          tags.pushObject(tagInputVal);
          tagInput.val('');
          e.preventDefault();
        }
      } else if (e.which === KEY_CODES.BACK_BUTTON) {

      }
    });
  }
});

import Ember from 'ember';
import layout from '../templates/components/tag-input';

const KEY_CODES = {
  BACK_BUTTON: 8,
  COMMA: 188,
  ENTER: 13,
  SPACE: 32
};

export default Ember.Component.extend({
  layout,

  classNames: ['emberTagInput'],

  tagName: 'ul',

  tags: Ember.A(),

  didInsertElement() {
    let tagInput = this.$('.js-ember-tag-input-new');

    tagInput.on('keydown', (e) => {
      let tags = this.get('tags'),
        tagInputVal = tagInput.val().trim();

      if (e.which === KEY_CODES.COMMA || e.which === KEY_CODES.SPACE || e.which === KEY_CODES.ENTER) {
        if (tagInputVal.length > 0) {
          let onTagAdd = this.get('onTagAdd');

          tags.pushObject(tagInputVal);
          tagInput.val('');

          if (onTagAdd) {
            onTagAdd(tagInputVal);
          }

          e.preventDefault();
        }
      } else if (e.which === KEY_CODES.BACK_BUTTON) {
        if (tagInputVal.length === 0) {
          let onTagRemove = this.get('onTagRemove'),
            removedTag = tags.popObject();

          if (onTagRemove) {
            onTagRemove(removedTag);
          }
        }
      }
    });
  }
});

Allow removing tags and add actions for add/remove


var fs = require('fs');

module.exports = function (context, req, res) {
    context.log('function triggered');
    context.log(req);

    fs.writeFile('message.txt', 'Hello Node.js', (err) => {
        if (err) throw err;
        console.log('It\'s saved!');
        context.done();
    });
}

var fs = require('fs');

var environmentVariables = [
    "WEBSITE_SITE_NAME",
    "WEBSITE_SKU",
    "WEBSITE_COMPUTE_MODE",
    "WEBSITE_HOSTNAME",
    "WEBSITE_INSTANCE_ID",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSOCKET_CONCURRENT_REQUEST_LIMIT",
    "%APPDATA%",
    "%TMP%"
]

module.exports = function (context, req, res) {
    context.log('function triggered');
    context.log(req);

    context.log('Environment Variables');
    environmentVariables
        .map(getEnvironmentVarible)
        .forEach(context.log);

    context.log('process.cwd()', process.cwd());
    context.log('__dirname', __dirname);

    fs.writeFile('D:/local/Temp/message.txt', 'Hello Node.js', (err) => {
        if (err) throw err;
        context.log("It's saved!");
        context.done();
    });
}

function getEnvironmentVarible(name) {
    return name + ": " + process.env[name];
}

Add print out of environment variables, cwd, dirname, and change file write destination to local directory.


/**
 * Created by dell on 2015/6/9.
 */
(function(){

    "use strict";

    var adminServices = angular.module('app.admin.services',["app.services"]);

    adminServices.factory("adminInfo",["ApiServer",function(ApiServer){
        return ApiServer.createResource('admin/login',{},{
            "login":{method:'POST',url:ApiServer.getApiUrl('admin/login')}
        });
    }]);

    adminServices.service('admin',[function(){
        this._id;
        this.name;
        this.last_login;
        this.token;

        this.set = function(info){
            this._id = info._id;
            this.name = info.name;
            this.last_login = info.last_login;
            this.token = info.token;
        };
    }]);

    adminServices.service('adminManager',['adminInfo','$q','admin',function(adminInfo,$q,admin){

        this.login = function(user_info){

            var deferred = $q.defer();

            adminInfo.login(user_info).$promise.then(function(response){

                admin.set(response.context);
                sessionStorage.setItem("AUTHOR",JSON.stringify(response.context));
                deferred.resolve(response);

            },function(){
                deferred.reject();
            });

            return deferred.promise;
        }
    }]);

}).call(this);

/**
 * Created by dell on 2015/6/9.
 */
(function(){

    "use strict";

    var adminServices = angular.module('app.admin.services',["app.services"]);

    adminServices.factory("adminInfo",["ApiServer",function(ApiServer){
        return ApiServer.createResource('admin/login',{},{
            "login":{method:'POST',url:ApiServer.getApiUrl('admin/login')}
        });
    }]);

    adminServices.service('admin',[function(){
        this._id;
        this.name;
        this.last_login;
        this.token;

        this.set = function(info){
            this._id = info._id;
            this.name = info.name;
            this.last_login = info.last_login;
            this.token = info.token;
        };
    }]);

    adminServices.service('adminManager',['adminInfo','$q','admin',function(adminInfo,$q,admin){

        this.login = function(user_info){

            var deferred = $q.defer();

            adminInfo.login(user_info).$promise.then(function(response){

                admin.set(response.context);

                sessionStorage.setItem("AUTHOR",JSON.stringify(response.context));
                sessionStorage.setItem("TOKEN",response.context.token);

                deferred.resolve(response);

            },function(){
                deferred.reject();
            });

            return deferred.promise;
        }
    }]);

}).call(this);

Save token to session storage


'use strict';

var _ = require('underscore');

var settings = {};

settings.cookieSecret = process.env.COOKIE_SECRET;

settings.movesClientId = '9uuys57PvQY7G2rFn2uBqPi6uoFabcTT';
settings.movesSecret = process.env.MOVES_SECRET;

settings.movesToken = process.env.MOVES_TOKEN; // if a token is in the environment for demonstration purposes

settings.movesAPIUrl = 'https://api.moves-app.com/api/v1';
settings.movesAuthUrl = 'https://api.moves-app.com/oauth/v1';

module.exports = settings;

'use strict';

var _ = require('underscore');

var settings = {};

settings.cookieSecret = process.env.COOKIE_SECRET;

settings.movesClientId = process.env.MOVES_CLIENT;
settings.movesSecret = process.env.MOVES_SECRET;

settings.movesToken = process.env.MOVES_TOKEN; // if a token is in the environment for demonstration purposes

settings.movesAPIUrl = 'https://api.moves-app.com/api/v1';
settings.movesAuthUrl = 'https://api.moves-app.com/oauth/v1';

module.exports = settings;

Move client id to environment variable


'use strict'

var test = require('tape')

var Compiler = require('../src/app/compiler')
var EventManager = require('../src/lib/eventManager')

test('compiler.compile smoke', function (t) {
  t.plan(1)

  var noop = function () {}
  var getCacheFile = function () { return 'fakeCacheFile' }
  var fakeEditor = {onChangeSetup: noop, clearAnnotations: noop, getValue: noop, setCacheFileContent: noop, getCacheFile: getCacheFile}
  var fakeQueryParams = {get: function () { return {} }}
  var compiler = new Compiler(fakeEditor, fakeQueryParams, null, null, new EventManager())
  compiler.setCompileJSON(noop)
  compiler.compile()
  t.ok(compiler)
})

'use strict'

var test = require('tape')

var Compiler = require('../src/app/compiler')

test('compiler.compile smoke', function (t) {
  t.plan(1)

  var noop = function () {}
  var fakeImport = function (url, cb) { cb('Not implemented') }
  var compiler = new Compiler(fakeImport)
  compiler.setCompileJSON(noop)
  compiler.compile({ 'test': '' }, 'test')
  t.ok(compiler)
})

Update compiler test for the new API


var address = 'https://api.github.com/repos/Coolnesss/lapio-galleria/contents/profiles'

$.get(address, function(data) {
  data.forEach(function(entry) {
    $.getJSON(entry.download_url, function(data) {
      $("#cards").append(`

${data.name} (${data.ircnick})

              ${data.description}

                Visit Homepage

`
      );
    })
  })
})

Add gradient on top of background image


function main() {
    $('#tabs').tabs();
    google.load('visualization', '1', {packages: ['geochart']});
    google.setOnLoadCallback(googleReady);
    var commodities_select=[];
    dojo.ready(chosenDojo);
    //Management of the selection
    $('select').on('change', function(event) {
    var select_object = dojo.byId('select');
    var select_div = dojo.byId('msg');
    var selected_values = [];
    for (x=0;x<=select_object.length;x++) {
        if (select_object[x] && select_object[x].selected) {
            selected_values.push(select_object[x].value);
        }
    }
     select_div.innerHTML = 'Selected value = ' + selected_values;
     console.log(selected_values)
    });
}

//Function to launch the googleAPI
function googleReady() {
    init_import_export();
    init_hscodes();
    worldMap();
    usaMap();
}

//Function to configure options of chosen-dojo commodities selector
function chosenDojo() {
        dojo.query(".chzn-select").chosen();
        dojo.query(".chzn-select-deselect").chosen({allow_single_deselect:true});
        dojo.query(".chzn-select-batch").chosen({batch_select:true});
    }

$(main);

function main() {
    $('#tabs').tabs();
    google.load('visualization', '1', {packages: ['geochart']});
    google.setOnLoadCallback(googleReady);
    var commodities_select=[];
    dojo.ready(chosenDojo);
    //Management of the selection
    $('select').on('change', function(event) {
    var select_object = dojo.byId('select');
    var select_div = dojo.byId('msg');
    var selected_values = [];
    for (var x=0; x<=select_object.length; x++) {
        if (select_object[x] && select_object[x].selected) {
            selected_values.push(select_object[x].value);
        }
    }
     select_div.innerHTML = 'Selected value = ' + selected_values;
     console.log(selected_values);
    });
}

//Function to launch the googleAPI
function googleReady() {
    init_import_export();
    init_hscodes();
    worldMap();
    usaMap();
}

//Function to configure options of chosen-dojo commodities selector
function chosenDojo() {
        dojo.query(".chzn-select").chosen();
        dojo.query(".chzn-select-deselect").chosen({allow_single_deselect:true});
        dojo.query(".chzn-select-batch").chosen({batch_select:true});
    }

$(main);

Trim trailing whitespace, add missing semicolon


import plugin_data from 'plugin_data';

export default {
  launchIntent: plugin_data.appCapabilities.launch_intent,
};

import plugin_data from 'plugin_data';

const appCapabilities = plugin_data.appCapabilities || {};

export default {
  launchIntent: appCapabilities.launch_intent,
};

Make capability reading robust for tests.


module.exports = function($stateParams, $state, $scope, $location, SearchService, DocumentRouteService, DocumentService, MathJaxService, UserService) {

    console.log('SITE CONTROLLER')

    var id = $stateParams.id
    UserService.setCurrentSite(id)
    console.log('Hey!, site = ' + id)
    SearchService.query('scope=user.'+id+'?filter=public')
    .then(function(response){
        $scope.site = id
        DocumentRouteService.getDocumentList($scope)
        $scope.docStyle = function(doc) {
            if (doc['id'] == DocumentService.documentId()) { return { "background-color" : "#fee" }}
        }
    })
}

module.exports = function($stateParams, $state, $scope, $location, SearchService, DocumentRouteService, DocumentService, MathJaxService, UserService) {

    console.log('SITE CONTROLLER')

    var id = $stateParams.id
    UserService.setCurrentSite(id)
    console.log('Hey!, site = ' + id)
    SearchService.query('user.public='+id)
    .then(function(response){
        $scope.site = id
        DocumentRouteService.getDocumentList($scope)
        $scope.docStyle = function(doc) {
            if (doc['id'] == DocumentService.documentId()) { return { "background-color" : "#fee" }}
        }
    }).then(function(result){
        $state.go('site')
    })
}

Fix search problem for /site/:id


Package.describe({
    name: 'smaltcreation:autoform-input-addon-icon',
    version: '1.0.0',
    summary: 'Input with bootstrap addon and custom icon for autoform'
});

Package.onUse(function(api) {
    api.versionsFrom('1.1.0.2');

    // Packages
    api.use([
        'underscore',
        'templating',
        'aldeed:autoform@5.3.2'
    ], 'client');

    // Files
    api.addFiles([
        'autoform-intl-tel-input.html',
        'autoform-intl-tel-input.js'
    ], 'client');
});

Package.describe({
    name: 'smaltcreation:autoform-input-addon-icon',
    version: '1.0.0',
    summary: 'Input with bootstrap addon and custom icon for autoform'
});

Package.onUse(function(api) {
    api.versionsFrom('1.1.0.2');

    // Packages
    api.use([
        'underscore',
        'templating',
        'aldeed:autoform'
    ], 'client');

    // Files
    api.addFiles([
        'autoform-intl-tel-input.html',
        'autoform-intl-tel-input.js'
    ], 'client');
});

Add compitablity with autoform 6


// Remove the webpack-dev-server grunt task since we do not use it
var fs = require('fs');
var path = require('path');

var taskFile = path.join(__dirname, '..', 'node_modules', 'grunt-webpack', 'tasks', 'webpack-dev-server.js');

if (fs.existsSync(taskFile)) {
    console.log('Removing unused task file ' + taskFile);
    fs.unlinkSync(taskFile);
}

// Remove the webpack-dev-server grunt task since we do not use it

var fs = require('fs');
var taskFile = null;

try {
    taskFile = require.resolve('grunt-webpack/tasks/webpack-dev-server.js');
} catch(e) {}

if (taskFile) {
    console.log('Removing unused task file ' + taskFile);
    fs.unlinkSync(taskFile);
}

Use require.resolve for more robust path lookup


module.exports = function (grunt) {
	return {
		options: {
			separator: Array(3).join(grunt.util.linefeed),
			sourceRoot: process.env.CI ? 'http://raw.github.com/' + process.env.TRAVIS_REPO_SLUG + '/' + process.env.TRAVIS_COMMIT : '../..'
		},
		all: {
			files: {
				'dist/<%= pkgName %>.js': [
					'umd/header.js',

					'src/shim.js',
					'src/utils.js',
					'src/core.js',
					'src/proto/cache.js',
					'src/proto/context.js',
					'src/type.js',
					'src/template.js',
					'src/proto/as.js',
					'src/proto/position.js',
					'src/proto/props.js',
					'src/typeSet/*.js',
					'src/io/toURI.js',
					'src/io/load.js',
					'src/io/save.js',

					'umd/footer.js'
				]
			}
		}
	};
};

module.exports = function (grunt) {
	return {
		options: {
			separator: Array(3).join(grunt.util.linefeed),
			sourceRoot: process.env.CI ? 'https://raw.github.com/' + process.env.TRAVIS_REPO_SLUG + '/' + process.env.TRAVIS_COMMIT : '../..'
		},
		all: {
			files: {
				'dist/<%= pkgName %>.js': [
					'umd/header.js',

					'src/shim.js',
					'src/utils.js',
					'src/core.js',
					'src/proto/cache.js',
					'src/proto/context.js',
					'src/type.js',
					'src/template.js',
					'src/proto/as.js',
					'src/proto/position.js',
					'src/proto/props.js',
					'src/typeSet/*.js',
					'src/io/toURI.js',
					'src/io/load.js',
					'src/io/save.js',

					'umd/footer.js'
				]
			}
		}
	};
};

Fix sources protocol to HTTPS.


'use strict';
require('dotenv').config();

const bot = require('./lib/bot.js');

require('./src/releases.js')(bot);
require('./src/releaseAndTag.js')(bot);
require('./src/cheese.js')(bot);
require('./src/conversation.js')(bot);

'use strict';
require('dotenv').config();

const bot = require('./lib/bot.js');

require('./src/releases.js')(bot);
require('./src/releaseAndTag.js')(bot);
require('./src/cheese.js')(bot);
require('./src/dogs.js')(bot);
require('./src/conversation.js')(bot);

Add dog conversation to bot


define([ "jquery", "lib/utils/viewport_helper" ], function($, isInViewport) {
  "use strict";

  var HeroParallax,
      _pageYOffset,
      started = false,
      speed = 15,
      els;

  HeroParallax = function( args ) {
    this.$els = args.els || $(".js-bg-parallax");
    $(window).bind("scroll", $.proxy(this._onScroll, this));
  };

  HeroParallax.prototype._updateBg = function( i, el ) {
    var $el = $(el);
    if (isInViewport(el)) {
      var percent = 30 + ((($el.offset().top - _pageYOffset) * speed) / $el.height());
      $el.css("backgroundPosition", "center " + percent + "%");
    }
  };

  HeroParallax.prototype._update = function() {
    window.lp.supports.requestAnimationFrame($.proxy(this._update, this));
    $.each(this.$els, $.proxy(this._updateBg, this));
  };

  HeroParallax.prototype._startrAF = function() {
    if (!started){
      window.lp.supports.requestAnimationFrame($.proxy(this._update, this));
      started = true;
    }
  };

  HeroParallax.prototype._onScroll = function() {
    _pageYOffset = window.pageYOffset;
    this._startrAF();
  };

  if ( window.lp.supports.requestAnimationFrame ){
    els = $(".js-bg-parallax");
    if (els.length) {
      new HeroParallax({
        els: els
      });
    }
  }

  return HeroParallax;

});

Fix @csutter's sloppy code style


var content = jQuery('#content');
var grafs = content.text().split('\n\n');

var cx_date = new Date();
var monthNames = ["Jan. ","Feb. ","March ","April ","May ","June ","July ","Aug. ","Sept. ","Oct. ","Nov.","Dec. "];
var cx_month = monthNames[cx_date.getMonth()];
var amPm = ( cx_date.getHours() < 12 ) ? ' a.m.' : ' p.m.';
var cx_date_markup = cx_month +  cx_date.getDay() + ', ' + cx_date.getFullYear() + ' at ' + cx_date.getHours() + ':' + cx_date.getMinutes() + amPm;

var cx_content = prompt('Type or paste the correction language here. The Update date and time, "The following ... has been added:" and all other formatting will be included automatically.\n\n', '');

var markup = '
\n\n\
Updated ' + cx_date_markup + ' The following corrected information has been added to this article: ' + cx_content + '\n\n\

';

grafs.splice(grafs.length, 0, markup);

jQuery('#content').text(grafs.join('\n\n'));

var content = jQuery('#content');
var grafs = content.text().split('\n\n');

var cx_date = new Date();
var monthNames = ["Jan. ","Feb. ","March ","April ","May ","June ","July ","Aug. ","Sept. ","Oct. ","Nov.","Dec. "];
var cx_month = monthNames[cx_date.getMonth()];
var amPm = ( cx_date.getHours() < 12 ) ? ' a.m.' : ' p.m.';
var cx_date_markup = cx_month +  cx_date.getDay() + ', ' + cx_date.getFullYear() + ' at ' + cx_date.getHours() + ':' + cx_date.getMinutes() + amPm;

var cx_content = prompt('Type or paste the correction language here. The Update date and time and all other formatting will be included automatically.\n\n', '');

var markup = '
\n\n\
Updated ' + cx_date_markup + ' ' + cx_content + '\n\n\

';

grafs.splice(grafs.length, 0, markup);

jQuery('#content').text(grafs.join('\n\n'));

Tweak to CX bookmarklet per Dan Petty.


chrome.storage.local.get(null, function(items) {
  var aliases = items.aliases
  var aliasKey = items.aliasKey
  $('body').on('keydown', 'input, textarea', function(e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if(code == aliasKey) {
      var input = $(this).val().split(" ");
      for(var i = 0; i < input.length; i++) {
        if(replaceInput(input[i])) {
          e.preventDefault();
          input[i] = replaceInput(input[i])
        };
      };
      $(this).val(input.join(" "))
    };
  });

  function replaceInput(input) {
    if(input in aliases) {
      return aliases[input]
    } else {
      return false
    };
  };
});

chrome.storage.local.get(null, function(items) {
  var aliases = items.aliases
  var aliasKey = items.aliasKey
  $('body').on('keydown', 'input, textarea', function(e) {
    var code = (e.keyCode ? e.keyCode : e.which);
    if(code == aliasKey) {
      var input = $(this).val().split(" ");
      for(var i = 0; i < input.length; i++) {
        if(replaceInput(input[i])) {
          e.preventDefault();
          input[i] = replaceInput(input[i])
        };
      };
      this.value = input.join(" ");
      var event = new Event('input', {bubbles: true});
      this.dispatchEvent(event);
    };
  });

  function replaceInput(input) {
    if(input in aliases) {
      return aliases[input]
    } else {
      return false
    };
  };
});

Add fix for reactjs shadowdom


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

var helpers = require('org.chromium.common.helpers');

var uiWindowFirstCallError = null;

exports.createUiWindow = function(callback) {
  if (uiWindowFirstCallError) {
    throw new Error('createUiWindow called multiple times. first from: ' + uiWindowFirstCallError);
  }
  uiWindowFirstCallError = new Error();

  if (!helpers.isChromeApp) {
    console.log('This is not running in a Chrome App, do not create the window');
    return;
  }

  chrome.app.window.create('index.html', {
    id: 'tests'
  }, function(appWindow) {
    if (callback) {
      callback(appWindow);
    }
  });
};

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

var helpers = require('cordova-plugin-chrome-apps-common.helpers');

var uiWindowFirstCallError = null;

exports.createUiWindow = function(callback) {
  if (uiWindowFirstCallError) {
    throw new Error('createUiWindow called multiple times. first from: ' + uiWindowFirstCallError);
  }
  uiWindowFirstCallError = new Error();

  if (!helpers.isChromeApp) {
    console.log('This is not running in a Chrome App, do not create the window');
    return;
  }

  chrome.app.window.create('index.html', {
    id: 'tests'
  }, function(appWindow) {
    if (callback) {
      callback(appWindow);
    }
  });
};

Update JS dependency requires to use NPM plugin ids


  // support CommonJS, AMD & browser
  /* istanbul ignore next */
  if (typeof exports === T_OBJECT)
    module.exports = riot
  else if (typeof define === 'function' && define.amd)
    define(function() { return (window.riot = riot) })
  else
    window.riot = riot

})(typeof window != 'undefined' ? window : void 0);

  // support CommonJS, AMD & browser
  /* istanbul ignore next */
  if (typeof exports === T_OBJECT)
    module.exports = riot
  else if (typeof define === T_FUNCTION && typeof define.amd !== T_UNDEF)
    define(function() { return (window.riot = riot) })
  else
    window.riot = riot

})(typeof window != 'undefined' ? window : void 0);

Remove UglifyJs warnings from webpack production shortcut (-p)


/*

    build.js

    Accepts:  config  - object, the config data
              files   - object, the files object generated in schema.js

    Creates a set of HTML files based on the json schemas and template
    files within the files object

*/

var fs  = require('fs');

module.exports = function (config, files) {

  // Import the template language
  var template = require(config.template.lib);

  // Pre compile the template
  // var compiled = template.compile(files.templates.contents[0], {
  //   filename: config.template.path
  // });

  // Pre compile the template(s)
  var compiled = {};

  files.templates.contents.forEach(function () {

  });

  // If the target folder doesn't exist already, create one.
  if (!fs.existsSync(config.target)) {

    fs.mkdirSync(config.target);

  }

  // For each schema that has been have loaded
  files.schemas.contents.forEach(function (file, key) {

    // Generate a html file name from the schema name.
    var htmlName = files.schemas.fileNames[key].split(/\./)[0] + config.suffix;

    // Create a file with the generated name and populate by passing the
    // schema contents through the previously compiled template.
    fs.writeFileSync(config.target + htmlName, compiled(file));

  });

};

/*

    build.js

    Accepts:  config  - object, the config data
              files   - object, the files object generated in schema.js

    Creates a set of HTML files based on the json schemas and template
    files within the files object

*/

var fs  = require('fs');

module.exports = function (config, files) {

  // Import the template language
  var template = require(config.template.lib);

  // Pre compile the template
  // var compiled = template.compile(files.templates.contents[0], {
  //   filename: config.template.path
  // });

  // Pre compile the template(s)
  var compiled = {};

  files.templates.contents.forEach(function (file, key) {
    // Create an object key from the file name
    var fileName = files.templates.fileNames[key].split(/\./)[0];

    // Pre-compile the template against that key
    compiled[fileName] = template.compile(file, {
      filename: config.template.path
    });

  });

  // If the target folder doesn't exist already, create one.
  if (!fs.existsSync(config.target)) {

    fs.mkdirSync(config.target);

  }

  // For each schema that has been have loaded
  files.schemas.contents.forEach(function (file, key) {

    // Generate a html file name from the schema name.
    var htmlName = files.schemas.fileNames[key].split(/\./)[0];

    var fileContent = '';

    if (compiled[htmlName]) {
      fileContent = compiled[htmlName](file);
    } else {
      fileContent = compiled[config.template.file](file);
    }

    // Create a file with the generated name and populate by passing the
    // schema contents through the previously compiled template.
    fs.writeFileSync(config.target + htmlName +  config.suffix, fileContent);

  });

};

Build from multiple mapped templates


//
// Main entry point.
//

require.config( {
    paths: {
        'jquery'                : "jquery-1.7.1.min",
        'jquery-ui'             : "jquery-ui-1.8.16.custom.min",
        'jquery-temporaryClass' : "jquery.temporaryClass",
        'mustache'              : "require-mustache"
    },
    shim: {
        'jquery' : {
            exports: "jQuery",
        },
        'jquery-ui' : {
            exports: "jQuery.ui",
            deps: ["jquery"],
        },
        'jquery-temporaryClass' : {
            exports: "jQuery.fn.temporaryClass",
            deps: ["jquery"]
        }
    }
} );

// Require Argumenta
require( ["argumenta"], function( undefined ) {

    // Argumenta is loaded & the app is running...

} );

//
// Main entry point.
//

require.config( {
    paths: {
        'jquery'                : "jquery-1.7.1.min",
        'jquery-ui'             : "jquery-ui-1.8.16.custom.min",
        'jquery-temporaryClass' : "jquery.temporaryClass",
        'mustache'              : "require-mustache"
    },
    shim: {
        'jquery' : {
            exports: "jQuery"
        },
        'jquery-ui' : {
            exports: "jQuery.ui",
            deps: ["jquery"]
        },
        'jquery-temporaryClass' : {
            exports: "jQuery.fn.temporaryClass",
            deps: ["jquery"]
        }
    }
} );

// Require Argumenta
require( ["argumenta"], function( undefined ) {

    // Argumenta is loaded & the app is running...

} );

Remove extraneous commas for IE


module.exports = {
    extends: 'eslint:recommended',
    env: {
        node: true,
        es6: true
    },
    rules: {
        'indent': ['error', 4],
        'quote-props': ['error', 'as-needed'],
        'no-cond-assign': 0,
        'no-console': 0,
        'no-control-regex': 0,
        'no-undef': 0,
        'no-unused-vars': 0
    }
}

module.exports = {
    extends: 'eslint:recommended',
    env: {
        node: true,
        es6: true
    },
    rules: {
        'indent': ['error', 4],
        'quote-props': ['error', 'as-needed'],
        'no-cond-assign': 0,
        'no-console': 0,
        'no-control-regex': 0,
        'no-undef': 0,
        'no-unused-vars': 0,
        'semi': ['error', 'never']
    }
}

Update eslint config to disallow semicolons


export default function getEmployee(request, reply) {
  const { employeeID } = request.params;
  request.server.methods.db.getEmployee(employeeID, (error, employee) => {
    if (error) reply(error).code(500);
    return reply(employee).code(200);
  });
}

import Boom from 'boom';

export default function getEmployee(request, reply) {
  const { employeeID } = request.params;
  request.server.methods.db.getEmployee(employeeID, (error, employee) => {
    if (error) {
      return reply(Boom.notFound(`No staff member found for user ID "${employeeID}"`));
    }
    return reply(employee).code(200);
  });
}

Correct reply() error and add neater Boom error handler if employee not found


// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';
import { connect } from '@folio/stripes-connect'; // eslint-disable-line
import RenderPermissions from '../lib/RenderPermissions';

class PermissionSet extends React.Component {

  static propTypes = {
    data: PropTypes.shape({
      availablePermissions: PropTypes.arrayOf(PropTypes.object),
    }).isRequired,
    addPermission: PropTypes.func.isRequired,
    removePermission: PropTypes.func.isRequired,
    availablePermissions: PropTypes.func.isRequired,
    selectedSet: PropTypes.object.isRequired,
  };

  static manifest = Object.freeze({
    availablePermissions: {
      type: 'okapi',
      records: 'permissions',
      path: 'perms/permissions?length=1000&query=(mutable=false)',
    },
  });

  render() {
    return (<RenderPermissions
      {...this.props}
      heading="Contains"
      addPermission={this.props.addPermission}
      removePermission={this.props.removePermission}
      availablePermissions={this.props.data.availablePermissions}
      listedPermissions={this.props.selectedSet.subPermissions}
    />);
  }
}

export default connect(PermissionSet, '@folio/users');

// We have to remove node_modules/react to avoid having multiple copies loaded.
// eslint-disable-next-line import/no-unresolved
import React, { PropTypes } from 'react';
import { connect } from '@folio/stripes-connect'; // eslint-disable-line
import RenderPermissions from '../lib/RenderPermissions';

class PermissionSet extends React.Component {

  static propTypes = {
    data: PropTypes.shape({
      availablePermissions: PropTypes.arrayOf(PropTypes.object),
    }).isRequired,
    addPermission: PropTypes.func.isRequired,
    removePermission: PropTypes.func.isRequired,
    selectedSet: PropTypes.object.isRequired,
  };

  static manifest = Object.freeze({
    availablePermissions: {
      type: 'okapi',
      records: 'permissions',
      path: 'perms/permissions?length=1000&query=(mutable=false)',
    },
  });

  render() {
    return (<RenderPermissions
      {...this.props}
      heading="Contains"
      addPermission={this.props.addPermission}
      removePermission={this.props.removePermission}
      availablePermissions={this.props.data.availablePermissions}
      listedPermissions={this.props.selectedSet.subPermissions}
    />);
  }
}

export default connect(PermissionSet, '@folio/users');

Remove extraneous prop declaration for availablePermissions


var connections = {};

// Listen to messages sent from the DevTools page
chrome.runtime.onConnect.addListener(function (port) {

  function extensionListener(message) {
    if (message.name == 'init') {
      connections[message.tabId] = port;
      connections[message.tabId].postMessage({
        payload: store.liftedStore.getState(),
        source: 'redux-page'
      });
    }
  }

  port.onMessage.addListener(extensionListener);

  port.onDisconnect.addListener(function (port) {
    port.onMessage.removeListener(extensionListener);

    Object.keys(connections).forEach(function (id) {
      if (connections[id] == port) {
        delete connections[id];
      }
    })
  })
});

// Receive message from content script and relay to the devTools page
chrome.runtime.onMessage.addListener(function (request, sender) {
  store.liftedStore.setState(request.payload);
  if (sender.tab) {
    var tabId = sender.tab.id;
    if (store.tabId !== tabId) {
      store.tabId = tabId;
      chrome.pageAction.show(tabId);
    }
    if (tabId in connections) {
      connections[ tabId ].postMessage(request);
    }
  }
  return true;
});

export function toContentScript(action) {
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(store.tabId, {action: action}, function(response) {});
  });
}

var connections = {};

// Listen to messages sent from the DevTools page
chrome.runtime.onConnect.addListener(function (port) {

  function extensionListener(message) {
    if (message.name == 'init') {
      connections[message.tabId] = port;
      connections[message.tabId].postMessage({
        payload: store.liftedStore.getState(),
        source: 'redux-page'
      });
    }
  }

  port.onMessage.addListener(extensionListener);

  port.onDisconnect.addListener(function (port) {
    port.onMessage.removeListener(extensionListener);

    Object.keys(connections).forEach(function (id) {
      if (connections[id] == port) {
        delete connections[id];
      }
    })
  })
});

// Receive message from content script and relay to the devTools page
chrome.runtime.onMessage.addListener(function (request, sender) {
  store.liftedStore.setState(request.payload);
  if (sender.tab) {
    var tabId = sender.tab.id;
    store.tabId = tabId;
    chrome.pageAction.show(tabId);
    if (tabId in connections) {
      connections[ tabId ].postMessage(request);
    }
  }
  return true;
});

export function toContentScript(action) {
  chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
    chrome.tabs.sendMessage(store.tabId, {action: action}, function(response) {});
  });
}

Fix the issue with losing pageAction after tab reload


var Sequelize = require('sequelize'),
    _ = require('lodash');

module.exports = function(target) {
  if (target instanceof Sequelize.Model) {
    // Model
    createHook(target);
  } else {
    // Sequelize instance
    target.afterDefine(createHook);
  }
}

function createHook(model) {
   model.hook('beforeFindAfterOptions', function(options) {
    if (options.role) {
      var role = options.role,
          attributes = options.attributes,
          includes = options.include;

      options.attributes = attrAccessible(model, role, attributes);
      cleanIncludesRecursive(includes, role);
    }
  });
}

function attrAccessible(model, role, attributes) {
  var attrsToReject = attrProtected(model, role);
  return rejectAttributes(attributes, attrsToReject);
}

function attrProtected(model, role) {
  return _.keys(_.pickBy(model.attributes, function(attr, name) {
    return !_.isUndefined(attr.access) && ( attr.access === false || attr.access[role] === false );
  }));
}

function rejectAttributes(attributes, attrsToRemove) {
  return _.reject(attributes, function(attr) {
    if (_.isArray(attr)) {
      attr = attr[1];
    }

    return _.includes(attrsToRemove, attr);
  });
}

function cleanIncludesRecursive(includes, role) {
  _.each(includes, function(include) {
    var model = include.model,
        attributes = include.attributes;

    include.attributes = attrAccessible(model, role, attributes);

    if (include.include) {
      cleanIncludesRecursive(include.include, role);
    }
  });
}

var Sequelize = require('sequelize'),
    _ = require('lodash');

module.exports = function(target) {
  if (target instanceof Sequelize.Model) {
    // Model
    createHook(target);
  } else {
    // Sequelize instance
    target.afterDefine(createHook);
  }
}

function createHook(model) {
   model.addHook('beforeFindAfterOptions', function(options) {
    if (options.role) {
      var role = options.role,
          attributes = options.attributes,
          includes = options.include;

      options.attributes = attrAccessible(model, role, attributes);
      cleanIncludesRecursive(includes, role);
    }
  });
}

function attrAccessible(model, role, attributes) {
  var attrsToReject = attrProtected(model, role);
  return rejectAttributes(attributes, attrsToReject);
}

function attrProtected(model, role) {
  return _.keys(_.pickBy(model.attributes, function(attr, name) {
    return !_.isUndefined(attr.access) && ( attr.access === false || attr.access[role] === false );
  }));
}

function rejectAttributes(attributes, attrsToRemove) {
  return _.reject(attributes, function(attr) {
    if (_.isArray(attr)) {
      attr = attr[1];
    }

    return _.includes(attrsToRemove, attr);
  });
}

function cleanIncludesRecursive(includes, role) {
  _.each(includes, function(include) {
    var model = include.model,
        attributes = include.attributes;

    include.attributes = attrAccessible(model, role, attributes);

    if (include.include) {
      cleanIncludesRecursive(include.include, role);
    }
  });
}

Replace usage of deprecated hook method


var Options = require('./options');
var Metafile = require('./metafile');

module.exports = metafiles;

// Not needed in Node 4.0+
if (!Object.assign) Object.assign = require('object-assign');

/**
 * Metalsmith plugin to read file metadata from separate files
 *
 * @param {Object} options
 * @param {boolean} [options.deleteMetaFiles=true] - Whether to delete metadata files from the built site
 * @return {Function}
 */

function metafiles(options) {
  options = new Options(options);

  return function(files, metalsmith) {
    for (var path in files) {
      var metafile = new Metafile(path, files[path], options);

      if (!metafile.isMetafile) continue;
      if (!files[metafile.mainFile]) continue;

      Object.assign(files[metafile.mainFile], metafile.metadata);
      if (options.deleteMetaFiles) delete files[metafile.path];
    }
  };
}

var Options = require('./options');
var Metafile = require('./metafile');

module.exports = metafiles;

// Not needed in Node 4.0+
if (!Object.assign) Object.assign = require('object-assign');

/**
 * Metalsmith plugin to read file metadata from separate files
 *
 * @param {Object} options
 * @param {String} [options.postfix=".metadata"] - The postfix added to filenames to indicate they are metadata files
 * @param {String} [options.prefix=""] - The prefix added to filenames to indicate they are metadata files
 * @param {boolean} [options.deleteMetaFiles=true] - Whether to delete metadata files from the built site
 * @return {Function}
 */

function metafiles(options) {
  options = new Options(options);

  return function(files, metalsmith) {
    for (var path in files) {
      var metafile = new Metafile(path, files[path], options);

      if (!metafile.isMetafile) continue;
      if (!files[metafile.mainFile]) continue;

      Object.assign(files[metafile.mainFile], metafile.metadata);
      if (options.deleteMetaFiles) delete files[metafile.path];
    }
  };
}

Update inline docs for the main function


'use strict';

module.exports = require('dbjs').Boolean.create('YesNo', {
	trueString: 'Yes',
	falseString: 'No'
});

'use strict';

module.exports = require('dbjs').Boolean.create('YesNo', {
	trueLabel: 'Yes',
	falseLabel: 'No'
});

Update up to changes in dbjs


console.log(html`<b>${process.argv[2]} says</b>: "${process.argv[3]}"`);

function html (strs, ...args) {
  let p1 = strs[0],
      p2 = args[0],
      p3 = strs[1],
      p4 = args[1],
      p5 = strs[2];

  return `${p1}${entities(p2)}${p3}${entities(p4)}${p5}`;
}

function entities(str) {
  return str.replace(/&/g, '&')
            .replace(/>/g, '>')
            .replace(/</g, '&lt')
            .replace(/"/g, '"')
            .replace(/'/g, ''');
}

Add last exercise of 'count-to-6'


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

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

Add category mapping for "festmøte"


import { bind } from 'decko';
import React from 'react';
import { findDOMNode } from 'react-dom';

/**
 * A modal dialog window.
 */
class Dialog extends React.Component {
  componentDidMount () {
    this.elDialog = findDOMNode(this.refs.dialog);

    document.body.addEventListener('keydown', this.onEsc);
  }

  componentWillUnmount () {
    document.body.removeEventListener('keydown', this.onEsc);
  }

  @bind
  onEsc (e) {
    e = e || window.event;
    if (e.keyCode == 27) {
      this.props.onClose();
    }
  }

  @bind
  onOverlayClick (e) {
    // Close (i.e. cancel) the dialog if the outer overlay is clicked
    if (!this.elDialog.contains(e.target)) {
      var exit = confirm("Are you sure you want to exit the editor" +
        "and lose all progress on your current CRC card?");
      if (exit == true) {
        this.props.onClose();
      }
    }
  }

  render () {
    return (

{this.props.title}

          {this.props.children}

    );
  }
}

export default Dialog;

import { bind } from 'decko';
import React from 'react';
import { findDOMNode } from 'react-dom';

/**
 * A modal dialog window.
 */
class Dialog extends React.Component {
  componentDidMount () {
    this.elDialog = findDOMNode(this.refs.dialog);

    document.body.addEventListener('keydown', this.onEsc);
  }

  componentWillUnmount () {
    document.body.removeEventListener('keydown', this.onEsc);
  }

  @bind
  onEsc (e) {
    e = e || window.event;
    if (e.keyCode == 27) {
      this.props.onClose();
    }
  }

  @bind
  onOverlayClick (e) {
    // Close (i.e. cancel) the dialog if the outer overlay is clicked
    if (!this.elDialog.contains(e.target) &&
      confirm("Are you sure you want to exit the editor " +
        "and lose all progress on your current CRC card?")) {
        this.props.onClose();
    }
  }

  render () {
    return (

{this.props.title}

          {this.props.children}

    );
  }
}

export default Dialog;

Move confirm call directly in the if statement


import React from 'react';
import ReactDOM from 'react-dom';
// import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import { ApolloClient, ApolloProvider, createNetworkInterface } from 'react-apollo';
import { BrowserRouter as Router } from 'react-router-dom'

import App from './App';
import './index.css';

const client = new ApolloClient({
  networkInterface: createNetworkInterface({
    uri: 'http://localhost:9000/graphql'
  }),
  dataIdFromObject: o => o.id,
});

// const store = createStore(
//   combineReducers({
//     apollo: client.reducer()
//   }),
//   {},
//   compose(
//     applyMiddleware(client.middleware()),
//       // If you are using the devToolsExtension, you can add it here also
//       (typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined')
//         ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
//   )
// );

ReactDOM.render(
  <ApolloProvider client={client}>
    <Router>
      <App />
    </Router>
  </ApolloProvider>,
  document.getElementById('root')
);

import React from 'react';
import ReactDOM from 'react-dom';
// import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import { ApolloClient, ApolloProvider, createNetworkInterface } from 'react-apollo';
import { BrowserRouter as Router } from 'react-router-dom'

import App from './App';
import './index.css';

const client = new ApolloClient({
  networkInterface: createNetworkInterface({
    uri: 'http://localhost:9000/graphql'
  }),
  // dataIdFromObject: o => o.id,
});

// const store = createStore(
//   combineReducers({
//     apollo: client.reducer()
//   }),
//   {},
//   compose(
//     applyMiddleware(client.middleware()),
//       // If you are using the devToolsExtension, you can add it here also
//       (typeof window.__REDUX_DEVTOOLS_EXTENSION__ !== 'undefined')
//         ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
//   )
// );

ReactDOM.render(
  <ApolloProvider client={client}>
    <Router>
      <App />
    </Router>
  </ApolloProvider>,
  document.getElementById('root')
);

Comment out for presentation reasons


/*
 * See https://github.com/jhen0409/react-native-debugger/issues/209
 *
 * Patch whatwg-fetch code to get `support` var,
 * so we could use it to fix the issue.
 */
const isFetch = /"node_modules\/@?[a-zA-Z-_/]*whatwg-fetch\/fetch.js"/;

const fetchSupportFlag = /(if \(self.fetch\) {\n\s+return;\n\s+}\n\s+var support )(=)( {)/g;
const fetchSupportReplaceStr = '$1= self.__FETCH_SUPPORT__ =$3';

const toggleFlag = 'if (support.arrayBuffer) {';
// Toggle Network Inspect after define `support` var.
// We have been set up `__NETWORK_INSPECT__` in Worker before import application script.
const toggleReplaceStr = `self.__NETWORK_INSPECT__ && self.__NETWORK_INSPECT__(true);${toggleFlag}`;

export const checkFetchExists = code => isFetch.test(code);
export const patchFetchPolyfill = code =>
  code.replace(fetchSupportFlag, fetchSupportReplaceStr).replace(toggleFlag, toggleReplaceStr);

/*
 * See https://github.com/jhen0409/react-native-debugger/issues/209
 *
 * Patch whatwg-fetch code to get `support` var,
 * so we could use it to fix the issue.
 */
const isFetch = /"node_modules\/@?[a-zA-Z-_/]*whatwg-fetch\/fetch.js"/;

const fetchSupportFlag = /(if \(self.fetch\) {\n\s+return;\n\s+}\n\s+var support )(=)( {)/g;
const fetchSupportReplaceStr = '$1= self.__FETCH_SUPPORT__ =$3';

const toggleFlag = 'self.fetch.polyfill = true';
// Toggle Network Inspect after define `support` var.
// We have been set up `__NETWORK_INSPECT__` in Worker before import application script.
const toggleReplaceStr = `self.__NETWORK_INSPECT__ && self.__NETWORK_INSPECT__(true);${toggleFlag}`;

export const checkFetchExists = code => isFetch.test(code);
export const patchFetchPolyfill = code =>
  code.replace(fetchSupportFlag, fetchSupportReplaceStr).replace(toggleFlag, toggleReplaceStr);

Fix error of blob function not found in whatwg-fetch with Network Inspect enabled


webvowl.nodes.externalclass = (function () {

	var o = function () {
		webvowl.nodes.RoundNode.call(this);

		this.styleClass("external")
			.textAttribute("white")
			.type("ExternalClass");
	};
	o.prototype = Object.create(webvowl.nodes.RoundNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

webvowl.nodes.externalclass = (function () {

	var o = function () {
		webvowl.nodes.RoundNode.call(this);

		this.indication("external")
			.styleClass("external")
			.textAttribute("white")
			.type("ExternalClass");
	};
	o.prototype = Object.create(webvowl.nodes.RoundNode.prototype);
	o.prototype.constructor = o;

	return o;
}());

Fix representation of External Classes