#! /usr/bin/env node
'use strict';

var findup = require('findup-sync');
var fs     = require('fs');
var shell  = require('child_process').execFile;

// Only check the value once
var baseDirectory = process.env.HOME;

var baseFile   = baseDirectory + '/.npmrc';
var baseBackup = baseDirectory + '/.npmrc.bak';
var nearestFile;

function isAlreadyInUse(path) {
    if (path && path !== baseFile) {
        return true;
    }
}

function getPath() {
    var npmrcPath = findup('.npmrc');

    if (isAlreadyInUse(npmrcPath)) {
        return npmrcPath;
    }

    return null;
}

function renameFile(currentFileName, newFileName) {
    if (fs.existsSync(currentFileName)) {
        fs.renameSync(currentFileName, newFileName);

        if (fs.existsSync(currentFileName)) {
            throw new Error('Could not rename file');
        }
    }
}

function copySourceToDestination(source, destination) {
    shell('/bin/cp', [source, destination]);
}

function returnToBackedUpFile() {
    renameFile(baseBackup, baseFile);
}

function backupFileCurrentlyInUse() {
    renameFile(baseFile, baseBackup);
}

nearestFile = getPath();
if (nearestFile) {
    backupFileCurrentlyInUse();
    copySourceToDestination(nearestFile, baseFile);
} else {
    returnToBackedUpFile();
}

#! /usr/bin/env node
'use strict';

var findup = require('findup-sync');
var fs     = require('fs');
var shell  = require('child_process').execFile;

// Only check the value once
var baseDirectory = process.env.HOME;

var baseFile   = baseDirectory + '/.npmrc';
var defaultFile = baseDirectory + '/.npmrc.default';
var nearestFile;

function isAlreadyInUse(path) {
    if (path && path !== baseFile) {
        return true;
    }
}

function getPath() {
    var npmrcPath = findup('.npmrc');

    if (isAlreadyInUse(npmrcPath)) {
        return npmrcPath;
    }

    return null;
}

function renameFile(currentFileName, newFileName) {
    if (fs.existsSync(currentFileName)) {
        fs.renameSync(currentFileName, newFileName);

        if (fs.existsSync(currentFileName)) {
            throw new Error('Could not rename file');
        }
    }
}

function copySourceToDestination(source, destination) {
    shell('/bin/cp', [source, destination]);
}

function defaultExists() {
    return fs.existsSync(defaultFile);
}

function returnToDefaultFile() {
    if (fs.existsSync(baseFile)) {
        fs.unlinkSync(baseFile);
    }

    if (defaultExists) {
        renameFile(defaultFile, baseFile);
    }
}

nearestFile = getPath();
if (nearestFile) {
    copySourceToDestination(nearestFile, baseFile);
} else {
    returnToDefaultFile();
}

Use a default file if it exists, otherwise fallback to nom's default


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

/**
 * Escapes URI components in a template string as a tag function.
 *
 * @since n.e.x.t
 *
 * @param {string[]} strings The array of static strings in the template.
 * @param {...*} values The array of expressions used in the template.
 * @return {string} Escaped URI string.
 */
export function escapeURI( strings, ...values ) {
	return strings.reduce( ( acc, string, idx ) => {
		return acc + string + encodeURIComponent( values[ idx ] || '' );
	}, '' );
}

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

/**
 * Escapes URI components in a template string as a tag function.
 *
 * @example
 * // escape redirect url
 * const redirectTo = 'http://localhost/admin/';
 * const loginUrl = escapeURI`http://localhost/login?redirect=${ redirectTo }`;
 *
 * @since n.e.x.t
 *
 * @param {string[]} strings The array of static strings in the template.
 * @param {...*} values The array of expressions used in the template.
 * @return {string} Escaped URI string.
 */
export function escapeURI( strings, ...values ) {
	return strings.reduce( ( acc, string, idx ) => {
		return acc + string + encodeURIComponent( values[ idx ] || '' );
	}, '' );
}

Add example to escapeURI function.


'use babel'

/* @flow */

import {Template} from 'string-templates'

export const CONFIG_FILE_NAME: string = '.ucompiler'
export const STATE_FILE_NAME: string = '.ucompiler.state'

export const DEFAULT_IGNORED: Array<string> = [
  'node_modules',
  'bower_components',
  'coverage',
  't{e,}mp',
  '*.min.js',
  '*.log',
  'bundle.js',
  'fixture{-*,}.{js,jsx}',
  'spec',
  'test{s, }',
  'fixture{s, }',
  'vendor',
  'dist',
  '*___jb_old___',
  '*___jb_bak___',
  '*.dist.*'
]

export const template = Template.create()

'use babel'

/* @flow */

import {Template} from 'string-templates'

export const CONFIG_FILE_NAME: string = '.ucompiler'
export const STATE_FILE_NAME: string = '.ucompiler.state'

export const DEFAULT_IGNORED: Array<string> = [
  'node_modules',
  'bower_components',
  'coverage',
  't{e,}mp',
  '*.min.js',
  '*.log',
  'bundle.js',
  'fixture{-*,}.{js,jsx}',
  'spec',
  'test{s, }',
  'fixture{s, }',
  'vendor',
  'dist',
  '*___jb_old___',
  '*___jb_bak___',
  '*.dist.*'
]

export const template:{
  render: ((template: string, parameters: Object) => string),
} = Template.create()

Add type to default template


import express from 'express';
import validate from 'express-validation';
import paramValidation from './validation/user';
import userCtrl from '../controllers/user';

const router = express.Router();  // eslint-disable-line new-cap

router.route('/')

  .post(validate(paramValidation.createUser), userCtrl.createUser);

router.route('/:userId')

  .get(validate(paramValidation.byId), userCtrl.getUser)

  .put(validate(paramValidation.updateUser), userCtrl.updateUser)

  .delete(validate(paramValidation.byId), userCtrl.deleteUser);

router.route('/:userId/device')

  .post(validate(paramValidation.addDevice), userCtrl.addDevice);

router.route('/:userId/device/:deviceId')

  .get(validate(paramValidation.deviceById), userCtrl.getDevice)

  .put(validate(paramValidation.updateDevice), userCtrl.updateDevice)

  .post(validate(paramValidation.deviceById), userCtrl.sortDevices)

  .delete(validate(paramValidation.deviceById), userCtrl.removeDevice);

router.route('/:userId/group')

  .get(validate(paramValidation.byId), userCtrl.getGroupsForUser);

/** Load user when API with userId route parameter is hit */
router.param('userId', userCtrl.loadUser);

export default router;

Remove unnecessary spaces for readability


Use ensureDir instead of mkdir


import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './reducers';

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import './styles/index.css';

const devTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

const store = createStore(rootReducer, devTools)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk'
import rootReducer from './reducers';

import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import './styles/index.css';

const devTools = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

const middleware = [thunk];
const store = createStore(
  rootReducer,
  devTools,
  applyMiddleware(...middleware),)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);

Add thunk to redux store


'use strict';

import './polyfills/Array.find';
import 'whatwg-fetch';

import Vue from 'vue';
import VueRouter from 'vue-router';

import DefaultRouter from './routers/DefaultRouter';
import Store from './stores/Store';
import App from './components/App';

// Inject additional package dependencies
Vue.use(VueRouter);

// Main app instance
new Vue({
  router: DefaultRouter,

  store: Store,

  template: '<App/>',

  components: {
    App
  },

  // Global options for VueResource
  http: {
    root: '',
    headers: {
      //
    }
  }
}).$mount('#app');

'use strict';

import './polyfills/Array.find';
import 'whatwg-fetch';

import Vue from 'vue';
import VueRouter from 'vue-router';

import DefaultRouter from './routers/DefaultRouter';
import Store from './stores/Store';
import App from './components/App';

// Inject additional package dependencies
Vue.use(VueRouter);

// Main app instance
new Vue({
  router: DefaultRouter,

  store: Store,

  template: '<App/>',

  components: {
    App
  }
}).$mount('#app');

Remove vue-resource global options from app init


'use strict';

const electron = require('electron');
const { app, BrowserWindow } = electron;

let mainWindow; // Ensures garbage collection does not remove the window

app.on('ready', () => {
  // Creates the application window with specified dimension
  mainWindow = new BrowserWindow({
    height: 750,
    width: 750
  });

  // Loads index.html in as the main application page
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  mainWindow.on('closed', () => {
    mainWindow = null; // allow window to be garbage collected
  });
});

'use strict';

const electron = require('electron');
const { app, BrowserWindow } = electron;

let mainWindow; // Ensures garbage collection does not remove the window

app.on('ready', () => {
  // Creates the application window and sets its dimensions to fill the screen
  const { width, height } = electron.screen.getPrimaryDisplay().workAreaSize;
  mainWindow = new BrowserWindow({
    width,
    height
  });

  // Loads index.html in as the main application page
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  mainWindow.on('closed', () => {
    mainWindow = null; // allow window to be garbage collected
  });
});

Update application dimensions to fill the screen


'use strict';

var setupTestHooks     = require('ember-cli-blueprint-test-helpers/lib/helpers/setup');
var BlueprintHelpers   = require('ember-cli-blueprint-test-helpers/lib/helpers/blueprint-helper');
var generateAndDestroy = BlueprintHelpers.generateAndDestroy;

describe('Acceptance: ember generate and destroy helper-addon', function() {
  setupTestHooks(this);

  it('in-addon helper-addon foo-bar', function() {
    return generateAndDestroy(['helper-addon', 'foo-bar'], {
      target: 'addon',
      files: [
        {
          file: 'app/helpers/foo-bar.js',
          contains: [
            "export { default, fooBar } from 'my-addon/helpers/foo-bar';"
          ]
        },
      ]
    });
  });

});

'use strict';

var blueprintHelpers = require('ember-cli-blueprint-test-helpers/helpers');
var setupTestHooks = blueprintHelpers.setupTestHooks;
var emberNew = blueprintHelpers.emberNew;
var emberGenerateDestroy = blueprintHelpers.emberGenerateDestroy;

var chai = require('ember-cli-blueprint-test-helpers/chai');
var expect = chai.expect;

describe('Acceptance: ember generate and destroy helper-addon', function() {
  setupTestHooks(this);

  it('in-addon helper-addon foo-bar', function() {
    var args = ['helper-addon', 'foo-bar'];

    return emberNew({ target: 'addon' })
      .then(() => emberGenerateDestroy(args, _file => {
        expect(_file('app/helpers/foo-bar.js'))
          .to.contain("export { default, fooBar } from 'my-addon/helpers/foo-bar';");
      }));
  });
});

Use alternative blueprint test helpers


/* ---------------------------------------
	Game launcher
--------------------------------------- */

	var MM =
	{
		// Overridden when resizing
		isMobile: true,

		resize: function()
		{
			MM.isMobile = ($(window).width() < 465)? true : false;
		},

		resizeDelay: function()
		{
			if (MM.resizeTimer)
			{
				clearTimeout(MM.resizeTimer);
			}

			MM.resizeTimer = setTimeout(MM.resize, 500);
		},

		init: function()
		{
			// Update isMobile
			$(window).resize(MM.resizeDelay);
			MM.resize();
		}
	};

	// Typekit fonts
	CRD.typekit.init({ kitId: 'vpq4ijb' });

	// Init MM helper
	MM.init();

/* ---------------------------------------
	Game launcher
--------------------------------------- */

	var MM =
	{
		// Overridden when resizing
		isMobile: true,

		resize: function()
		{
			MM.isMobile = ($(window).width() < 465)? true : false;
		},

		resizeDelay: function()
		{
			if (MM.resizeTimer)
			{
				clearTimeout(MM.resizeTimer);
			}

			MM.resizeTimer = setTimeout(MM.resize, 500);
		},

		init: function()
		{
			// Update isMobile
			$(window).resize(MM.resizeDelay);
			MM.resize();
		}
	};

	// Typekit fonts
	CRD.typekit.init({ kitId: 'hjz0ljw' });

	// Init MM helper
	MM.init();

Create new Typekit kit for fonts


export const extractWithRegex = regex => (url) => {
  const match = url.match(regex);
  return match.length > 1 ? match[1] : '';
};

export const extractWithRegex = regex => (url) => {
  const match = url.match(regex);
  return match && match.length > 1 ? match[1] : '';
};

Check if match exists FIRST


var activeMentors = function () {
  this.endpoint = "/api/mentor_requests/available";
  this.template;
};

activeMentors.prototype.getMentors = function () {
  var self = this;
  $.ajax({
    method: "get",
    url: self.endpoint
  }).done( function(response) {
    self.updateView(response)
  });
};

activeMentors.prototype.updateView = function (data) {
  if (data.length > 0) {
    var html = this.template(data);
    $('#active-mentor-list').html(html)
  } else {
    $('#active-mentor-list').text("There doesn't appear to be any mentors on duty currently.")
  }
};

activeMentors.prototype.setup = function () {
  this.template = Handlebars.compile($("#mentor-template").html());
  this.getMentors();
  this.poll();
};

activeMentors.prototype.poll = function () {
  var self = this
  setTimeout(function(){
    self.getMentors();
    self.poll();
  }, 120000);
};

var mentorList = new activeMentors()

$(document).ready(function() {
  if ( $('#active-mentor-list').length == 1 ) {
    mentorList.setup();
  }
});

var activeMentors = function () {
  this.endpoint = "/api/mentor_requests/available";
  this.template;
};

activeMentors.prototype.getMentors = function () {
  var self = this;
  $.ajax({
    method: "get",
    url: self.endpoint
  }).done( function(response) {
    self.updateView(response)
  });
};

activeMentors.prototype.updateView = function (data) {
  if (data.length > 0) {
    var html = this.template(data);
    $('#active-mentor-list').html(html)
  } else {
    $('#active-mentor-list').text("There doesn't appear to be any mentors on duty currently.")
  }
};

activeMentors.prototype.setup = function () {
  this.template = Handlebars.compile($("#mentor-template").html());
  this.getMentors();
  this.poll();
};

activeMentors.prototype.poll = function () {
  var self = this
  setTimeout(function(){
    self.getMentors();
    self.poll();
  }, 60000);
};

var mentorList = new activeMentors()

$(document).ready(function() {
  if ( $('#active-mentor-list').length == 1 ) {
    mentorList.setup();
  }
});

Change active mentor polling to one minute


import {Experiment, ExperimentStep} from './experiment.model';

angular.module('materialscommons').component('mcExperiment', {
    templateUrl: 'app/project/experiments/experiment/mc-experiment.html',
    controller: MCExperimentComponentController
});

/*@ngInject*/
function MCExperimentComponentController($scope, moveStep) {
    let ctrl = this;
    ctrl.currentStep = null;
    ctrl.currentNode = null;
    ctrl.showSidebar = true;

    // Create the initial hard coded experiment
    ctrl.experiment = new Experiment('test experiment');
    let s = new ExperimentStep('', '');
    s.id = "simple0";
    ctrl.experiment.steps.push(s);
    ctrl.currentStep = s;

    ctrl.moveLeft = () => moveStep.left(ctrl.currentNode, ctrl.currentStep, ctrl.experiment);
    ctrl.moveRight = () => moveStep.right(ctrl.currentNode, ctrl.currentStep);
    ctrl.moveUp = () => moveStep.up(ctrl.currentNode, ctrl.currentStep);
    ctrl.moveDown = () => moveStep.down(ctrl.currentNode, ctrl.currentStep, ctrl.experiment);
    ctrl.expandAll = () => $scope.$broadcast('angular-ui-tree:expand-all');
    ctrl.collapseAll = () => $scope.$broadcast('angular-ui-tree:collapse-all');
    ctrl.showStepMaximized = () => ctrl.currentStep && ctrl.currentStep.displayState.maximize;
}

import {Experiment, ExperimentStep} from './experiment.model';

angular.module('materialscommons').component('mcExperiment', {
    templateUrl: 'app/project/experiments/experiment/mc-experiment.html',
    controller: MCExperimentComponentController
});

/*@ngInject*/
function MCExperimentComponentController($scope, moveStep) {
    let ctrl = this;
    ctrl.currentStep = null;
    ctrl.currentNode = null;
    ctrl.showSidebar = false;

    // Create the initial hard coded experiment
    ctrl.experiment = new Experiment('test experiment');
    let s = new ExperimentStep('', '');
    s.id = "simple0";
    ctrl.experiment.steps.push(s);
    ctrl.currentStep = s;

    ctrl.moveLeft = () => moveStep.left(ctrl.currentNode, ctrl.currentStep, ctrl.experiment);
    ctrl.moveRight = () => moveStep.right(ctrl.currentNode, ctrl.currentStep);
    ctrl.moveUp = () => moveStep.up(ctrl.currentNode, ctrl.currentStep);
    ctrl.moveDown = () => moveStep.down(ctrl.currentNode, ctrl.currentStep, ctrl.experiment);
    ctrl.expandAll = () => $scope.$broadcast('angular-ui-tree:expand-all');
    ctrl.collapseAll = () => $scope.$broadcast('angular-ui-tree:collapse-all');
    ctrl.showStepMaximized = () => ctrl.currentStep && ctrl.currentStep.displayState.maximize;
}

Hide the sidebar by default.


var cadence = require('cadence')
var Dispatcher = require('inlet/dispatcher')

function Static (addresses) {
    this._addresses = addresses
    var dispatcher = new Dispatcher({ object: this, workers: 256 })
    dispatcher.dispatch('GET /', 'index')
    dispatcher.dispatch('GET /discover', 'discover')
    dispatcher.dispatch('GET /health', 'health')
    this.dispatcher = dispatcher
}

Static.prototype.index = cadence(function () {
    return 'Mingle Static Discovery API'
})

Static.prototype.discover = cadence(function () {
    return [ this._addresses ]
})

Static.prototype.health = cadence(function () {
    return { http: this.dispatcher.turnstile.health }
})

module.exports = Static

var cadence = require('cadence')
var Dispatcher = require('inlet/dispatcher')

function Static (addresses) {
    this._addresses = addresses
    var dispatcher = new Dispatcher({ object: this, workers: 256 })
    dispatcher.dispatch('GET /', 'index')
    dispatcher.dispatch('GET /discover', 'discover')
    dispatcher.dispatch('GET /health', 'health')
    this.dispatcher = dispatcher
}

Static.prototype.index = cadence(function () {
    return 'Mingle Static Discovery API\n'
})

Static.prototype.discover = cadence(function () {
    return [ this._addresses ]
})

Static.prototype.health = cadence(function () {
    return { http: this.dispatcher.turnstile.health }
})

module.exports = Static

Add newline to plain text index.


'use strict';

angular.module('ddsCommon').factory('CustomizationService', function(lyonMetropoleInseeCodes) {

    function determineCustomizationId(testCase, currentPeriod) {
        if (testCase.menages &&
            testCase.menages._) {
            if (testCase.menages._.depcom[currentPeriod].match(/^93/))
                return 'D93-SSD';
            if (testCase.menages._.depcom[currentPeriod].match(/^75/))
                return 'D75-PARIS';
            if (testCase.menages._.depcom[currentPeriod].match(/^14/))
                return 'D14-CALVADOS';
            if (testCase.menages._.depcom[currentPeriod].match(/^59/))
                return 'D59-NORD';
            if (_.includes(lyonMetropoleInseeCodes, testCase.menages._.depcom[currentPeriod]))
                return 'M69-LYON';
        }

        return undefined;
    }

    return {
        determineCustomizationId: determineCustomizationId,
    };
});

'use strict';

angular.module('ddsCommon').factory('CustomizationService', function(lyonMetropoleInseeCodes) {

    function determineCustomizationId(testCase, currentPeriod) {
        if (testCase.menages &&
            testCase.menages._) {
            if (testCase.menages._.depcom[currentPeriod].match(/^93/))
                return 'D93-SSD';
            if (testCase.menages._.depcom[currentPeriod].match(/^75/))
                return 'D75-PARIS';
            if (testCase.menages._.depcom[currentPeriod].match(/^14/))
                return 'D14-CALVADOS';
            if (testCase.menages._.depcom[currentPeriod].match(/^59/))
                return 'D59-NORD';
            if (testCase.menages._.depcom[currentPeriod].match(/^13/))
                return 'D13-BDR';
            if (_.includes(lyonMetropoleInseeCodes, testCase.menages._.depcom[currentPeriod]))
                return 'M69-LYON';
        }
        return undefined;
    }
    return {
        determineCustomizationId: determineCustomizationId,
    };
});

Add customization for conseil departemental BDR


import fs from 'fs';
import path from 'path';
import schema from '../src/server/api/schema';
import { graphql }  from 'graphql';
import { introspectionQuery, printSchema } from 'graphql/utilities';

// Save JSON of full schema introspection for Babel Relay Plugin to use
(async () => {
    const result = await (graphql(schema, introspectionQuery));
    if (result.errors) {
        console.error(
            'ERROR introspecting schema: ',
            JSON.stringify(result.errors, null, 2)
        );
    } else {
        fs.writeFileSync(
            path.join(__dirname, '../src/server/api', 'schema.json'),
            JSON.stringify(result, null, 2)
        );
    }
})();

// Save user readable type system shorthand of schema
fs.writeFileSync(
    path.join(__dirname, '../src/server/api', 'schema.graphql'),
    printSchema(schema)
);

import fs from 'fs';
import path from 'path';
import schema from '../src/server/schema';
import { graphql }  from 'graphql';
import { introspectionQuery, printSchema } from 'graphql/utilities';

// Save JSON of full schema introspection for Babel Relay Plugin to use
(async () => {
    const result = await (graphql(schema, introspectionQuery));
    if (result.errors) {
        console.error(
            'ERROR introspecting schema: ',
            JSON.stringify(result.errors, null, 2)
        );
    } else {
        fs.writeFileSync(
            path.join(__dirname, '../src/server', 'schema.json'),
            JSON.stringify(result, null, 2)
        );
    }
})();

// Save user readable type system shorthand of schema
fs.writeFileSync(
    path.join(__dirname, '../src/server', 'schema.graphql'),
    printSchema(schema)
);

Add missing steps for building schema


refreshFrequency: false,

style: "border: 0",

render: function() {
	window.sto = window.sto || {
		libs: {},
		data: {},
	};

	var staff = [
		'Mike Sjulstad',
		'Phinehas Bynum',
		'Nhia Lee',
		'Jennie Moberg',
		'Michael Domingues',
		'Perrin Bishop-Wright',
		'Tony Skalski',
		'Ben Gottfried',
		'Roberta Lembke',
		'Kelly Kloos',
		'Wendy Woitalla',
		'Jeff Dixon',
		'Tim Isom',
		'Andy Prehall',
		'Michael Strand',
		'Myron Engle',
		'Craig Rice',
		'Bob Breid',
		'Nancy Aarsvold',
		'Doug Hamilton',
		'Jason Menard',
		'Dana Thompson',
		'Sean Tonko',
		'Dan Beach',
		'Marc Thomas',
	];
	window.sto.data.staff = staff;

	var colors = [
		'red',
		'orange',
		'yellow',
		'green',
		'blue',
		'purple',
		'pink',
		'aqua',
		'silver',
	]
	window.sto.data.colors = colors;

	return ''
}

refreshFrequency: false,

style: "border: 0",

render: function() {
	window.sto = window.sto || {
		libs: {},
		data: {},
	};

	var staff = [
		'Andy Prehall',
		'Ben Gottfried',
		'Bob Breid',
		'Craig Rice',
		'Dan Beach',
		'Dana Thompson',
		'Doug Hamilton',
		'Heather Malecha',
		'Jason Menard',
		'Jeff Dixon',
		'Jennie Moberg',
		'Kelly Kloos',
		'Marc Thomas',
		'Michael Domingues',
		'Michael Strand',
		'Mike Sjulstad',
		'Myron Engle',
		'Nancy Aarsvold',
		'Nhia Lee',
		'Perrin Bishop-Wright',
		'Phinehas Bynum',
		'Rich Graves',
		'Roberta Lembke',
		'Sean Tonko',
		'System',
		'Tim Isom',
		'Tony Skalski',
		'Wendy Woitalla',
	];
	window.sto.data.staff = staff;

	var colors = [
		'red',
		'orange',
		'yellow',
		'green',
		'blue',
		'purple',
		'pink',
		'aqua',
		'silver',
	]
	window.sto.data.colors = colors;

	return ''
}

Sort 'staff' by first name; add Heather to the list


(function () {
	'use strict';

	mare.views.SiteVisitorRegistration = Backbone.View.extend({
		el: '.site-visitor-registration',

		events: {
			'change .other-way-to-hear-about-mare': 'toggleOtherWayToHearTextField'
		},

		initialize: function() {
			// DOM cache any commonly used elements to improve performance
			this.$howDidYouHearOther = this.$('#site-visitor-how-did-you-hear-other');
		},

		toggleOtherWayToHearTextField: function toggleOtherWayToHearTextField() {
			this.$howDidYouHearOther.toggleClass('hidden');
		}

	});
})();

(function () {
	'use strict';

	mare.views.SiteVisitorRegistration = Backbone.View.extend({
		el: '.registration-form--site-visitor',

		events: {
			'change .other-way-to-hear-about-mare': 'toggleOtherWayToHearTextField'
		},

		initialize: function() {
			// DOM cache any commonly used elements to improve performance
			this.$howDidYouHearOther = this.$('#site-visitor-how-did-you-hear-other');
			// Initialize parsley validation on the form
			this.form = this.$el.parsley();
			this.form.on('field:validated', this.validateForm);
		},

		toggleOtherWayToHearTextField: function toggleOtherWayToHearTextField() {
			this.$howDidYouHearOther.toggleClass('hidden');
		},

		validateForm: function validateForm() {
			var ok = $('.parsley-error').length === 0;
			$('.bs-callout-info').toggleClass('hidden', !ok);
			$('.bs-callout-warning').toggleClass('hidden', ok);

			// need to add a check to show site-visitor-how-did-you-hear-error if no checkboxes are checked
		}

	});
})();

Add form validation to the site user view using Parsley.


var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://0.0.0.0:8545'));

//TODO: when TestRPC can handle synchronous requests, use this
//var TestRPC = require("ethereumjs-testrpc");
//web3.setProvider(TestRPC.provider());

var LiveLibs = require('../index.js');
var liveLibs = new LiveLibs(web3, 'testrpc');

liveLibs.deploy().then(function() {

  describe('Retrieving lib info', function() {
    it('foo', function() {
      var libName = 'foo';
      var libInfo = liveLibs.get(libName);
    });
  });

  run(); // this is exposed because we're running mocha --delay
  // we are runnning mocha --delay because we have to deploy before we run tests
  // we have to deploy because TestRPC can't handle synchronous requests
}).catch(function(err) {
  console.error('Problem while deploying to testrpc: ' + err);
});

var Web3 = require('web3');
var web3 = new Web3();
web3.setProvider(new web3.providers.HttpProvider('http://0.0.0.0:8545'));

//TODO: when TestRPC can handle synchronous requests, use this
//var TestRPC = require("ethereumjs-testrpc");
//web3.setProvider(TestRPC.provider());

var LiveLibs = require('../index.js');
var liveLibs = new LiveLibs(web3, 'testrpc');

var deploy;

try {
  deploy = liveLibs.deploy()
} catch(e) {
  console.error('Error while setting up deploy: '+e);
  console.error('Make sure you have testrpc running!')
  process.exit(1);
}

deploy.then(function() {

  describe('Retrieving lib info', function() {
    it('foo', function() {
      var libName = 'foo';
      var libInfo = liveLibs.get(libName);
    });
  });

  run(); // this is exposed because we're running mocha --delay
  // we are runnning mocha --delay because we have to deploy before we run tests
  // we have to deploy because TestRPC can't handle synchronous requests
}).catch(function(err) {
  console.error('Problem while deploying to testrpc: ' + err);
});

Test should handle case where testrpc isn't running


Package.describe({
  name: 'lookback:tooltips',
  summary: 'Reactive tooltips.',
  version: '0.3.1',
  git: 'https://github.com/lookback/meteor-tooltips.git'
});

Package.on_use(function(api) {
  api.versionsFrom('METEOR@0.9.3');
  api.use('coffeescript reactive-var jquery templating tracker'.split(' '), 'client');

  api.add_files('tooltips.html tooltips.coffee'.split(' '), 'client');
  api.export('Tooltips', 'client');
});

Package.describe({
  name: 'lookback:tooltips',
  summary: 'Reactive tooltips.',
  version: '0.3.1',
  git: 'https://github.com/lookback/meteor-tooltips.git'
});

Package.on_use(function(api) {
  api.versionsFrom('1.0.4');
  api.use('coffeescript reactive-var jquery templating tracker'.split(' '), 'client');

  api.add_files('tooltips.html tooltips.coffee'.split(' '), 'client');
  api.export('Tooltips', 'client');
});

Update Meteor release to 1.0.4


Package.describe({
  name: 'konecty:user-presence',
  summary: 'Track user status',
  version: '1.1.0',
  git: 'https://github.com/Konecty/meteor-user-presence'
});

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

  api.use('nooitaf:colors@0.0.2');

  api.addFiles('server/server.js', ['server']);
  api.addFiles('server/monitor.js', ['server']);
  api.addFiles('client/client.js', ['client']);
  api.addFiles('common/common.js');

  api.export(['UserPresence'], ['server', 'client']);
  api.export(['UserPresenceMonitor'], ['server']);
});

Package.onTest(function(api) {
  api.use('tinytest');
  api.use('konecty:user-presence');
  api.addFiles('konecty:user-presence-tests.js');
});

Package.describe({
  name: 'konecty:user-presence',
  summary: 'Track user status',
  version: '1.1.0',
  git: 'https://github.com/Konecty/meteor-user-presence'
});

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

  api.use('nooitaf:colors@0.0.2');

  api.addFiles('common/common.js');
  api.addFiles('server/server.js', ['server']);
  api.addFiles('server/monitor.js', ['server']);
  api.addFiles('client/client.js', ['client']);

  api.export(['UserPresence'], ['server', 'client']);
  api.export(['UserPresenceMonitor'], ['server']);
});

Package.onTest(function(api) {
  api.use('tinytest');
  api.use('konecty:user-presence');
  api.addFiles('konecty:user-presence-tests.js');
});

Move api common.js file to top of list


if (document.URL.indexOf("search")>=0) {
    hide_table_actions();
}

function hide_table_actions(){

   var table = document.querySelector( '.results');
   var cellIndex = table.rows[0].cells.length - 1;  // index for last column
   var num_columns = table.rows[0].cells.length;
   for (i = 0; i<table.rows.length; i++){
        table.rows[i].cells[cellIndex % num_columns].style.display = 'none';
    }

}

if (document.URL.indexOf("search")>=0 || document.URL.indexOf("member")>=0) {
    hide_table_actions();
}

function hide_table_actions(){

   var table = document.querySelector( '.results');
   var cellIndex = table.rows[0].cells.length - 1;  // index for last column
   var num_columns = table.rows[0].cells.length;
   for (i = 0; i<table.rows.length; i++){
        table.rows[i].cells[cellIndex % num_columns].style.display = 'none';
    }

}

Fix hide actions on member page


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",
    "WEBJOBS_PATH",
    "WEBJOBS_NAME",
    "WEBJOBS_TYPE",
    "WEBJOBS_DATA_PATH",
    "WEBJOBS_RUN_ID",
    "WEBJOBS_SHUTDOWN_FILE"
]

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

    context.log('Environment Variables');
    environmentVariables
        .map(getEnvironmentVarible)
        .forEach(function (x) {
            context.log(x);
        });

    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];
}

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

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",
    "HOME",
    "SYSTEMDRIVE",
    "WEBJOBS_PATH",
    "WEBJOBS_NAME",
    "WEBJOBS_TYPE",
    "WEBJOBS_DATA_PATH",
    "WEBJOBS_RUN_ID",
    "WEBJOBS_SHUTDOWN_FILE",
    "WEBSITE_NODE_DEFAULT_VERSION",
    "WEBSITE_NPM_DEFAULT_VERSION"
]

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

    context.log('Environment Variables');
    environmentVariables
        .map(getEnvironmentVarible)
        .forEach(function (x) {
            context.log(x);
        });

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

    var tempDir = process.env["TMP"];
    var filePath = path.join(tmpDir, 'message.txt');
    var fileContents = 'Hellow Node.js_' + req.body;

    context.log("writing: ", fileContents);

    fs.writeFile(filePath, fileContents, (err) => {
        if (err) {
            throw err;
        }

        context.log("File is saved!");
        context.done();
    });
}

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

Add few more environment variables to test, and use them to construct filepaths for more robustness


import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Select from 'react-select';
import * as actions from '../actions/characterCreationActions';

class App extends Component {
  defaultArchetypes = ['Architect', 'Bravo'];  // TODO

  handleChange = (val) => {
    this.props.actions.updateArchetype(val.value);
  }

  render() {
    const character = this.props.character;

    // TODO: Bug if create new item
    const options = this.defaultArchetypes.map(a => ({value: a, label: a}));

    return (
      <div>
        Embracer
        <Select.Creatable value={character.archetype} multi={false} options={options} onChange={this.handleChange} />
      </div>
    );
  }
}

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

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators(actions, dispatch)
});

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

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import Select from 'react-select';
import * as actions from '../actions/characterCreationActions';

class App extends Component {
  defaultArchetypes = ['Architect', 'Bravo'];  // TODO

  handleChange = (val) => {
    this.props.actions.updateArchetype(val.value);
  }

  render() {
    const character = this.props.character;

    let options = this.defaultArchetypes.map(a => ({value: a, label: a}));

    if (character.archetype && this.defaultArchetypes.indexOf(character.archetype) === -1) {
      options.push({value: character.archetype, label: character.archetype});
    }

    return (
      <div>
        Embracer
        <Select.Creatable value={character.archetype} multi={false} options={options} onChange={this.handleChange} />
      </div>
    );
  }
}

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

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators(actions, dispatch)
});

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

Fix bug when creating new archetype


#!/usr/bin/env node

/**
 * Module dependencies.
 */

const debug = require('debug')('docsmith:start');
const program = require('commander');
const start = require('./docsmith/start');
const config = require('./docsmith/utils/settings').config;

let workspace;

program
  .arguments('[workspace]')
  .option('-s, --source [path]', '[migrate] Source folder path]')
  .option('--baseurl [baseurl]', 'Set site.baseurl metadata value.')
  .option('-w, --watch', 'Watch content folder and serve on local server.')
  .option('-d, --debug', 'Enable /debug-ui url for debugging pipeline.')
  .option('-f, --force', 'Initialise whether the current directory is empty or not.')
  .option('-l, --link', 'For development purposes. Link local packages.')
  .action(function(wksp) {
    workspace = wksp;
  })
  .parse(process.argv);

const { link, source, baseurl, watch, debug: dbg } = program;

// check if we could resolve the config.
if (config) {
  debug('config', config);
  // called from a content as code instance, initialise from the instance configuration
  start.run({ workspace, config, link, source, watch, dbg, baseurl });
} else {
  console.warn('Could not find config. Aborting start. Please contact the developer');
}

#!/usr/bin/env node

/**
 * Module dependencies.
 */

const debug = require('debug')('docsmith:start');
const program = require('commander');
const start = require('./docsmith/start');
const config = require('./docsmith/utils/settings').config;

let workspace;

program
  .arguments('[workspace]')
  .option('-s, --source [path]', '[migrate] Source folder path]')
  .option('--baseurl [baseurl]', 'Set site.baseurl metadata value.')
  .option('-n, --no-watch', 'Do not watch content folder and serve on local server. Watches by default.')
  .option('-d, --debug', 'Enable /debug-ui url for debugging pipeline.')
  .option('-f, --force', 'Initialise whether the current directory is empty or not.')
  .option('-l, --link', 'For development purposes. Link local packages.')
  .action(function(wksp) {
    workspace = wksp;
  });

program.parse(process.argv);

const { link, source, baseurl, watch, debug: dbg } = program;

if (typeof workspace === 'undefined') workspace = 'toolkit';

// check if we could resolve the config.
if (config) {
  debug('config', config);
  // called from a content as code instance, initialise from the instance configuration
  start.run({ workspace, config, link, source, watch, dbg, baseurl });
} else {
  console.warn('Could not find config. Aborting start. Please contact the developer');
}

Make default start command watch toolkit


/* eslint-disable prefer-arrow-callback, func-names */
/* eslint-env mocha */
import { chai } from 'meteor/practicalmeteor:chai';
import { setup, breakdown } from './setup';

const { TemplateInstance } = Blaze;

describe('setup', function () {
  beforeEach(function () {
    breakdown();
  });

  it('should add functions to the TemplateInstance prototype', function () {
    setup();

    chai.expect(TemplateInstance.prototype.gqlQuery).to.be.ok;
    chai.expect(TemplateInstance.prototype.queriesReady).to.be.ok;
  });
});

/* eslint-disable prefer-arrow-callback, func-names */
/* eslint-env mocha */
import { chai } from 'meteor/practicalmeteor:chai';
import { setup, breakdown } from './setup';

const { TemplateInstance } = Blaze;

describe('setup', function () {
  beforeEach(function () {
    breakdown();
  });

  it('should add functions to the TemplateInstance prototype', function () {
    setup();

    chai.expect(TemplateInstance.prototype.gqlQuery).to.be.ok;
    chai.expect(TemplateInstance.prototype.gqlMutate).to.be.ok;
    chai.expect(TemplateInstance.prototype.gqlSubscribe).to.be.ok;
    chai.expect(TemplateInstance.prototype.queriesReady).to.be.ok;
  });
});

Make sure gql functions are availabel


module.exports = {
    "parserOptions": {
        "ecmaVersion": 8
    },
    "env": {
        "browser": false,
        "node": true,
        "commonjs": true,
        "es6": true,
        "mocha": true
    },
    "extends": "eslint:recommended",
    "rules": {
        "no-console": 0,
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ],
        "max-len": [
            "error",
            120
        ]
    }
};

module.exports = {
    "parserOptions": {
        "ecmaVersion": 8
    },
    "env": {
        "browser": false,
        "node": true,
        "commonjs": true,
        "es6": true,
        "mocha": true
    },
    "extends": "eslint:recommended",
    "rules": {
        "no-console": 0,
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ],
        "space-before-function-paren": [
            "error",
            {"anonymous": "always", "named": "never"}
        ],
        "max-len": [
            "error",
            120
        ]
    }
};

Add ESLint rule for space-before-function-paren


// !! Defines a parser and serializer for
// [CommonMark](http://commonmark.org/) text (registered in the
// [`format`](#format) module under `"markdown"`).

;({defaultMarkdownParser: exports.defaultMarkdownParser, MarkdownParser: exports.MarkdownParser} = require("./from_markdown"))
;({MakdownSerializer: exports.MakdownSerializer, defaultMarkdownSerializer: exports.defaultMarkdownSerializer, MarkdownSerializerState: exports.MarkdownSerializerState} = require("./to_markdown"))

// !! Defines a parser and serializer for
// [CommonMark](http://commonmark.org/) text (registered in the
// [`format`](#format) module under `"markdown"`).

;({defaultMarkdownParser: exports.defaultMarkdownParser, MarkdownParser: exports.MarkdownParser} = require("./from_markdown"))
;({MarkdownSerializer: exports.MarkdownSerializer, defaultMarkdownSerializer: exports.defaultMarkdownSerializer,
   MarkdownSerializerState: exports.MarkdownSerializerState} = require("./to_markdown"))

Fix typo in exports of markdown module


$(function() {
    var usernameEl = $('#username');
    var passwordEl = $('#password');

    // in a real application, hardcoding the user/password would be idiotic
    // but for the demo application it's very convenient to do so
    if (!usernameEl.val() || 'jane_admin' === usernameEl.val()) {
        usernameEl.val('jane_admin');
        passwordEl.val('kitten');
    }
});

$(function() {
    var usernameEl = $('#username');
    var passwordEl = $('#password');

    // in a real application, the user/password should never be hardcoded
    // but for the demo application it's very convenient to do so
    if (!usernameEl.val() || 'jane_admin' === usernameEl.val()) {
        usernameEl.val('jane_admin');
        passwordEl.val('kitten');
    }
});

Use a more friendly message about hardcoding user details


import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';

const withTheme = theme => WrappedComponent => {
  class WithTheme extends PureComponent {
    render() {
      const { color, size, tint, className, ...others } = this.props;

      const classNames = cx(theme[`is-${color}`], theme[`is-${size}`], theme[`is-${tint}`], className);

      return <WrappedComponent className={classNames} {...others} />;
    }
  }

  WithTheme.propTypes = {
    /** The color of the component */
    color: PropTypes.PropTypes.oneOf(['aqua', 'gold', 'mint', 'neutral', 'ruby', 'teal', 'violet']),
    /** The size of the component */
    size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'fullscreen']),
    /** The tint of the component */
    tint: PropTypes.oneOf(['lightest', 'light', 'normal', 'dark', 'darkest']),
  };

  WithTheme.defaultProps = {
    color: 'neutral',
    size: 'medium',
    tint: 'normal',
  };

  WithTheme.displayName = `WithTheme(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;

  return WithTheme;
};

export default withTheme;

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import { COLORS, TINTS } from '../../../constants';

const withTheme = theme => WrappedComponent => {
  class WithTheme extends PureComponent {
    render() {
      const { color, size, tint, className, ...others } = this.props;

      const classNames = cx(theme[`is-${color}`], theme[`is-${size}`], theme[`is-${tint}`], className);

      return <WrappedComponent className={classNames} {...others} />;
    }
  }

  WithTheme.propTypes = {
    /** The color of the component */
    color: PropTypes.PropTypes.oneOf(COLORS),
    /** The size of the component */
    size: PropTypes.oneOf(['tiny', 'small', 'medium', 'large', 'fullscreen']),
    /** The tint of the component */
    tint: PropTypes.oneOf(TINTS),
  };

  WithTheme.defaultProps = {
    color: 'neutral',
    size: 'medium',
    tint: 'normal',
  };

  WithTheme.displayName = `WithTheme(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;

  return WithTheme;
};

export default withTheme;

Use the COLOR and TINTS constants


import { document } from 'global';
import qs from 'qs';
import ClientApi, { defaultDecorateStory } from './client_api';
import StoryStore, { splitPath } from './story_store';
import ConfigApi from './config_api';
import subscriptionsStore from './subscriptions_store';
import pathToId from './pathToId';

export {
  ClientApi,
  StoryStore,
  ConfigApi,
  subscriptionsStore,
  defaultDecorateStory,
  pathToId,
  splitPath,
};

export const getQueryParams = () => {
  return qs.parse(document.location.search, { ignoreQueryPrefix: true });
};

export const getQueryParam = key => {
  const params = getQueryParams();
  return params[key];
};

ADD api for reading queryParams in client-api


// Profile Model
module.exports = function(sequelize, DataTypes) {
  var Profile = sequelize.define('Profile', {
    rate: {
      type: DataTypes.DECIMAL(10,2),
      allowNull: false
    },
    tagLine: {
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT,
      allowNull: false
    },
  }, {
    associate: function(models) {
      Profile.hasMany(models.ProfileItem);
      Profile.hasMany(models.ProfileVote);
    },
    instanceMethods: {
      getSimple: function() {
        var obj = {};

        obj.tagLine = this.tagLine;
        obj.description = this.description;
        obj.profileItems = [];

        this.profileItems.forEach(function(profileItem) {
          obj.profileItems.push(profileItem.getSimple());
        });

        return obj;
      }
    }
  });

  return Profile;
}

// Profile Model
module.exports = function(sequelize, DataTypes) {
  var Profile = sequelize.define('Profile', {
    rate: {
      type: DataTypes.DECIMAL(10,2),
      allowNull: false
    },
    tagLine: {
      type: DataTypes.STRING,
      allowNull: false
    },
    description: {
      type: DataTypes.TEXT,
      allowNull: false
    },
  }, {
    associate: function(models) {
      Profile.hasMany(models.ProfileItem);
      Profile.hasMany(models.ProfileVote);
    },
    instanceMethods: {
      getSimple: function() {
        var obj = {};

        obj.rate = this.rate;
        obj.tagLine = this.tagLine;
        obj.description = this.description;
        obj.profileItems = [];

        this.profileItems.forEach(function(profileItem) {
          obj.profileItems.push(profileItem.getSimple());
        });

        return obj;
      }
    }
  });

  return Profile;
}

Add rate to JSON object for Profile


var remote = require('remote')
var fs = require('fs')
var path = require('path')
var app = remote.require('app')

var filename = path.join(app.getPath('userData'), 'settings.json')
var settings = JSON.decode(fs.readFileSync(filename, { encoding: 'utf8' }))

exports.get = function(key) {
    return settings[key]
}

exports.set = function(key, value) {
    settings[key] = value
    fs.writeFileSync(filename, JSON.encode(settings))
}

var remote = require('remote')
var fs = require('fs')
var path = require('path')
var app = remote.require('app')

var filename = path.join(app.getPath('userData'), 'settings.json')
var settings = JSON.decode(fs.readFileSync(filename, { encoding: 'utf8' }))

exports.get = function(key) {
    if (key in settings) return settings[key]
    else return null
}

exports.set = function(key, value) {
    settings[key] = value
    fs.writeFileSync(filename, JSON.encode(settings))
}

Return null if key doesn't exist


/* eslint-disable no-undef */
const FastBootAppServer = require('fastboot-app-server');
const fetch = require('node-fetch');

let server = new FastBootAppServer({
  distPath: 'dist',
  gzip: true, // Optional - Enables gzip compression.
  host: '0.0.0.0', // Optional - Sets the host the server listens on.
  port: 4000, // Optional - Sets the port the server listens on (defaults to the PORT env var or 3000).
  buildSandboxGlobals(defaultGlobals) {
    // Optional - Make values available to the Ember app running in the FastBoot server, e.g. "MY_GLOBAL" will be available as "GLOBAL_VALUE"
    return Object.assign({}, defaultGlobals, {
      btoa: function (str) {
        return Buffer.from(str).toString('base64');
      },
      fetch,
    });
  },
  chunkedResponse: true, // Optional - Opt-in to chunked transfer encoding, transferring the head, body and potential shoeboxes in separate chunks. Chunked transfer encoding should have a positive effect in particular when the app transfers a lot of data in the shoebox.
});

server.start();

/* eslint-disable no-undef */
const FastBootAppServer = require('fastboot-app-server');
const fetch = require('node-fetch');

let server = new FastBootAppServer({
  distPath: 'dist',
  gzip: true, // Optional - Enables gzip compression.
  host: '0.0.0.0', // Optional - Sets the host the server listens on.
  port: 4000, // Optional - Sets the port the server listens on (defaults to the PORT env var or 3000).
  buildSandboxGlobals(defaultGlobals) {
    // Optional - Make values available to the Ember app running in the FastBoot server, e.g. "MY_GLOBAL" will be available as "GLOBAL_VALUE"
    return Object.assign({}, defaultGlobals, {
      btoa: function (str) {
        return Buffer.from(str).toString('base64');
      },
      fetch,
    });
  },
  // This should be false for Twitter/Linkedin according to https://github.com/ember-fastboot/ember-cli-fastboot/tree/master/packages/fastboot-app-server#twitter-and-linkedin
  chunkedResponse: false, // Optional - Opt-in to chunked transfer encoding, transferring the head, body and potential shoeboxes in separate chunks. Chunked transfer encoding should have a positive effect in particular when the app transfers a lot of data in the shoebox.
});

server.start();

Update to turn off chunking


module.exports = function(app) {
  var express = require('express');
  var bodyParser = require('body-parser');
  var jwt = require('jsonwebtoken');
  var apiTokenAuthRouter = express.Router();

  apiTokenAuthRouter.post('/', function(req, res) {
    var token = jwt.sign(req.body, 'secret', {expiresInSeconds: 10});
    res.send({
      token: token
    });
  });

  app.use(bodyParser.json());
  app.use('/api/token-auth', apiTokenAuthRouter);
};

module.exports = function(app) {
  var express = require('express');
  var bodyParser = require('body-parser');
  var jwt = require('jsonwebtoken');
  var apiTokenAuthRouter = express.Router();

  apiTokenAuthRouter.post('/', function(req, res) {
    jwt.sign(req.body, 'secret', { expiresIn: 10 }, function(token) {
      res.send({
        token: token
      });
    });
  });

  app.use(bodyParser.json());
  app.use('/api/token-auth', apiTokenAuthRouter);
};

Use expiresIn instead of expiresInSeconds


var angular = require('angular');

angular.module('LoginComp', ['AuthSvc']).component('loginComponent', {
    templateUrl: '/views/shimapan/login-form.html',
    controller: ['$scope', '$timeout', 'AuthService', function ($scope, $timeout, AuthService) {
        $scope.login = function () {
            AuthService.login({
                username: $scope.username,
                password: $scope.password
            }).catch(function(err) {
                $scope.error = true;
                $timeout(function() {
                    $scope.error = false;
                },820);
            });
        };
    }]
});

var angular = require('angular');

angular.module('LoginComp', ['AuthSvc']).component('loginComponent', {
    templateUrl: '/views/shimapan/login-form.html',
    controller: ['$scope', '$timeout', 'AuthService', function ($scope, $timeout, AuthService) {
        $scope.login = function () {
            AuthService.login({
                username: $scope.username,
                password: $scope.password
            }).catch(function() {
                $scope.error = true;
                $timeout(function() {
                    $scope.error = false;
                },820);
            });
        };
    }]
});

Remove unneeded error parameter for login form


import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import MenuItem from 'material-ui/MenuItem';
import { isSidebarOpen } from '../../reducers';
import toggleSidebar from '../../actions/sidebar-action';

class Sidebar extends Component {
  redirect(path) {
    this.props.history.push(path);
  }

  render() {
    return (
      <Drawer
        docked={false}
        open={this.props.isOpen}
      >
        <AppBar
          title="Caravanas"
          iconClassNameRight="muidocs-icon-navigation-expand-more"
          onLeftIconButtonTouchTap={this.props.toggleSidebar}
        />
        <MenuItem onClick={() => this.redirect('/')}>
          Caravanas
        </MenuItem>
        <MenuItem onClick={() => this.redirect('/companies')}>
          Companies
        </MenuItem>
      </Drawer>
    );
  }
}

function mapStateToProps(state) {
  return {
    isOpen: isSidebarOpen(state),
  };
}

Sidebar.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired,
  }).isRequired,
};

export default withRouter(connect(
  mapStateToProps,
  {
    toggleSidebar,
  }
)(Sidebar));

import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Drawer from 'material-ui/Drawer';
import AppBar from 'material-ui/AppBar';
import MenuItem from 'material-ui/MenuItem';
import { isSidebarOpen } from '../../reducers';
import toggleSidebar from '../../actions/sidebar-action';

class Sidebar extends Component {
  redirect(path) {
    this.props.history.push(path);
  }

  render() {
    return (
      <Drawer
        docked={false}
        open={this.props.isOpen}
      >
        <AppBar
          title="Menu"
          iconClassNameRight="muidocs-icon-navigation-expand-more"
          onLeftIconButtonTouchTap={this.props.toggleSidebar}
        />
        <MenuItem onClick={() => this.redirect('/')}>
          Caravanas
        </MenuItem>
        <MenuItem onClick={() => this.redirect('/companies')}>
          Companies
        </MenuItem>
      </Drawer>
    );
  }
}

function mapStateToProps(state) {
  return {
    isOpen: isSidebarOpen(state),
  };
}

Sidebar.propTypes = {
  history: PropTypes.shape({
    push: PropTypes.func.isRequired,
  }).isRequired,
};

export default withRouter(connect(
  mapStateToProps,
  {
    toggleSidebar,
  }
)(Sidebar));

Update sidebar logic and UI


'use strict';

angular.module('privateTheaterApp')
  .controller('MediaErrorsPublisherCtrl', ['$scope', '$modal', 'MediaError', function ($scope, $modal, MediaError) {

    $scope.openReportModal = function(){
      if(!$scope.media){
        return;
      }
      $scope.error = new MediaError();
      $scope.error.media = $scope.media._id;
      $modal.open({
        templateUrl: 'views/movie/report-modal.html',
        controller: ReportModalInstanceCtrl,
        resolve: {
          error: function(){
            return $scope.error;
          }
        }
      });
    };

    //Rerpot Modal Instance
    var ReportModalInstanceCtrl = ['$scope','$modalInstance', 'error', function($scope, $modalInstance, error){
      $scope.predefs = [
        'Audio is poor or missing',
        'Incorrect quality',
        'Image freezes continuously',
        'Incorrect language',
        'Captions do not show up',
        'Captions are not in correct language',
        'Captions are not properly synced'
      ];
      $scope.error = error;
      $scope.ok = function(){
        $scope.error.$save(function(error){
          if(error){
            $modalInstance.close();
          }else {
            console.err('Error! Media report was not sent');
          }
        }, function(){
          console.error('Error! Media report was not sent');
        });
      };
      $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
      };
    }];
  }]);

'use strict';

angular.module('privateTheaterApp')
  .controller('MediaErrorsPublisherCtrl', ['$scope', '$modal', 'MediaError', function ($scope, $modal, MediaError) {

    $scope.openReportModal = function(){
      if(!$scope.media){
        return;
      }
      $scope.error = new MediaError();
      $scope.error.media = $scope.media._id;
      $modal.open({
        templateUrl: 'views/movie/report-modal.html',
        controller: ReportModalInstanceCtrl,
        resolve: {
          error: function(){
            return $scope.error;
          }
        }
      });
    };

    //Rerpot Modal Instance
    var ReportModalInstanceCtrl = ['$scope', '$rootScope','$modalInstance', 'error', 'MediaError', function($scope, $rootScope, $modalInstance, error, MediaError){
      $scope.predefs = [
        'Audio is poor or missing',
        'Incorrect quality',
        'Image freezes continuously',
        'Incorrect language',
        'Captions do not show up',
        'Captions are not in correct language',
        'Captions are not properly synced'
      ];
      $scope.error = error;
      $scope.ok = function(){
        $scope.error.$save(function(report){
          if(report){
            $modalInstance.close();
            $rootScope.reports = MediaError.query();
          }else {
            console.err('Error! Media report was not sent');
          }
        }, function(){
          console.error('Error! Media report was not sent');
        });
      };
      $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
      };
    }];
  }]);

Refresh reports in rootScope when a new report is pushed


'use strict';

/* Modules */
var imageSets = require('cloud/imagesets.js').ImageSets;

/**
 * Responds with the next image set.
 * @param request.params.id The current image set id.
 */
Parse.Cloud.define('getNextImageSet', function(request, response) {
    var id = parseInt(request.params.id, 10);
    var nextId = isNaN(id) ? 0 : (id + 1) % imageSets.length;
    var imageSet = imageSets[nextId];
    response.success(imageSet);
});

'use strict';

/* Modules */
var imageSets = require('cloud/imagesets.js').ImageSets;

/**
 * Responds with the next image set.
 * @param request.params.id The current image set id.
 */
Parse.Cloud.define('getNextImageSet', function(request, response) {
    var id = parseInt(request.params.id, 10);
    var nextId = (isNaN(id) || id < 0 || id >= imageSets.length) ? 0 : (id + 1) % imageSets.length;
    var imageSet = imageSets[nextId];
    response.success(imageSet);
});

Handle invalid image set ids in api code


'use strict';

/* Filters */

angular.module('myApp.filters', []).
  filter('interpolate', ['version', function(version) {
    return function(text) {
      return String(text).replace(/\%VERSION\%/mg, version);
    }
  }])
  .filter('mapUrl', function() {
      return function(e) {
          var str = "";
          for (var i=0;i<e.length;i++) {
              str += typeof e[i].name === 'undefined' ||
                e[i].name.localeCompare('') === 0  ?
                e[i].latitude + ',' + e[i].longitude + '%7C' :
                e[i].name + '%7C';
          }
          return str;
      };
  });

'use strict';

/* Filters */

angular.module('myApp.filters', []).
  filter('interpolate', ['version', function(version) {
    return function(text) {
      return String(text).replace(/\%VERSION\%/mg, version);
    }
  }])
  .filter('mapUrl', function() {
      return function(e) {
          var str = "";
          for (var i=0;i<e.length;i++) {
              str += typeof e[i].name === 'undefined' ||
                e[i].name.localeCompare('') === 0  ?
                e[i].latitude + ',' + e[i].longitude + '%7C' :
                e[i].name + '%7C';
          }
          str = str.replace(/ /g, '%20C');
          console.log(str);
          return str.replace(/%7C$/, '');
      };
  });

Improve mapUrl filter. Replace whitespace with %20C.


var orm = require('orm');
var async = require('async');
var dbConfig = require('../config/database');

module.exports.run = function(done) {
    orm.connect(dbConfig, function(err, db) {
        var cinema = require('../models/cinema')(db);
        var movie  = require('../models/movie')(db);

        async.series([
            // Truncate tables
            cinema.clear,
            movie.clear,

            // Seed data
            async.apply(cinema.create, require('./cinemas').cinemas),
            async.apply(movie.create, require('./movies').movies),

        ], function(err) {
            if (err) console.error(err);
            db.close(done);
        });
    });
};

var orm = require('orm');
var async = require('async');
var dbConfig = require('../config/database');

var truncate = function(db, table, done) {
    async.series([
        async.apply(db.driver.db.query.bind(db.driver.db), 'SET FOREIGN_KEY_CHECKS = 0'),
        async.apply(db.driver.db.query.bind(db.driver.db), 'TRUNCATE TABLE ' + db.driver.query.escape(table)),
        async.apply(db.driver.db.query.bind(db.driver.db), 'SET FOREIGN_KEY_CHECKS = 1'),
    ], done);
};

module.exports.run = function(done) {
    orm.connect(dbConfig, function(err, db) {
        var cinema = require('../models/cinema')(db);
        var movie  = require('../models/movie')(db);

        async.series([
            // Truncate tables
            async.apply(truncate, db, 'cinemas'),
            async.apply(truncate, db, 'movies'),

            // Seed data
            async.apply(cinema.create, require('./cinemas').cinemas),
            async.apply(movie.create, require('./movies').movies),

        ], function(err) {
            if (err) console.error(err);
            db.close(done);
        });
    });
};

Truncate tables when there are foreign key constraints


"use strict";

let user = {
  name: "Sam",
  totalReplies: 17,
  isBlocked: false
};

user[Symbol.iterator] = function () {
  let properties = Object.keys(this);
  let count = 0;
  let isDone = false;

  let next = () => {
    if (count >= properties.lenght) {
      isDone = true;
    }

    let value = this[properties[count++]];

    return;
  };

  return { next };
};

"use strict";

let user = {
  name: "Sam",
  totalReplies: 17,
  isBlocked: false
};

user[Symbol.iterator] = function () {
  let properties = Object.keys(this);
  let count = 0;
  let isDone = false;

  let next = () => {
    if (count >= properties.lenght) {
      isDone = true;
    }

    let value = this[properties[count++]];

    return { done: isDone, value };
  };

  return { next };
};

Add return object for next()


var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var raptorTemplatesCompiler = require('../../compiler');

function loadSource(templatePath, compiledSrc) {
    var templateModulePath = templatePath + '.js';

    var templateModule = new Module(templateModulePath, module);
    templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
    templateModule.filename = templateModulePath;

    templateModule._compile(
        compiledSrc,
        templateModulePath);

    return templateModule.exports;
}

module.exports = function load(templatePath) {
    var targetFile = templatePath + '.js';
    var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
    var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);
    if (isUpToDate) {
        return require(targetFile);
    }

	var templateSrc = fs.readFileSync(templatePath, {encoding: 'utf8'});
	var compiledSrc = compiler.compile(templateSrc);

    // console.log('Compiled code for "' + templatePath + '":\n' + compiledSrc);

    fs.writeFileSync(targetFile, compiledSrc, {encoding: 'utf8'});

    return require(targetFile);
};

module.exports.loadSource = loadSource;

var nodePath = require('path');
var fs = require('fs');
var Module = require('module').Module;
var raptorTemplatesCompiler = require('../../compiler');
var cwd = process.cwd();

function loadSource(templatePath, compiledSrc) {
    var templateModulePath = templatePath + '.js';

    var templateModule = new Module(templateModulePath, module);
    templateModule.paths = Module._nodeModulePaths(nodePath.dirname(templateModulePath));
    templateModule.filename = templateModulePath;

    templateModule._compile(
        compiledSrc,
        templateModulePath);

    return templateModule.exports;
}

module.exports = function load(templatePath) {
    templatePath = nodePath.resolve(cwd, templatePath);

    var targetFile = templatePath + '.js';
    var compiler = raptorTemplatesCompiler.createCompiler(templatePath);
    var isUpToDate = compiler.checkUpToDate(templatePath, targetFile);
    if (isUpToDate) {
        return require(targetFile);
    }

	var templateSrc = fs.readFileSync(templatePath, {encoding: 'utf8'});
	var compiledSrc = compiler.compile(templateSrc);

    // console.log('Compiled code for "' + templatePath + '":\n' + compiledSrc);

    fs.writeFileSync(targetFile, compiledSrc, {encoding: 'utf8'});

    return require(targetFile);
};

module.exports.loadSource = loadSource;

Make sure template paths are resolved


function setImageValue(url){
  $('.mce-btn.mce-open').parent().find('.mce-textbox').val(url);
}

$(document).ready(function(){

  $.ajaxSetup({
      headers: {
          'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
      }
  });

  tinymce.init({
    menubar: false,
    selector:'textarea.richTextBox',
    skin: 'voyager',
    plugins: 'link, image, code, youtube, giphy, table, textcolor',
    extended_valid_elements : 'input[onclick|value|style|type]',
    file_browser_callback: function(field_name, url, type, win) {
            if(type =='image'){
              $('#upload_file').trigger('click');
            }
        },
    toolbar: 'styleselect bold italic underline | forecolor backcolor | alignleft aligncenter alignright | bullist numlist outdent indent | link image table youtube giphy | code',
    convert_urls: false,
    image_caption: true,
    image_title: true
  });

});

function setImageValue(url){
  $('.mce-btn.mce-open').parent().find('.mce-textbox').val(url);
}

$(document).ready(function(){

  $.ajaxSetup({
      headers: {
          'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
      }
  });

  tinymce.init({
    menubar: false,
    selector:'textarea.richTextBox',
    skin: 'voyager',
    plugins: 'link, image, code, youtube, giphy, table, textcolor',
    extended_valid_elements : 'input[onclick|value|style|type|class|name]',
    file_browser_callback: function(field_name, url, type, win) {
            if(type =='image'){
              $('#upload_file').trigger('click');
            }
        },
    toolbar: 'styleselect bold italic underline | forecolor backcolor | alignleft aligncenter alignright | bullist numlist outdent indent | link image table youtube giphy | code',
    convert_urls: false,
    image_caption: true,
    image_title: true
  });

});

Add forms inside page editor.


import React from 'react';
import HeroBanner from 'shared/components/heroBanner/heroBanner';
import banner1 from 'images/bannerimg1.jpg';
import WhyGive from './whyGive/whyGive';
import Volunteer from './volunteer/volunteer';
import SuccessStories from './successStories/successStories';
import styles from './getInvolved.css';

const getInvolved = () => (
  <div className={styles.page}>
    <HeroBanner
      imageSrc={banner1}
      title="Get Involved"
      subtitle="See the magic happen..."
    />

    <WhyGive />
    <Volunteer />
    <SuccessStories />
  </div>
);

export default getInvolved;

import React from 'react';
import HeroBanner from 'shared/components/heroBanner/heroBanner';
import banner1 from 'images/bannerimg1.jpg';
import WhyGive from './whyGive/whyGive';
import Volunteer from './volunteer/volunteer';

const getInvolved = () => (
  <div>
    <HeroBanner
      imageSrc={banner1}
      title="Get Involved"
      subtitle="See the magic happen..."
    />

    <WhyGive />
    <Volunteer />
  </div>
);

export default getInvolved;

Remove SuccessStories from this page


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

module.exports = {
  entry: [path.resolve(__dirname, '../client/index.js')],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }, {
        test: /\.css/,
        loader: ExtractTextPlugin.extract('css')
      }, {
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
        loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]'
      }
    ],
    preLoaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'eslint-loader'
    }]
  },
  output: {
    path: path.resolve(__dirname, '../public'),
    filename: 'client.js'
  },
  plugins: [
    new ExtractTextPlugin('style.css', {
      allChunks: true
    }),
    new webpack.ProvidePlugin({
      fetch: 'imports?this=>global!exports?global.fetch!whatwg-fetch'
    })
  ],
  resolve: {
    root: path.resolve(__dirname, '../client'),
    extensions: ['', '.js']
  }
}

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

module.exports = {
  entry: [path.resolve(__dirname, '../client/index.js')],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loaders: ['babel']
      }, {
        test: /\.css/,
        loader: ExtractTextPlugin.extract('css')
      }, {
        test: /\.(eot|woff|woff2|ttf|svg|png|jpg)$/,
        loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]'
      }
    ],
    preLoaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'eslint-loader'
    }]
  },
  output: {
    path: path.resolve(__dirname, '../public'),
    filename: 'client.js'
  },
  plugins: [
    new ExtractTextPlugin('style.css', {
      allChunks: true
    }),
    new webpack.NoErrorsPlugin(),
    new webpack.ProvidePlugin({
      fetch: 'imports?this=>global!exports?global.fetch!whatwg-fetch'
    })
  ],
  resolve: {
    root: path.resolve(__dirname, '../client'),
    extensions: ['', '.js']
  }
}

Add the webpack NoErrors plugin


export default {
  coerce (val) {
    return Array.isArray(val) ? val : [val];
  },
  default () {
    return [];
  },
  deserialize (val) {
    return val.split(',');
  },
  serialize (val) {
    return val.join(',');
  }
};

const { parse, stringify } = window.JSON;

export default {
  coerce (val) {
    return Array.isArray(val) ? val : [val];
  },
  default () {
    return [];
  },
  deserialize (val) {
    return parse(val);
  },
  serialize (val) {
    return stringify(val);
  }
};

Convert to using JSON parsing.


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

class App extends Component {
  render() {
    return (

Desvolar

              Origen
              <input type="text"></input>

              Destino
              <input type="text"></input>

              <button>Buscar</button>

    );
  }
}

export default App;

import React, { Component } from 'react';
import logo from './airplane.svg';
import './App.css';
import {Button, Input} from 'semantic-ui-react'
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import moment from 'moment';

class App extends Component {
  constructor(props){
    super(props)
    moment.locale('es');
    this.state = {
      departureDate:  moment()
    }
    this.handleChange = this.handleChange.bind(this);
  }
  handleChange(date){
    console.info(date);
    this.setState({
      departureDate: date
    })
  }
  render() {
    return (

Desvolar.com

              Origen
              <Input placeholder="Ciudad origen..."></Input>

              Destino
              <Input placeholder="Ciudad destino..."></Input>

              Fecha Ida
              <DatePicker selected={this.state.departureDate} onChange={this.handleChange}/>

              Fecha Regreso
              <DatePicker/>

              Número de pasajeros
              <input type="number" max="20" min="1"></input>

              <Button>Buscar</Button>

    );
  }
}

export default App;

Add fields and state to manage departureDate


core.Module("unify.Kernel", {
	init : function() {
		core.io.Script.load("script/" + jasy.Env.getValue("unify.application.namespace") + "-" + jasy.Env.CHECKSUM + ".js");
	}
});

setTimeout(unify.Kernel.init, 0);

core.Module("unify.Kernel", {
	init : function() {
		core.io.Script.load("script/" + jasy.Env.getValue("unify.application.namespace") + "-" + jasy.Env.getChecksum() + ".js");
	}
});

setTimeout(unify.Kernel.init, 0);

Refactor from CHECKSUM to getChecksum()


(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else {
        root.ess = factory();
    }
}(this, function () {
    function s(selector, context) {
        var elements = [];
        if (selector.indexOf(' ') !== -1) {
            var parts = selector.split(' '),
                thisSelector = parts.shift(),
                nextSelector = parts.join(' '),
                results = s(thisSelector, context);
            if (results) {
                if (typeof results.length !== 'undefined') {
                    for (var i=0, l=results.length; i < l; i++) {
                        elements = elements.concat(s(nextSelector, results[i]));
                    }
                } else {
                    elements = elements.concat(s(nextSelector, results));
                }
            }
        } else {
            context = context || document;
            var type = selector.substring(0, 1);
            if ('#' === type) {
                return context.getElementById(selector.substring(1));
            } else {
                var list;
                if ('.' === type) {
                    list = context.getElementsByClassName(selector.substring(1));
                } else {
                    list = context.getElementsByTagName(selector);
                }
                var listLength = list.length;
                for (var i = 0; i < listLength; i++) {
                    elements.push(list[i]);
                }
            }
        }
        return elements;
    }
    return s;
}));

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        define([], factory);
    } else {
        root.ess = factory();
    }
}(this, function () {
    function s(selector, context) {
        var elements = [];
        if (selector.indexOf(' ') !== -1) {
            var parts = selector.split(' '),
                thisSelector = parts.shift(),
                nextSelector = parts.join(' '),
                results = s(thisSelector, context);
            if (results) {
                if (typeof results.length !== 'undefined') {
                    for (var i=0, l=results.length; i < l; i++) {
                        elements = elements.concat(s(nextSelector, results[i]));
                    }
                } else {
                    elements = elements.concat(s(nextSelector, results));
                }
            }
        } else {
            context = context || document;
            var type = selector.substring(0, 1);
            if ('#' === type) {
                return context.getElementById(selector.substring(1));
            } else {
                var list;
                if ('.' === type) {
                    if (document.getElementsByClassName) {
                        list = context.getElementsByClassName(selector.substring(1));
                    } else {
                        list = context.querySelectorAll(selector);
                    }
                } else {
                    list = context.getElementsByTagName(selector);
                }
                var listLength = list.length;
                for (var i = 0; i < listLength; i++) {
                    elements.push(list[i]);
                }
            }
        }
        return elements;
    }
    return s;
}));

Add find by class name support for IE8


module.exports = function(r) {
    'use strict';
    return {
        getProjectsForUser: getProjectsForUser
    };

    ///////////////

    function *getProjectsForUser(user, isAdmin) {
        let rql;
        if (isAdmin) {
            rql = r.table('projects')
                .filter(r.row('owner').ne('delete@materialscommons.org'))
                .pluck('name').orderBy('name');
        } else {
            rql = r.table('access').getAll(user, {index: 'user_id'})
                .eqJoin('project_id', r.table('projects'))
                .zip()
                .pluck('name')
                .orderBy('name');
        }

        return yield rql.run();
    }
};

module.exports = function(r) {
    'use strict';
    let run = require('./run');
    return {
        forUser: forUser
    };

    ///////////////

    function forUser(user) {
        let rql;
        if (user.isAdmin) {
            rql = r.table('projects')
                .filter(r.row('owner').ne('delete@materialscommons.org'));
        } else {
            rql = r.table('access').getAll(user.id, {index: 'user_id'})
                .eqJoin('project_id', r.table('projects'))
                .zip();
        }

        rql = addComputed(rql);

        return run(rql);
    }

    // addComputed adds additional attributes to the rql that
    // that are computed from other tables.
    function addComputed(rql) {
        rql = rql.merge(function(project) {
            return {
                users: r.table('access')
                    .getAll(project('id'), {index: 'project_id'})
                    .map(function(access) {
                        return access.merge({
                            'user': access('user_id')
                        });
                    })
                    .pluck('user', 'permissions')
                    .coerceTo('array'),
                reviews: r.table('reviews')
                    .getAll(project('id'), {index: 'project_id'})
                    .coerceTo('array'),
                notes: r.table('notes')
                    .getAll(project('id'), {index: 'project_id'})
                    .coerceTo('array'),
                events: r.table('events')
                    .getAll(project('id'), {index: 'project_id'})
                    .coerceTo('array')
            };
        });

        return rql;
    }
};

Return a promise rather than a generator since you can always pass a promise to a generator. Rely on module name (golang style) for method names. The module makes the method name more understandable. General cleanup of the interface.


'use strict';
/* global window:false, performance:false */
const Bluefox = require('bluefox');

const log = require('../../../../lib/logger')({hostname: 'content', MODULE: 'wait/content/index'});
const trackRunResultEvents = require('./trackRunResultEvents');
const registerRunnerModule = require('../../../content-register');

registerRunnerModule('wait', async ({eventEmitter, getModule}) => {
    const runResultModule = await getModule('runResult');
    const bluefox = new Bluefox();
    const wait = bluefox.target(window);

    eventEmitter.on('tabs.initializedTabContent', () => {
        const drain = trackRunResultEvents(runResultModule, bluefox);
        eventEmitter.on('tabs.beforeContentUnload', () => {
            try {
                log.debug('Creating run result events...');
                drain();
            }
            catch (err) {
                log.error({err}, 'Error while creating runResult events');
            }
        });
    });

    return {
        scriptValue: metadata => {
            if (typeof metadata.waitBeginTime === 'number') {
                return wait.overrideStartTime(metadata.waitBeginTime);
            }
            if (typeof metadata.runBeginTime === 'number') {
                return wait.overrideStartTime(metadata.runBeginTime);
            }
            return wait;
        },
    };
});

'use strict';
/* global window:false */
const Bluefox = require('bluefox');

const log = require('../../../../lib/logger')({hostname: 'content', MODULE: 'wait/content/index'});
const trackRunResultEvents = require('./trackRunResultEvents');
const registerRunnerModule = require('../../../content-register');

registerRunnerModule('wait', async ({eventEmitter, getModule}) => {
    const runResultModule = await getModule('runResult');
    const bluefox = new Bluefox();
    const wait = bluefox.target(window);

    eventEmitter.on('tabs.initializedTabContent', () => {
        const drain = trackRunResultEvents(runResultModule, bluefox);
        eventEmitter.on('tabs.beforeContentUnload', () => {
            try {
                log.debug('Creating run result events...');
                drain();
            }
            catch (err) {
                log.error({err}, 'Error while creating runResult events');
            }
        });
    });

    return {
        scriptValue: metadata => {
            if (typeof metadata.waitBeginTime === 'number') {
                return wait.overrideStartTime(metadata.waitBeginTime);
            }
            if (typeof metadata.runBeginTime === 'number') {
                return wait.overrideStartTime(metadata.runBeginTime);
            }
            return wait;
        },
    };
});

Fix linter error caused by in-range update to eslint


import React from 'react';

require('./detail.scss');

export default class Detail extends React.Component {

  render() {
    const {title} = this.props;
    return (

{title} (clear)

      {this.props.children}

);
  }
}

Detail.propTypes = {
  title: React.PropTypes.string,
  children: React.PropTypes.object,
  clear: React.PropTypes.func,
};

import React from 'react';

require('./detail.scss');

export default class Detail extends React.Component {

  componentDidMount() {
    document.addEventListener('keydown', this.handleEscape.bind(this), false);
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this.handleEscape.bind(this), false);
  }

  handleEscape(e) {
    if (e.keyCode === 27) {
      this.props.clear(); // Uncaught TypeError: Cannot read property 'clear' of undefined
    }
  }

  render() {
    const {title} = this.props;
    return (

{title} (clear)

      {this.props.children}

);
  }
}

Detail.propTypes = {
  title: React.PropTypes.string,
  children: React.PropTypes.object,
  clear: React.PropTypes.func.isRequired,
};

Clear selections on escape key


Template.lottoAdd.created = function() {
  Session.set('lottoAddErrors', {});
};
Template.lottoAdd.rendered = function() {
  var nextSaturday = moment().day(5).utcOffset(0);
  this.find('#date').value = nextSaturday.format('YYYY-MM-DD');
  this.find('#date').valueAsDate = nextSaturday.toDate();
};

Template.lottoAdd.helpers({
  errorMessage: function(field) {
    return Session.get('lottoAddErrors')[field];
  },
  errorClass: function (field) {
    return !!Session.get('lottoAddErrors')[field] ? 'has-error' : '';
  }
});

Template.lottoAdd.events({
  'submit form': function(e) {
    e.preventDefault();

    var lotto = {
      date: moment(e.target.date.value).toDate()
    };

    if (!lotto.date) {
      var errors = {};
      errors.date = "Please select a date";
      return Session.set('lottoAddErrors', errors);
    }

    //var autofill = e.target.autofill.checked;

    Meteor.call('lottoInsert', lotto, false, function(error, result) {
      if(error) {
        return throwError(error.reason);
      }
      if(result.lottoExists) {
        throwError('Lotto for this date already exists');
      }
      Router.go('lottoPage', {_id: result._id});
    });
  }
});

Template.lottoAdd.created = function() {
  Session.set('lottoAddErrors', {});
};
Template.lottoAdd.rendered = function() {
  var nextSaturday = moment().startOf('day').day(6).utcOffset(0);
  this.find('#date').value = nextSaturday.format('YYYY-MM-DD');
  this.find('#date').valueAsDate = nextSaturday.toDate();
};

Template.lottoAdd.helpers({
  errorMessage: function(field) {
    return Session.get('lottoAddErrors')[field];
  },
  errorClass: function (field) {
    return !!Session.get('lottoAddErrors')[field] ? 'has-error' : '';
  }
});

Template.lottoAdd.events({
  'submit form': function(e) {
    e.preventDefault();

    var lotto = {
      date: moment(e.target.date.value).toDate()
    };

    if (!lotto.date) {
      var errors = {};
      errors.date = "Please select a date";
      return Session.set('lottoAddErrors', errors);
    }

    //var autofill = e.target.autofill.checked;

    Meteor.call('lottoInsert', lotto, false, function(error, result) {
      if(error) {
        return throwError(error.reason);
      }
      if(result.lottoExists) {
        throwError('Lotto for this date already exists');
      }
      Router.go('lottoPage', {_id: result._id});
    });
  }
});

Fix bug showing the wrong date when creating a new lotto because it depended on the current time


module.exports = inject

function inject (bot) {
  bot.isAlive = true

  bot._client.on('respawn', (packet) => {
    bot.isAlive = false
    bot.emit('respawn')
  })

  bot._client.once('update_health', (packet) => {
    if (bot.isAlive && packet.health > 0) {
      bot.emit('spawn')
    }
  })

  bot._client.on('update_health', (packet) => {
    bot.health = packet.health
    bot.food = packet.food
    bot.foodSaturation = packet.foodSaturation
    bot.emit('health')
    if (bot.health <= 0) {
      bot.isAlive = false
      bot.emit('death')
      bot._client.write('client_command', { payload: 0 })
    } else if (bot.health > 0 && !bot.isAlive) {
      bot.isAlive = true
      bot.emit('spawn')
    }
  })
}

module.exports = inject

function inject (bot) {
  bot.isAlive = true

  bot._client.on('respawn', (packet) => {
    bot.isAlive = false
    bot.emit('respawn')
  })

  bot._client.once('update_health', (packet) => {
    if (packet.health > 0) {
      bot.emit('spawn')
    }
  })

  bot._client.on('update_health', (packet) => {
    bot.health = packet.health
    bot.food = packet.food
    bot.foodSaturation = packet.foodSaturation
    bot.emit('health')
    if (bot.health <= 0) {
      bot.isAlive = false
      bot.emit('death')
      bot._client.write('client_command', { payload: 0 })
    } else if (bot.health > 0 && !bot.isAlive) {
      bot.isAlive = true
      bot.emit('spawn')
    }
  })
}

Check for bot.isAlive not needed


import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import { findWithAssert } from 'ember-native-dom-helpers/test-support/helpers';

moduleForComponent('find', 'Integration | Test Helper | findWithAssert', {
  integration: true
});

test('with empty query result, findWithAssert raises an error', function(assert) {
  this.render(hbs`

You can't find me

  `);
  assert.throws(() => {
    findWithAssert('.hidden');
  });
});

/*
test('find helper uses querySelector within test DOM', function(assert) {
  const selector = 'input[type="text"]';
  const firstInput = document.querySelector(selector);

  this.render(hbs`
    <input type="text" />
  `);
  let expected = document.querySelector(`#ember-testing ${selector}`);
  let actual = find(selector);

  assert.strictEqual(actual, expected, 'input found within #ember-testing');
  assert.notStrictEqual(actual, firstInput, 'test runner input not selected with find');
});
*/

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import { findWithAssert } from 'ember-native-dom-helpers/test-support/helpers';

moduleForComponent('find', 'Integration | Test Helper | findWithAssert', {
  integration: true
});

test('with empty query result, findWithAssert raises an error', function(assert) {
  this.render(hbs`

You can't find me

  `);
  assert.throws(() => {
    findWithAssert('.hidden');
  });
});

test('with a query result, findWithAssert helper is the same as find helper', function(assert) {
  const selector = 'input[type="text"]';

  this.render(hbs`
    <input type="text" />
  `);
  let expected = document.querySelector(`#ember-testing ${selector}`);
  let actual = findWithAssert(selector);

  assert.strictEqual(actual, expected, 'input found within #ember-testing');
});

Add findWithAssert test, acts like find


exports.BattleAbilities = {
	"serenegrace": {
  		inherit: true
		onModifyMove: function(move) {
			if (move.secondaries) {
				this.debug('doubling secondary chance');
				for (var i=0; i<move.secondaries.length; i++) {
					if move.secondaries[i].chance >= 50 {
						move.secondaries[i].chance = 100;
					}
				}
			}
		}
	},
	"skilllink": {
		inherit: true
		onModifyMove: function(move) {
			if (move.multihit && move.multihit.length) {
				if (move.multihit[1] === 3 && move.id !== "triplekick") {
					move.multihit = 5;
				}
			}
		}
	}
};

exports.BattleAbilities = {
	"serenegrace": {
  		inherit: true
  		onModifyMovePriority: -101,
		onModifyMove: function(move) {
			if (move.secondaries) {
				this.debug('doubling secondary chance');
				for (var i=0; i<move.secondaries.length; i++) {
					if move.secondaries[i].chance >= 50 {
						move.secondaries[i].chance = 100;
					}
				}
			}
		}
	},
	"skilllink": {
		inherit: true
		onModifyMove: function(move) {
			if (move.multihit && move.multihit.length) {
				if (move.multihit[1] === 3 && move.id !== "triplekick") {
					move.multihit = 5;
				}
			}
		}
	}
};

Test 1 of Serene Grace


'use strict';

const BaseRepository = require('@gfcc/mongo-tenant-repository/BaseRepository');

/**
 * @class AccountRepository
 */
class AccountRepository extends BaseRepository {
  /**
   * @inheritDoc
   */
  getSchemaDefinition() {
    return {
      email: {
        type: String,
        unique: true,
        required: true
      },
      username: {
        type: String,
        index: {
          unique: true,
          partialFilterExpression: {
            email: {
              $type: 'string'
            }
          }
        }
      },
      passwordHash: String,
    };
  }

  /**
   * @param email
   * @param callback
   * @returns {AccountRepository}
   */
  findOneByEmail(email, callback) {
    this.findOne({
      email: email,
    }, callback);

    return this;
  }

  /**
   * Find an account by its username.
   *
   * @param {string} username
   * @param {function} callback
   * @return {AccountRepository}
   */
  findOneByUsername(username, callback) {
    this.findOne({
      username: username,
    }, callback);

    return this;
  }
}

module.exports = AccountRepository;

'use strict';

const BaseRepository = require('@gfcc/mongo-tenant-repository/BaseRepository');

/**
 * @class AccountRepository
 */
class AccountRepository extends BaseRepository {
  /**
   * @inheritDoc
   */
  getSchemaDefinition() {
    return {
      email: {
        type: String,
        unique: true,
        required: true
      },
      username: {
        type: String,
        index: {
          unique: true,
          partialFilterExpression: {
            username: {
              $type: 'string'
            }
          }
        }
      },
      passwordHash: String,
    };
  }

  /**
   * @param email
   * @param callback
   * @returns {AccountRepository}
   */
  findOneByEmail(email, callback) {
    this.findOne({
      email: email,
    }, callback);

    return this;
  }

  /**
   * Find an account by its username.
   *
   * @param {string} username
   * @param {function} callback
   * @return {AccountRepository}
   */
  findOneByUsername(username, callback) {
    this.findOne({
      username: username,
    }, callback);

    return this;
  }
}

module.exports = AccountRepository;

Fix field name in order to support multiple accounts without usernames.


isic.views.LayoutHeaderView = isic.View.extend({
    events: {
        'click .isic-link-home': function () {
            isic.router.navigate('index', {trigger: true});
        },

        'click .isic-link-dataset-upload': function () {
            isic.router.navigate('uploadDataset', {trigger: true});
        },

        'click .isic-link-studies': function () {
            isic.router.navigate('studies', {trigger: true});
        }
    },

    initialize: function () {
        this.datasetContributor = false;

        this._updateUserInfo();

        girder.events.on('g:login', this._updateUserInfo, this);

        this.render();
    },

    render: function () {
        this.$el.html(isic.templates.layoutHeader({
            datasetContributor: this.datasetContributor
        }));

        this.$('a[title]').tooltip({
            placement: 'bottom',
            delay: {show: 300}
        });

        new isic.views.LayoutHeaderUserView({
            el: this.$('.isic-current-user-wrapper'),
            parentView: this
        }).render();
    },

    _updateUserInfo: function (){
        // Check whether user has permission to contribute datasets
        var datasetModel = new isic.models.DatasetModel();
        datasetModel.userCanContribute(girder.currentUser).then(_.bind(function (datasetContributor) {
            if (this.datasetContributor != datasetContributor) {
                this.datasetContributor = datasetContributor;
                this.render();
            }
        }, this));
    }
});

isic.views.LayoutHeaderView = isic.View.extend({
    events: {
        'click .isic-link-home': function () {
            isic.router.navigate('index', {trigger: true});
        },

        'click .isic-link-dataset-upload': function () {
            isic.router.navigate('uploadDataset', {trigger: true});
        },

        'click .isic-link-studies': function () {
            isic.router.navigate('studies', {trigger: true});
        }
    },

    initialize: function () {
        this.datasetContributor = false;

        this._updateUserInfo();

        girder.events.on('g:login', this._updateUserInfo, this);

        this.render();
    },

    render: function () {
        this.$el.html(isic.templates.layoutHeader({
            datasetContributor: this.datasetContributor
        }));

        // Specify trigger for tooltip to ensure that tooltip hides when button
        // is clicked. See http://stackoverflow.com/a/33585981/2522042.
        this.$('a[title]').tooltip({
            placement: 'bottom',
            trigger: 'hover',
            delay: {show: 300}
        });

        new isic.views.LayoutHeaderUserView({
            el: this.$('.isic-current-user-wrapper'),
            parentView: this
        }).render();
    },

    _updateUserInfo: function (){
        // Check whether user has permission to contribute datasets
        var datasetModel = new isic.models.DatasetModel();
        datasetModel.userCanContribute(girder.currentUser).then(_.bind(function (datasetContributor) {
            if (this.datasetContributor != datasetContributor) {
                this.datasetContributor = datasetContributor;
                this.render();
            }
        }, this));
    }
});

Fix tooltips not hiding after clicking button


// @ngInject
export default function appstoreField($filter, $compile, $parse) {
  return {
    restrict: 'E',
    link: function(scope, element, attributes) {
      const field = $parse(attributes.field)(scope);
      const fieldType = field.type.replace('_', '-');
      const component = field.component && $filter('snakeCase')(field.component) || `appstore-field-${fieldType}`;
      const template = `<${component} model="${attributes.model}" field="${attributes.field}" form="${attributes.form}"></${component}>`;
      element.html(template);
      $compile(element.contents())(scope);
    }
  };
}

// @ngInject
export default function appstoreField($filter, $compile, $parse) {
  return {
    restrict: 'E',
    link: function(scope, element, attributes) {
      const field = $parse(attributes.field)(scope);
      let fieldType;
      if (field.type) {
        fieldType = field.type.replace('_', '-');
      }

      const component = field.component && $filter('snakeCase')(field.component) || `appstore-field-${fieldType}`;
      const template = `<${component} model="${attributes.model}" field="${attributes.field}" form="${attributes.form}"></${component}>`;
      element.html(template);
      $compile(element.contents())(scope);
    }
  };
}

Read field type only if it's present