'use strict';

/**
 * A set of functions called "actions" for `ContentManager`
 */

module.exports = {

  models: async(ctx) => {
    ctx.body = strapi.models;
  },

  find: async(ctx) => {
    const model = ctx.params.model;

    const {
      limit = 10,
      skip = 0,
      sort = '_id'
    } = ctx.request.query;

    const entries = await User
      .find()
      .limit(limit)
      .sort(sort)
      .limit(skip);

    ctx.body = entries;
  },

  count: async(ctx) => {
    const model = ctx.params.model;

    const count = await User
      .count();

    ctx.body = {
      count: Number(count)
    };
  },

  findOne: async(ctx) => {
    const model = ctx.params.model;
    const _id = ctx.params._id;

    const entries = await User
      .find({
        id
      });

    ctx.body = entries;
  },

  update: async(ctx) => {
    const entryUpdated = await User
      .update({_id: ctx.request.params.id}, ctx.request.body);

    ctx.body = entryUpdated;
  },

  delete: async(ctx) => {
    const entryDeleted = await User
      .remove({_id: ctx.request.params.id});

    ctx.body = entryDeleted;
  }
};

'use strict';

/**
 * A set of functions called "actions" for `ContentManager`
 */

module.exports = {

  models: async(ctx) => {
    ctx.body = strapi.models;
  },

  find: async(ctx) => {
    const model = ctx.params.model;

    const {
      limit = 10,
      skip = 0,
      sort = '_id'
    } = ctx.request.query;

    const entries = await User
      .find()
      .limit(Number(limit))
      .sort(sort)
      .skip(Number(skip));

    ctx.body = entries;
  },

  count: async(ctx) => {
    const model = ctx.params.model;

    const count = await User
      .count();

    ctx.body = {
      count: Number(count)
    };
  },

  findOne: async(ctx) => {
    const model = ctx.params.model;
    const _id = ctx.params._id;

    const entries = await User
      .find({
        id
      });

    ctx.body = entries;
  },

  update: async(ctx) => {
    const entryUpdated = await User
      .update({_id: ctx.request.params.id}, ctx.request.body);

    ctx.body = entryUpdated;
  },

  delete: async(ctx) => {
    const entryDeleted = await User
      .remove({_id: ctx.request.params.id});

    ctx.body = entryDeleted;
  }
};

Fix find function in content manager controller


/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
], function() {
    'use strict';
});

/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
    'jquery',
    'utils/init',
    'utils/html',
    'utils/error',
    'utils/request'
], function($, init, html, err, request) {
    'use strict';
    var gTestSuite;

    document.getElementById('li-test').setAttribute('class', 'active');

    function getCountsFail() {
        html.replaceByClass('count-list-badge', '∞');
    }

    function getCountsDone(response) {
        console.log(response);
    }

    function getCounts() {
        var batchOps;
        var queryStr;
        var deferred;

        batchOps = [];
        queryStr = 'test_suite_name=' + gTestSuite;

        batchOps.push({
            method: 'GET',
            resource: 'count',
            document: 'test_set',
            operation_id: 'count-test-sets',
            query: queryStr
        });

        batchOps.push({
            method: 'GET',
            resource: 'count',
            document: 'test_case',
            operation_id: 'count-test-cases',
            query: queryStr
        });

        batchOps.push({
            method: 'GET',
            resource: 'test_suite',
            distinct: 'build_id',
            operation_id: 'count-builds',
            query: queryStr
        });

        batchOps.push({
            method: 'GET',
            resource: 'test_suite',
            distinct: 'boot_id',
            operation_id: 'count-boots',
            query: queryStr
        });

        batchOps.push({
            method: 'GET',
            resource: 'test_suite',
            distinct: 'board',
            operation_id: 'count-boards',
            query: queryStr
        });

        deferred = request.post(
            '/_ajax/batch', JSON.stringify({batch: batchOps}));

        $.when(deferred)
            .done(getCountsDone)
            .fail(err.error, getCountsFail);
    }

    gTestSuite = document.getElementById('test-suite');
    if (gTestSuite) {
        gTestSuite = gTestSuite.value;

        getCounts();
    }

    init.hotkeys();
    init.tooltip();
});

Add initial batch operations to retrieve data


var parseEnv = require('parse-env');

var configTemplate = require('./config.template');
var config;

try {
    config = require('./config');
}
catch(e) {}

module.exports = parseEnv(process.env, configTemplate, config);

var parseEnv = require('parse-env');

var configTemplate = require('./config.template');
var config;

try {
    config = require('./config');
}
catch(e) {}

var env = parseEnv(process.env, configTemplate, config);

if(process.env.VCAP_SERVICES){
    var vcap = JSON.parse(process.env.VCAP_SERVICES);

    console.log(vcap);

    env.mongo = vcap['mongodb2-2.4.8'][0]['credentials'];
}

module.exports = env;

Connect to MongoDB on AppFog


var log = require('../lib/logger');

var allTheSettings = {
  coinbaseApiKey: process.env.COINBASE_API_KEY,
  coinbaseApiSec: process.env.COINBASE_API_SECRET,
  coinbaseApiUri: process.env.COINBASE_API_URI,
  coinbaseApiWallet: process.env.COINBASE_API_WALLET,
  dbUrl: process.env.DATABASE_URL,
  redisUrl: process.env.REDIS_URL,
  secret: process.env.SECRET,
  mailerUser: process.env.MG_USER,
  mailerPass: process.env.MG_PASS,
  authSecret: process.env.AUTH_SECRET
};

try {
  var overrides = require('./configOverrides.js');

  log.debug("Found overrides for", Object.keys(overrides));

  for (var prop in overrides) {
    if (overrides.hasOwnProperty(prop)) {
      if (allTheSettings[prop]) {
        allTheSettings[prop] = overrides[prop];
      }
    }
  }
} catch (e) {
  // if no override file is found
  log.debug("no overrides found, reverting to env vars");

}

module.exports = allTheSettings;

var log = require('../lib/logger');

var config = {
  coinbaseApiKey: process.env.COINBASE_API_KEY,
  coinbaseApiSec: process.env.COINBASE_API_SECRET,
  coinbaseApiUri: process.env.COINBASE_API_URI,
  coinbaseApiWallet: process.env.COINBASE_API_WALLET,
  dbUrl: process.env.DATABASE_URL,
  redisUrl: process.env.REDIS_URL,
  secret: process.env.SECRET,
  mailerUser: process.env.MG_USER,
  mailerPass: process.env.MG_PASS,
  authSecret: process.env.AUTH_SECRET
};

try {
  var overrides = require('./configOverrides.js');
  Object.keys(overrides).forEach(function(key) {
    log.debug("found override for " + key);
    config[key] = overrides[key];
  });

} catch (e) {
  // if no override file is found
  log.debug("no overrides found, reverting to env vars");

}

module.exports = config;

Update overrides iterator to use Array.forEach


//= require jquery.cookie
//= require jquery.timeago
//= require jquery.timeago.de
//= require leaflet
//= require foundation/modernizr.foundation
//= require foundation/jquery.placeholder
//= require foundation/jquery.foundation.alerts
//= require foundation/jquery.foundation.accordion
//= require foundation/jquery.foundation.buttons
//= require foundation/jquery.foundation.tooltips
//= require foundation/jquery.foundation.forms
//= require foundation/jquery.foundation.tabs
//= require foundation/jquery.foundation.navigation
//= require foundation/jquery.foundation.topbar
//= require foundation/jquery.foundation.reveal
//= require foundation/jquery.foundation.orbit
//= require foundation/jquery.foundation.joyride
//= require foundation/jquery.foundation.clearing
//= require foundation/jquery.foundation.mediaQueryToggle
//= require foundation/app
//= require select2
//= require backbone
//= require backbone.marionette
//= require backbone.forms
//= require backbone.forms-ext
//= require backbone.forms.select2
//= require teikei
//= require_tree ../templates
//= require_tree ./utils
//= require_tree ./models
//= require_tree ./collections
//= require_tree ./views
//= require_tree ./routers
//= require_tree .

//= require jquery.cookie
//= require jquery.timeago
//= require jquery.timeago.de
//= require leaflet
//= require foundation/modernizr.foundation
//= require foundation/jquery.placeholder
//= require foundation/jquery.foundation.alerts
//= require foundation/jquery.foundation.accordion
//= require foundation/jquery.foundation.buttons
//= require foundation/jquery.foundation.tooltips
//= require foundation/jquery.foundation.forms
//= require foundation/jquery.foundation.tabs
//= require foundation/jquery.foundation.navigation
//= require foundation/jquery.foundation.topbar
//= require foundation/jquery.foundation.reveal
//= require foundation/jquery.foundation.orbit
//= require foundation/jquery.foundation.joyride
//= require foundation/jquery.foundation.clearing
//= require foundation/jquery.foundation.mediaQueryToggle
//= require foundation/app
//= require select2
//= require select2_locale_de
//= require backbone
//= require backbone.marionette
//= require backbone.forms
//= require backbone.forms-ext
//= require backbone.forms.select2
//= require teikei
//= require_tree ../templates
//= require_tree ./utils
//= require_tree ./models
//= require_tree ./collections
//= require_tree ./views
//= require_tree ./routers
//= require_tree .

Enable German locale for select2 dropdown form field.


function(doc) {
    if (doc.doc_type === "FormExportInstance" || doc.doc_type === "CaseExportInstance") {
        emit([doc.domain, doc.doc_type, doc.is_deidentified], {
            _id: doc._id,
            domain: doc.domain,
            doc_type: doc.doc_type,
            is_deidentified: doc.is_deidentified,
            is_daily_saved_export: doc.is_daily_saved_export,
            export_format: doc.export_format,
            name: doc.name,
            owner_id: doc.owner_id,
            sharing: doc.sharing,
        });
    }
}

function(doc) {
    if (doc.doc_type === "FormExportInstance" || doc.doc_type === "CaseExportInstance") {
        emit([doc.domain, doc.doc_type, doc.is_deidentified], {
            _id: doc._id,
            domain: doc.domain,
            doc_type: doc.doc_type,
            is_deidentified: doc.is_deidentified,
            is_daily_saved_export: doc.is_daily_saved_export,
            is_odata_config: doc.is_odata_config,
            export_format: doc.export_format,
            name: doc.name,
            owner_id: doc.owner_id,
            sharing: doc.sharing,
        });
    }
}

Include is_odata_config in brief exports


function(context) {
  var app = $$(this).app;
  var url = $("#pasted_url").val();
  if (url.length > 0) {
    idPos = url.indexOf("id=");
    if (idPos > -1) {
      url = url.substr(idPos + 3);
    }
    lastSlash = url.lastIndexOf("/");
    if (lastSlash > -1) {
      url = url.substr(lastSlash + 1);
    }
    ampPos = url.indexOf("&");
    if (ampPos > -1) {
      url = url.substr(0, ampPos);
    }
    if (url.length == 32) {
      app.db.openDoc(url, {
        success: function(doc) {
          if (doc.type) {
            if (doc.type == 'Veteran') {
              window.open("vet_edit.html?vetid=" + doc._id, '_blank')
            } else if (doc.type == 'Guardian') {
              window.open("grd_edit.html?grdid=" + doc._id, '_blank')
            } else if (doc.type == 'Volunteer') {
              window.open("vol_edit.html?volid=" + doc._id, '_blank')
            }
          }
        }
      });
    } else {
      alert('Invalid URL');
    }
  }

  return false;
};

//@ sourceURL=/finder/submit_pasted_url.js

function(context) {
  var app = $$(this).app;
  var url = $("#pasted_url").val();
  if (url.length > 0) {
    idPos = url.indexOf("id=");
    if (idPos > -1) {
      url = url.substr(idPos + 3);
    }
    lastSlash = url.lastIndexOf("/");
    if (lastSlash > -1) {
      url = url.substr(lastSlash + 1);
    }
    ampPos = url.indexOf("&");
    if (ampPos > -1) {
      url = url.substr(0, ampPos);
    }
    guid = url.replace(/^\s+|\s+$/g,"");
    if (guid.length == 32) {
      app.db.openDoc(guid, {
        success: function(doc) {
          if (doc.type) {
            if (doc.type == 'Veteran') {
              window.open("vet_edit.html?vetid=" + doc._id, '_blank')
            } else if (doc.type == 'Guardian') {
              window.open("grd_edit.html?grdid=" + doc._id, '_blank')
            } else if (doc.type == 'Volunteer') {
              window.open("vol_edit.html?volid=" + doc._id, '_blank')
            }
          }
        }
      });
    } else {
      alert('Invalid URL');
    }
  }

  return false;
};

//@ sourceURL=/finder/submit_pasted_url.js

Trim pasted URL before submitting.


/**
 * The Indonesian Forest Area layer module. (based on IdnPlantationsLayerBySpecies.js)
 * More info @ https://basecamp.com/3063126/projects/10726176/todos/303918841
 * @return IdnForestArea class (extends CartoDBLayerClass)
 */

//   'text!map/cartocss/IdnForestArea.cartocss'], function(CartoDBLayerClass, ) {

define([
  'abstract/layer/CartoDBLayerClass',
  'text!map/cartocss/IdnForestArea.cartocss'
], function(CartoDBLayerClass, IdnForestAreaCartocss) {

  'use strict';

  var IdnForestArea = CartoDBLayerClass.extend({

    options: {
      sql: 'SELECT the_geom_webmercator, fungsi_kws, legend as name, cartodb_id, \'{tableName}\' AS tablename, \'{tableName}\' AS layer, {analysis} AS analysis FROM {tableName}',
      cartocss: IdnForestAreaCartocss,
      infowindow: true,
      interactivity: 'cartodb_id, tablename, layer, name, analysis',
      analysis: true,
            },
  });

  return IdnForestArea;

});

/**
 * The Indonesian Forest Area layer module. (based on IdnPlantationsLayerBySpecies.js)
 * More info @ https://basecamp.com/3063126/projects/10726176/todos/303918841
 * @return IdnForestArea class (extends CartoDBLayerClass)
 */

//   'text!map/cartocss/IdnForestArea.cartocss'], function(CartoDBLayerClass, ) {

define([
  'abstract/layer/CartoDBLayerClass',
  'text!map/cartocss/IdnForestArea.cartocss'
], function(CartoDBLayerClass, IdnForestAreaCartocss) {

  'use strict';

  var IdnForestArea = CartoDBLayerClass.extend({

    options: {
      sql: 'SELECT the_geom_webmercator, fungsi_kws, legend as name, cartodb_id, \'{tableName}\' AS tablename, \'{tableName}\' AS layer, {analysis} AS analysis FROM {tableName}',
      cartocss: IdnForestAreaCartocss,
      infowindow: true,
      interactivity: 'cartodb_id, tablename, layer, name, analysis',
      analysis: false
    }
  });

  return IdnForestArea;

});

Disable analysis and subscription from the Indonesia Forest Area layer as requested


/*jslint white: true */
'use strict';

function SignupController($location, $scope, $routeParams, authenticateRequest, errorHandler, httpRequest, itemsRequest, userSession) {

  $scope.user = {};
  var inviteResponseCode;

  $scope.errorHandler = errorHandler;

  httpRequest.get('/api/invite/' + $routeParams.hex_code + '?email=' + $routeParams.email).then(function(inviteResponse) {
    $scope.user.email = inviteResponse.data.email;
    inviteResponseCode = inviteResponse.data.code;
  });

  function userLogin() {

    userSession.setCredentials($scope.user.email, $scope.user.password);

    authenticateRequest.login().then(function(authenticateResponse) {
      userSession.setUserSessionData(authenticateResponse);
      itemsRequest.getItems();
      $location.path('/my');
    }, function(authenticateResponse) {
      $scope.errorHandler.errorMessage = authenticateResponse.data;
    });
  }

  $scope.signUp = function() {
    httpRequest.post('/api/invite/' + inviteResponseCode, {email: $scope.user.email, password: $scope.user.password}).then(function() {
      userLogin();
    });
  };
}

SignupController.$inject = ['$location', '$scope', '$routeParams', 'authenticateRequest', 'errorHandler', 'httpRequest', 'itemsRequest', 'userSession'];
angular.module('em.app').controller('SignupController', SignupController);

/*jslint white: true */
'use strict';

function SignupController($location, $scope, $routeParams, authenticateRequest, errorHandler, httpRequest, itemsRequest, userSession) {

  $scope.user = {};
  var inviteResponseCode;

  $scope.errorHandler = errorHandler;

  httpRequest.get('/api/invite/' + $routeParams.hex_code + '?email=' + $routeParams.email).then(function(inviteResponse) {
    if (inviteResponse.data.accepted) {
      $location.path('/login');
    } else {
      $scope.user.email = inviteResponse.data.email;
      inviteResponseCode = inviteResponse.data.code;
    }
  });

  function userLogin() {

    userSession.setCredentials($scope.user.email, $scope.user.password);

    authenticateRequest.login().then(function(authenticateResponse) {
      userSession.setUserSessionData(authenticateResponse);
      itemsRequest.getItems();
      $location.path('/my');
    }, function(authenticateResponse) {
      $scope.errorHandler.errorMessage = authenticateResponse.data;
    });
  }

  $scope.signUp = function() {
    httpRequest.post('/api/invite/' + inviteResponseCode, {email: $scope.user.email, password: $scope.user.password}).then(function() {
      userLogin();
    });
  };
}

SignupController.$inject = ['$location', '$scope', '$routeParams', 'authenticateRequest', 'errorHandler', 'httpRequest', 'itemsRequest', 'userSession'];
angular.module('em.app').controller('SignupController', SignupController);

Check is user already signed up.


import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

moduleForComponent('zesty/time-input', 'Integration | Component | zesty/time-input', {
  integration: true
});

test('displays an input field', async function(assert) {
  await this.render(hbs`
    {{zesty/time-input
    entries=entries
    property="status"}}
  `);

  assert.equal(this.$("input").length, 1);
});

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import moment from 'moment';

moduleForComponent('zesty/time-input', 'Integration | Component | zesty/time-input', {
  integration: true
});

test('can update a moment date', async function(assert) {
  assert.expect(3);

  this.set('date', moment("2016-11-03T10:30"));
  this.set('updateDate', (date) => {
    assert.equal(moment.isMoment(date), true, "sends up a moment object");
    assert.equal(moment("2016-11-03T10:45").isSame(date), true, "has the same date");
  });

  await this.render(hbs`
    {{zesty/time-input
    value=date
    action=(action updateDate)
    entries=entries
    property="status"
    format="h.mm a"
    }}
  `);

  assert.equal(this.$("input").val(), "10.30 am");

  this.$("input").val("10.45 am");
  await this.$("input").blur();
});

test('can update a js date', async function(assert) {
  assert.expect(3);

  this.set('date', new Date(2016, 10, 3, 10, 30));
  this.set('updateDate', (date) => {
    assert.equal(moment.isDate(date), true, "sends up a moment object");
    assert.equal(moment("2016-11-03T10:45").isSame(moment(date)), true, "has the same date");
  });

  await this.render(hbs`
    {{zesty/time-input
    value=date
    action=(action updateDate)
    entries=entries
    property="status"
    format="h.mm a"
    }}
  `);

  assert.equal(this.$("input").val(), "10.30 am");

  this.$("input").val("10.45 am");
  await this.$("input").blur();
});

Add a test for the right date being set


openerp.printer_proxy = function (instance) {
    instance.printer_proxy = {};
    instance.printer_proxy.Printer  = instance.web.Class.extend({
        init: function(options){
            options = options || {};

            this.connection = new instance.web.JsonRPC();
            this.connection.setup(options.url || 'http://localhost:8069');
            this.notifications = {};
        },

        // Makes a JSON-RPC call to the local OpenERP server.
        message : function(name,params){
            var ret = new $.Deferred();
            var callbacks = this.notifications[name] || [];
            for(var i = 0; i < callbacks.length; i++){
                callbacks[i](params);
            }

            this.connection.rpc('/printer_proxy/' + name, params || {}).done(function(result) {
                ret.resolve(result);
            }).fail(function(error) {
                ret.reject(error);
            });
            return ret;
        },

        // Allows triggers to be set for when particular JSON-RPC function calls are made via 'message.'
        add_notification: function(name, callback){
            if(!this.notifications[name]){
                this.notifications[name] = [];
            }
            this.notifications[name].push(callback);
        },

        // Convenience function for sending EPL commands to the local printer.
        print_epl: function (data) {
            return this.message("print_epl", {"data": data});
        }
    });
};

openerp.printer_proxy = function (instance) {
    instance.printer_proxy = {};
    instance.printer_proxy.Printer  = instance.web.Class.extend({
        init: function(options){
            options = options || {};

            this.name = options.name || 'zebra_python_unittest';
            this.connection = new instance.web.JsonRPC();
            this.connection.setup(options.url || 'http://localhost:8069');
            this.notifications = {};
        },

        // Makes a JSON-RPC call to the local OpenERP server.
        message : function(name,params){
            var ret = new $.Deferred();
            var callbacks = this.notifications[name] || [];
            for(var i = 0; i < callbacks.length; i++){
                callbacks[i](params);
            }

            this.connection.rpc('/printer_proxy/' + name, params || {}).done(function(result) {
                ret.resolve(result);
            }).fail(function(error) {
                ret.reject(error);
            });
            return ret;
        },

        // Allows triggers to be set for when particular JSON-RPC function calls are made via 'message.'
        add_notification: function(name, callback){
            if(!this.notifications[name]){
                this.notifications[name] = [];
            }
            this.notifications[name].push(callback);
        },

        // Convenience function for sending EPL commands to the local printer.
        print_epl: function (data) {
            return this.message("print_epl", {"printer_name": this.name, "data": data});
        }
    });
};

Add 'name' option to Printer object, to specify the 'printer_name' argument sent to the client.


var webpack = require('webpack');
var precss = require('precss');
var autoprefixer = require('autoprefixer');
var TransferWebpackPlugin = require('transfer-webpack-plugin');
var path = require('path');

module.exports = {
  entry: [
    './src/js/main.js'
  ],
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader!postcss-loader' },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: ['babel'],
        query: {
          'presets': ['react', 'es2015'],
          'plugins': [
            'transform-object-rest-spread'
          ]
        }
      },
      { test: /\.svg$/, loader: 'file?name=/flags/[name].[ext]' }
    ]
  },
  postcss: function () {
    return [precss, autoprefixer({ browsers: ['> 5%'] })]
  },
  plugins: [
    new TransferWebpackPlugin([
        { from: 'img', to: 'img' }
    ], path.join(__dirname, 'src')),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ],
  resolve: {
    extensions: ['', '.js']
  },
  output: {
    path: __dirname + '/dist',
    filename: './js/model-explorer.js'
  }
}

var webpack = require('webpack');
var precss = require('precss');
var autoprefixer = require('autoprefixer');
var TransferWebpackPlugin = require('transfer-webpack-plugin');
var path = require('path');

module.exports = {
  entry: [
    './src/js/main.js'
  ],
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader!postcss-loader' },
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: ['babel'],
        query: {
          'presets': ['react', 'es2015'],
          'plugins': [
            'transform-object-rest-spread'
          ]
        }
      },
      { test: /\.svg$/, loader: 'file?name=/flags/[name].[ext]' }
    ]
  },
  postcss: function () {
    return [precss, autoprefixer({ browsers: ['> 0%', 'IE 9'] })]
  },
  plugins: [
    new TransferWebpackPlugin([
        { from: 'img', to: 'img' }
    ], path.join(__dirname, 'src')),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': JSON.stringify('production')
      }
    })
  ],
  resolve: {
    extensions: ['', '.js']
  },
  output: {
    path: __dirname + '/dist',
    filename: './js/model-explorer.js'
  }
}

Fix layout issue on IE 10 in production


/*****************************************************************************/
/* PageSettings: Event Handlers and Helpersss .js*/
/*****************************************************************************/
Template.PageSettings.events({
  /*
   * Example:
   *  'click .selector': function (e, tmpl) {
   *
   *  }
   */
  'click #cancel-page-settings': function (e) {
    e.preventDefault();

    Session.set('pageSettings', null);
  },

  'submit #page-slug': function (e, tmpl) {
    e.preventDefault();

    var slug = tmpl.find('#pageSlug').value;

    Pages.update({ _id: this._id }, {
      $set: { slug: slug }
    });
    App.setAlert('Added a new page slug.', 'success');
  }
});

Template.PageSettings.helpers({
  /*
   * Example:
   *  items: function () {
   *    return Items.find();
   *  }
   */
});

/*****************************************************************************/
/* PageSettings: Lifecycle Hooks */
/*****************************************************************************/
Template.PageSettings.created = function () {
};

Template.PageSettings.rendered = function () {
};

Template.PageSettings.destroyed = function () {
};

/*****************************************************************************/
/* PageSettings: Event Handlers and Helpersss .js*/
/*****************************************************************************/
Template.PageSettings.events({
  /*
   * Example:
   *  'click .selector': function (e, tmpl) {
   *
   *  }
   */
  'click #cancel-page-settings': function (e) {
    e.preventDefault();

    Session.set('pageSettings', null);
  },

  'submit #page-slug': function (e, tmpl) {
    e.preventDefault();

    var slug = tmpl.find('#pageSlug').value;

    if (slug.length > 0) {
      Pages.update({ _id: this._id }, {
        $set: { slug: slug }
      });
      App.setAlert('Added a new page slug.', 'success');
    } else {
      Pages.update({ _id: this._id }, {
        $unset: { slug: '' }
      });
      App.setAlert('Removed page slug.', 'success');
    }
  }
});

Template.PageSettings.helpers({
  /*
   * Example:
   *  items: function () {
   *    return Items.find();
   *  }
   */
});

/*****************************************************************************/
/* PageSettings: Lifecycle Hooks */
/*****************************************************************************/
Template.PageSettings.created = function () {
};

Template.PageSettings.rendered = function () {
};

Template.PageSettings.destroyed = function () {
};

Make a difference between add slug and remove slug


import {Dropdown} from 'reactjs-components';
import React from 'react';

class UserAccountDropdown extends React.Component {
  handleItemSelection(item) {
    if (item.onClick) {
      item.onClick();
    }
  }

  render() {
    return (
      <Dropdown buttonClassName="user-account-dropdown-button"
        dropdownMenuClassName="user-account-dropdown-menu dropdown-menu"
        dropdownMenuListClassName="user-account-dropdown-list dropdown-menu-list"
        items={this.props.menuItems}
        onItemSelection={this.handleItemSelection}
        persistentID="dropdown-trigger"
        transition={true}
        wrapperClassName="user-account-dropdown dropdown header flex-item-shrink-0" />
    );
  }
};

module.exports = UserAccountDropdown;

import {Dropdown} from 'reactjs-components';
import React from 'react';

class UserAccountDropdown extends React.Component {
  handleItemSelection(item) {
    if (item.onClick) {
      item.onClick();
    }
  }

  render() {
    return (
      <Dropdown buttonClassName="user-account-dropdown-button text-no-transform"
        dropdownMenuClassName="user-account-dropdown-menu dropdown-menu"
        dropdownMenuListClassName="user-account-dropdown-list dropdown-menu-list"
        items={this.props.menuItems}
        onItemSelection={this.handleItemSelection}
        persistentID="dropdown-trigger"
        transition={true}
        wrapperClassName="user-account-dropdown dropdown header flex-item-shrink-0" />
    );
  }
};

module.exports = UserAccountDropdown;

Remove text transformation on user account dropdown button


var endpoint = require('../../lib/endpoint')
  , driver = require('../../lib/drivers/base')
  , io = require('../mocks/io').new();

module.exports = endpoint;

module.exports.make = function(props) {
  props = props || {};
  return new endpoint({
    'type': props.type || 'blergh',
    'id'  : props.id || 'endpoint_' + Math.floor(Math.random() * 100),
    'driver': props.driver || new driver(io)
  });
};

var endpoint = require('../../lib/endpoint');

function driver() {
  return require("../../lib/drivers/base").new(
    require('../mocks/io').new(true)
  );
}

module.exports = endpoint;

module.exports.make = function(props) {
  props = props || {};
  return new endpoint({
    'type': props.type || 'blergh',
    'id'  : props.id || 'endpoint_' + Math.floor(Math.random() * 1000),
    'driver': props.driver || driver()
  });
};

Fix bug whereby all blueprint Endpoints shared a driver


angular.module('rosieApp', [
  'ui.router',
  'rosieApp.layout',
  'rosieApp.lights',
  'rosieApp.remotes',
  'rosieApp.tasks'
])
  .run(function($rootScope) {
    $rootScope.$on("$stateChangeError", console.log.bind(console));
  })

Print routing errors to console


/** @ngInject */
export function SaveModalDialogFactory($uibModal) {
  var modalSaveDialog = {
    showModal: showModal,
  };

  return modalSaveDialog;

  function showModal(saveCallback, doNotSaveCallback, cancelCallback, okToSave) {
    var modalOptions = {
      templateUrl: 'app/components/save-modal-dialog/save-modal-dialog.html',
      controller: SaveModalDialogController,
      controllerAs: 'vm',
      resolve: {
        saveCallback: resolveSave,
        doNotSaveCallback: resolveDoNotSave,
        cancelCallback: resolveCancel,
        okToSave: resolveOkToSave,
      },
    };

    function resolveSave() {
      return saveCallback;
    }

    function resolveDoNotSave() {
      return doNotSaveCallback;
    }

    function resolveCancel() {
      return cancelCallback;
    }
    function resolveOkToSave() {
      return okToSave;
    }
    var modal = $uibModal.open(modalOptions);

    return modal.result;
  }
}

/** @ngInject */
function SaveModalDialogController(saveCallback, doNotSaveCallback, cancelCallback, okToSave, $uibModalInstance) {
  var vm = this;
  vm.save = save;
  vm.doNotSave = doNotSave;
  vm.cancel = cancel;
  vm.okToSave = okToSave;

  function save() {
    saveCallback();
    $uibModalInstance.close();
  }

  function doNotSave() {
    doNotSaveCallback();
    $uibModalInstance.close();
  }

  function cancel() {
    cancelCallback();
    $uibModalInstance.close();
  }
}

import templateUrl from './save-modal-dialog.html';

/** @ngInject */
export function SaveModalDialogFactory($uibModal) {
  var modalSaveDialog = {
    showModal: showModal,
  };

  return modalSaveDialog;

  function showModal(saveCallback, doNotSaveCallback, cancelCallback, okToSave) {
    var modalOptions = {
      templateUrl,
      controller: SaveModalDialogController,
      controllerAs: 'vm',
      resolve: {
        saveCallback: resolveSave,
        doNotSaveCallback: resolveDoNotSave,
        cancelCallback: resolveCancel,
        okToSave: resolveOkToSave,
      },
    };

    function resolveSave() {
      return saveCallback;
    }

    function resolveDoNotSave() {
      return doNotSaveCallback;
    }

    function resolveCancel() {
      return cancelCallback;
    }

    function resolveOkToSave() {
      return okToSave;
    }

    var modal = $uibModal.open(modalOptions);

    return modal.result;
  }
}

/** @ngInject */
function SaveModalDialogController(saveCallback, doNotSaveCallback, cancelCallback, okToSave, $uibModalInstance) {
  var vm = this;
  vm.save = save;
  vm.doNotSave = doNotSave;
  vm.cancel = cancel;
  vm.okToSave = okToSave;

  function save() {
    saveCallback();
    $uibModalInstance.close();
  }

  function doNotSave() {
    doNotSaveCallback();
    $uibModalInstance.close();
  }

  function cancel() {
    cancelCallback();
    $uibModalInstance.close();
  }
}

Save modal dialog now correctly imports html template


import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { settingsLive } from './collections';
import defaultSettings from './defaultSettings';
import { checkSiteIdOwnership, checkUserLoggedIn } from '../utils';

Meteor.methods({
  saveSettings(settings) {
    const userId = this.userId;
    const name = settings.woronaInfo.name;
    const siteId = settings.woronaInfo.siteId;

    check(name, String);
    check(siteId, String);
    checkUserLoggedIn(userId);
    checkSiteIdOwnership(siteId, userId);

    const newSettingData = {};
    Object.assign(newSettingData, settings);
    delete newSettingData.woronaInfo;

    const id = settingsLive.findOne({ 'woronaInfo.name': name, 'woronaInfo.siteId': siteId })._id;

    return settingsLive.update(id, { $set: newSettingData });
  },

  initSettings(siteId) {
    check(siteId, String);
    defaultSettings.forEach(setting => {
      const woronaInfo = Object.assign({}, setting.woronaInfo, { siteId });
      settingsLive.insert(Object.assign({}, setting, { woronaInfo }));
    });
  },
});

import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { settingsLive } from './collections';
import defaultSettings from './defaultSettings';
import { checkSiteIdOwnership, checkUserLoggedIn } from '../utils';

Meteor.methods({
  saveSettings(settings) {
    const userId = this.userId;
    const name = settings.woronaInfo.name;
    const siteId = settings.woronaInfo.siteId;

    check(name, String);
    check(siteId, String);
    checkUserLoggedIn(userId);
    checkSiteIdOwnership(siteId, userId);

    const newSettingData = {};
    Object.assign(newSettingData, settings);
    delete newSettingData.woronaInfo;
    newSettingData['woronaInfo.init'] = true;

    const id = settingsLive.findOne({ 'woronaInfo.name': name, 'woronaInfo.siteId': siteId })._id;

    return settingsLive.update(id, { $set: newSettingData });
  },

  initSettings(siteId) {
    check(siteId, String);
    defaultSettings.forEach(setting => {
      const woronaInfo = Object.assign({}, setting.woronaInfo, { siteId });
      settingsLive.insert(Object.assign({}, setting, { woronaInfo }));
    });
  },
});

Change 'init' to true on each save.


function noop(){}

module.exports = function(ws) {
  let isAlive = true;

  ws.on('pong', () => isAlive = true);

  setInterval(function ping() {
    if(!isAlive) return ws.terminate();

    isAlive = false;
    ws.ping(noop);
  }, 15000);
};

function noop(){}

module.exports = function(ws) {
  let awake = true;

  ws.on('pong', () => awake = true);

  const id = setInterval(function ping() {
    if(!awake) return isAlive() && ws.terminate();

    awake = false;
    isAlive() && ws.ping(noop);
  }, 15000);

  function isAlive() {
    if(ws.readyState === ws.OPEN || ws.readyState === ws.CONNECTING) {
      return true;
    }
    clearInterval(id);
    return false;
  }
};

Stop ping when client is not open


import Component from '@ember/component';
import { computed } from '@ember/object';

export default Component.extend({
  classNames: ['rl-dropdown-toggle'],

  tagName: 'button',

  attributeBindings: ['type', 'role', 'disabled'],

  type: computed('tagName', function() {
    return this.tagName === 'button' ? 'button' : null;
  }),

  role: computed('tagName', function() {
    return this.tagName === 'a' ? 'button' : null;
  }),

  disabled: false,

  click() {
    if (!this.disabled) {
      this.toggle();
    }
  },
});

import Component from '@ember/component';
import { computed } from '@ember/object';

export default Component.extend({
  tagName: 'button',

  attributeBindings: ['type', 'role', 'disabled'],

  type: computed('tagName', function() {
    return this.tagName === 'button' ? 'button' : null;
  }),

  role: computed('tagName', function() {
    return this.tagName === 'a' ? 'button' : null;
  }),

  disabled: false,

  click() {
    if (!this.disabled) {
      this.toggle();
    }
  },
});

Remove unused `.rl-dropdown-toggle` CSS class assignment


'use strict';

angular.module('ddsApp').directive('ddsDateMonthYear', function() {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
            ctrl.$parsers.push(function(viewValue) {
                var result = moment(viewValue, ['MM/YY', 'MM/YYYY', 'MMMM YYYY', 'L', 'DD/MM/YY']);

                ctrl.$setValidity('ddsDateMonthYear', result.isValid());

                return result;
            });

            ctrl.$formatters.push(function(momentInstance) {
                if (! momentInstance) return;

                return momentInstance.format('MMM YYYY');
            });
        }
    };
});

'use strict';

angular.module('ddsApp').directive('ddsDateMonthYear', function() {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
            ctrl.$parsers.push(function(viewValue) {
                var result = moment(viewValue, ['MM/YY', 'MM/YYYY', 'MMMM YYYY', 'L', 'DD/MM/YY']);

                ctrl.$setValidity('ddsDateMonthYear', result.isValid());

                return result;
            });

            ctrl.$formatters.push(function(momentInstance) {
                if (! momentInstance) return;

                return momentInstance.format('MM/YYYY');
            });
        }
    };
});

Format parsed month-year inputs as unambiguous data format for input


"use strict";

annotationApp.directive('formSelector', function() {
  return {
    restrict: 'E',
    replace: true,
    controller: function($scope, $element, $attrs) {
      var id = $scope.id;
      var form = $scope.form;
      $scope.text = 'Select';
      $scope.action = function() {
        if ($scope.plugin.isFormSelected(id, form)) {
          $scope.text = "Select";
          $scope.plugin.unsetState(id);
        } else {
          $scope.text = "Deselect";
          $scope.plugin.setState(id, form);
        }
      };
    },
    template: '{{ text }}'
  };

});

"use strict";

annotationApp.directive('formSelector', function() {
  return {
    restrict: 'E',
    replace: true,
    controller: function($scope, $element, $attrs) {
      var id = $scope.id;
      var form = $scope.form;
      $scope.text = 'Select';
      $scope.action = function(event) {
        event.stopPropagation();
        if ($scope.plugin.isFormSelected(id, form)) {
          $scope.text = "Select";
          $scope.plugin.unsetState(id);
        } else {
          $scope.text = "Deselect";
          $scope.plugin.setState(id, form);
        }
      };
    },
    template: '{{ text }}'
  };

});

Stop event propagation in form-selector


import {homedir} from 'os';

import settings from 'electron-settings';
import objectPath from 'object-path';

const DEFAULTS = {
  kapturesDir: `${homedir()}/Movies/Kaptures`,
  openOnStartup: false,
  allowAnalytics: true,
  showCursor: true,
  highlightClicks: false,
  fps: 30
};

const volatiles = {
  cropperWindow: {
    size: {
      width: 512,
      height: 512
    },
    position: {
      x: 'center',
      y: 'center'
    }
  }
};

function init() {
  settings.defaults(DEFAULTS);
  settings.applyDefaultsSync();
}

function get(key) {
  return objectPath.get(volatiles, key) || settings.getSync(key);
}

function getAll() {
  return Object.assign({}, volatiles, settings.getSync());
}

function set(key, value, {volatile = false} = {}) {
  if (volatile) {
    return objectPath.set(volatiles, key, value);
  }
  settings.setSync(key, value);
}

export {init, get, getAll, set};

import {homedir} from 'os';

import settings from 'electron-settings';
import objectPath from 'object-path';

const DEFAULTS = {
  kapturesDir: `${homedir()}/Movies/Kaptures`,
  openOnStartup: false,
  allowAnalytics: true,
  showCursor: true,
  highlightClicks: false,
  fps: 30,
  sound: false
};

const volatiles = {
  cropperWindow: {
    size: {
      width: 512,
      height: 512
    },
    position: {
      x: 'center',
      y: 'center'
    }
  }
};

function init() {
  settings.defaults(DEFAULTS);
  settings.applyDefaultsSync();
}

function get(key) {
  return objectPath.get(volatiles, key) || settings.getSync(key);
}

function getAll() {
  return Object.assign({}, volatiles, settings.getSync());
}

function set(key, value, {volatile = false} = {}) {
  if (volatile) {
    return objectPath.set(volatiles, key, value);
  }
  settings.setSync(key, value);
}

export {init, get, getAll, set};

Add `sound` to the default settings


/**
 * Main entrypoint for banknote.
 *
 * Copyright 2015 Ethan Smith
 */

var Backbone = require('backbone'),
    Marionette = require('backbone.marionette'),
    $ = require('jquery'),
    _ = require('underscore'),

    // Config
    layout = require('./src/layout.js'),

    // Controller
    PrimaryDisplayController = require('./src/controller/PrimaryDisplayController'),

    // View
    MainLayout = require('./src/view/MainLayout'),
    WelcomeScreen = require('./src/view/WelcomeScreen'),
    RegionModal = require('./src/common/modal/RegionModal.js');

require('./src/common/library/CurrencyInputStyler');

var Banknote = new Marionette.Application();

Banknote.addRegions({
   central: '#app',
   modal: RegionModal
});

Banknote.addInitializer(function(options) {
   var mainLayout = new MainLayout(),
       welcomeScreen = new WelcomeScreen();

   Banknote.central.show(mainLayout);

   // Present welcome screen
   mainLayout.elements.show(welcomeScreen);
});

Banknote.start();

// Make Banknote available globally
global.Banknote = Banknote;

/**
 * Main entrypoint for banknote.
 *
 * Copyright 2015 Ethan Smith
 */

var Backbone = require('backbone'),
    Marionette = require('backbone.marionette'),
    $ = require('jquery'),
    _ = require('underscore'),

    // Config
    layout = require('./src/layout.js'),

    // Controller
    PrimaryDisplayController = require('./src/controller/PrimaryDisplayController'),

    // View
    MainLayout = require('./src/view/MainLayout'),
    WelcomeScreen = require('./src/view/WelcomeScreen'),
    RegionModal = require('./src/common/modal/RegionModal.js');

require('./src/common/library/CurrencyInputStyler');

var Banknote = new Marionette.Application();

Banknote.addRegions({
   central: '#app',
   modal: RegionModal
});

Banknote.addInitializer(function(options) {
   var mainLayout = new MainLayout(),
       welcomeScreen = new WelcomeScreen();

   Banknote.central.show(mainLayout);

   welcomeScreen.on('click:newsheet', function() {
      $.getJSON('demo.json', function(data) {
         var controller = new PrimaryDisplayController(),
             layoutView = controller.render(data);

         mainLayout.elements.show(layoutView);
      });
   });

   // Present welcome screen
   mainLayout.elements.show(welcomeScreen);
});

Banknote.start();

// Make Banknote available globally
global.Banknote = Banknote;

Load demo on new sheet click


  System.import('./test.jade!')
    .then(function(fn) {
    document.body.innerHTML = fn({local: 'no'});
    })
    .catch(function(err) {
      console.log('ERROR: ', err);
    });

import fn from './test.jade!';

document.body.innerHTML = fn('no');

Use import statement to convert jade template during bundle


'use strict';

// Load environment variables.
require('dotenv').load();

var shell = require('shelljs');
var settings = require('./settings');

// Generate settings.json file.
shell.echo(JSON.stringify(settings)).to('settings.json');

// Copy settings.json file to root directory of etherpad.
shell.mv('-f', 'settings.json', './codeaux-etherpad/');

// Execute etherpad server.
if (shell.exec('bash ./codeaux-etherpad/bin/run.sh').code !== 0) {
  shell.echo('Error: codeaux-etherpad not found');
  shell.exit(1);
}

'use strict';

// Load local environment variables (Uncomment this when doing development locally).
//require('dotenv').load();

var shell = require('shelljs');
var settings = require('./settings');

// Generate settings.json file.
shell.echo(JSON.stringify(settings)).to('settings.json');

// Copy settings.json file to root directory of etherpad.
shell.mv('-f', 'settings.json', './codeaux-etherpad/');

// Execute etherpad server.
if (shell.exec('bash ./codeaux-etherpad/bin/run.sh').code !== 0) {
  shell.echo('Error: codeaux-etherpad not found');
  shell.exit(1);
}

Comment library that is only required when doing development locally.


var CityDashboard = {
  mainContainerID: '#city-dashboard',
  mapWindowID: '#mapWindow',
  infoWindowID: '#infoWindow',
  filterBarID: '#filterBar',
  getData: function ( url, callback, props ) {
    if ( url.charAt(0) !== '#' ){
      $.getJSON(url,function( json ){
        props.data = json;
        return callback( props );
      });
    }
    else {
      return callback( props );
    }
  }
};

var CityDashboard = (function($) {
    "use strict";

    return {
        mainContainerID: '#city-dashboard',
        mapWindowID: '#mapWindow',
        infoWindowID: '#infoWindow',
        filterBarID: '#filterBar',

        /**
         * Get the data for the dashboard
         *
         * @param {String} uri uri or id for the data source
         * @param {Callback} callback function to pass the data to
         * @param {Object} mapping of properties to pass to the callback
         * @return {Object} result for the callback
         */
        getData: function(uri, callback, props) {
            if (uri.charAt(0) !== '#') {
                $.getJSON(uri, function(json) {
                    props.data = json;

                    // TODO: The return value of callback is never used
                    return callback(props);
                });
            } else {
                return callback(props);
            }
        }
    };
})(jQuery);

Convert CityDasbhboard to the module pattern


var mapnik = require('mapnik');

function Renderer(color, options) {
    this.color = color || '#ffffff';

    this.options = options || {};
    this.options.tileSize = this.options.tileSize || 256;
    this.options.format = this.options.format || 'png8:m=h';

    this.cachedTile = null;
}

module.exports = Renderer;

Renderer.prototype.getTile = function(z, x, y, callback) {
    var self = this;

    if (this.cachedTile !== null) {
        return callback(null, buffer);
    }

    var image = new mapnik.Image(this.options.tileSize, this.options.tileSize);
    image.background = new mapnik.Color(this.color);

    image.encode(this.options.format, function(err, buffer) {
        if (err) {
            return callback(err);
        }

        self.cachedTile = buffer;

        return callback(null, buffer);
    });
};

var mapnik = require('mapnik');

function Renderer(color, options) {
    this.color = color || '#ffffff';

    this.options = options || {};
    this.options.tileSize = this.options.tileSize || 256;
    this.options.format = this.options.format || 'png8:m=h';

    this.cachedTile = null;
}

module.exports = Renderer;

Renderer.prototype.getTile = function(z, x, y, callback) {
    var self = this;

    if (this.cachedTile !== null) {
        return callback(null, this.cachedTile);
    }

    var image = new mapnik.Image(this.options.tileSize, this.options.tileSize);
    image.background = new mapnik.Color(this.color);

    image.encode(this.options.format, function(err, buffer) {
        if (err) {
            return callback(err);
        }

        self.cachedTile = buffer;

        return callback(null, buffer);
    });
};

Return the proper cached object


var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {

    if (!req.user) {
	res.render('login', { title: 'Express',
			      ui_language: req.ui_language,
			      error_message: req.flash('error'),
			      success_message: req.flash('error'),
			    });
    }
    else {
	if (req.user.role == 'user') {
            res.redirect('/test');
	}
	if (req.user.role == 'teacher') {
            res.redirect('/users');
	}
	else {
	    res.render('index', {  title: 'User management',
				   username: req.user.username ,
				   user: req.user,
				   ui_language: req.ui_language,
				   error_message: req.flash('error'),
				   success_message: req.flash('error')
				});
	}
    }

    //res.render('index', { title: 'Express', message : req.flash('info') });
});

router.post('/api/photo',function(req,res){
  if(done==true){
    console.log(req.files);
    res.end("File uploaded.");
  }
});

module.exports = router;

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {

    if (!req.user) {
	res.render('login', { title: 'Express',
			      ui_language: req.ui_language,
			      error_message: req.flash('error'),
			      success_message: req.flash('error'),
			    });
    }
    else {
	if (req.user.role == 'user') {
            res.redirect('/test');
	}
	else {
	    res.render('index', {  title: 'User management',
				   username: req.user.username ,
				   user: req.user,
				   ui_language: req.ui_language,
				   error_message: req.flash('error'),
				   success_message: req.flash('error')
				});
	}
    }

    //res.render('index', { title: 'Express', message : req.flash('info') });
});

router.post('/api/photo',function(req,res){
  if(done==true){
    console.log(req.files);
    res.end("File uploaded.");
  }
});

module.exports = router;

Test view allowed for also teachers


import React from 'react';
import IconCheckbox from '@ichef/gypcrete/src/IconCheckbox';

import FlexRow from 'utils/FlexRow';

export default {
    title: '@ichef/gypcrete|IconCheckbox',
    component: IconCheckbox
};

export function BasicUsage() {
    return (
        <FlexRow>
            <IconCheckbox />

            <IconCheckbox indeterminate />
        </FlexRow>
    );
}

export function WithStatus() {
    return (
        <FlexRow>
            <IconCheckbox
                defaultChecked
                status="loading" />

            <IconCheckbox
                status="success"
                statusOptions={{ autohide: false }} />

            <IconCheckbox
                status="error"
                errorMsg="Cannot add printer." />
        </FlexRow>
    );
}

import React from 'react';
import Checkbox from '@ichef/gypcrete/src/Checkbox';
import IconCheckbox from '@ichef/gypcrete/src/IconCheckbox';

import FlexRow from 'utils/FlexRow';

export default {
    title: '@ichef/gypcrete|IconCheckbox',
    component: IconCheckbox,
    subcomponents: {
        Checkbox,
    },
};

export function BasicUsage() {
    return (
        <FlexRow>
            <IconCheckbox />

            <IconCheckbox indeterminate />
        </FlexRow>
    );
}

export function WithStatus() {
    return (
        <FlexRow>
            <IconCheckbox
                defaultChecked
                status="loading" />

            <IconCheckbox
                status="success"
                statusOptions={{ autohide: false }} />

            <IconCheckbox
                status="error"
                errorMsg="Cannot add printer." />
        </FlexRow>
    );
}

Add Checkbox into IconCheckbox storybook subcomponents


requirejs.config({
    baseUrl: "js",
    urlArgs: '_=' + (new Date()).getTime(),
    paths: {
        jquery: 'libs/jquery',
        elasticsearch: 'libs/elasticsearch',
        d3: 'libs/d3',
        d3pie: 'libs/d3pie',
        d3tip: 'libs/index',
        nv: 'libs/nv.d3',
        app: 'app'
    },
    shim: {
        d3tip: {
            deps: ['d3'],
            exports: 'd3tip'
        },
        d3pie: {
            deps: ['d3'],
            exports: 'd3pie'
        },
        nv: {
            deps: ['d3'],
            exports: 'nv'
        }
    }
});

require(['app']);

requirejs.config({
    baseUrl: "js",
    waitSeconds: 60,
    urlArgs: '_=' + (new Date()).getTime(),
    paths: {
        jquery: 'libs/jquery',
        elasticsearch: 'libs/elasticsearch',
        d3: 'libs/d3',
        d3pie: 'libs/d3pie',
        d3tip: 'libs/index',
        nv: 'libs/nv.d3',
        app: 'app'
    },
    shim: {
        d3tip: {
            deps: ['d3'],
            exports: 'd3tip'
        },
        d3pie: {
            deps: ['d3'],
            exports: 'd3pie'
        },
        nv: {
            deps: ['d3'],
            exports: 'nv'
        }
    }
});

require(['app']);

Increase requirejs timeout to 60s


import * as THREE from 'three';
import PropTypes from 'prop-types';

import GeometryDescriptorBase from './GeometryDescriptorBase';
import propTypeInstanceOf from '../../utils/propTypeInstanceOf';

class BufferGeometryDescriptor extends GeometryDescriptorBase {
  constructor(react3RendererInstance) {
    super(react3RendererInstance);

    [
      'vertices',
      'colors',
      'faceVertexUvs',
      'faces',
      'dynamic',
    ].forEach((propName) => {
      this.removeProp(propName);
    });

    [
      'position',
      'normal',
      'color',
      'uv',
    ].forEach((attributeName) => {
      this.hasProp(attributeName, {
        type: PropTypes.oneOfType([
          propTypeInstanceOf(THREE.BufferAttribute),
          propTypeInstanceOf(THREE.InterleavedBufferAttribute),
        ]),
        update(threeObject, attributeValue) {
          if (attributeValue) {
            threeObject.addAttribute(attributeName, attributeValue);
          } else {
            threeObject.removeAttribute(attributeName);
          }
        },
        updateInitial: true,
        default: undefined,
      });
    });

    this.hasProp('index', {
      type: PropTypes.oneOfType([
        propTypeInstanceOf(THREE.BufferAttribute),
        propTypeInstanceOf(THREE.InterleavedBufferAttribute),
      ]),
      update(threeObject, attributeValue) {
        threeObject.setIndex(attributeValue);
      },
      updateInitial: true,
      default: undefined,
    });
  }

  construct() {
    return new THREE.BufferGeometry();
  }
}

module.exports = BufferGeometryDescriptor;

import * as THREE from 'three';
import PropTypes from 'prop-types';

import GeometryDescriptorBase from './GeometryDescriptorBase';
import propTypeInstanceOf from '../../utils/propTypeInstanceOf';

class BufferGeometryDescriptor extends GeometryDescriptorBase {
  constructor(react3RendererInstance) {
    super(react3RendererInstance);

    [
      'vertices',
      'colors',
      'faceVertexUvs',
      'faces',
      'dynamic',
    ].forEach((propName) => {
      this.removeProp(propName);
    });

    [
      'position',
      'normal',
      'color',
      'uv',
    ].forEach((attributeName) => {
      this.hasProp(attributeName, {
        type: PropTypes.oneOfType([
          propTypeInstanceOf(THREE.BufferAttribute),
          propTypeInstanceOf(THREE.InterleavedBufferAttribute),
        ]),
        update(threeObject, attributeValue) {
          if (attributeValue) {
            threeObject.addAttribute(attributeName, attributeValue);
          } else {
            threeObject.removeAttribute(attributeName);
          }
        },
        updateInitial: true,
        default: undefined,
      });
    });

    this.hasProp('index', {
      type: PropTypes.oneOfType([
        propTypeInstanceOf(THREE.BufferAttribute),
        propTypeInstanceOf(THREE.InterleavedBufferAttribute),
      ]),
      update(threeObject, attributeValue) {
        threeObject.setIndex(attributeValue);
      },
      updateInitial: true,
      default: null,
    });
  }

  construct() {
    return new THREE.BufferGeometry();
  }
}

module.exports = BufferGeometryDescriptor;

Replace undefined with null as default for index for BufferGeometry


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

module.exports = {
  parser: 'babel-eslint',
  extends: [
    'airbnb',
    'plugin:flowtype/recommended',
    'prettier',
    'prettier/flowtype',
    'prettier/react',
  ],
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  plugins: ['flowtype'],
  rules: {
    // import
    'import/prefer-default-export': 'off', // conflict when there is only 1 action

    // jsx-a11y
    'jsx-a11y/anchor-is-valid': 'off',

    // react
    'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx'] }],
  },
  settings: {
    'import/resolver': {
      node: {
        paths: [paths.appMain, paths.appResources],
      },
    },
  },
};

module.exports = {
  parser: 'babel-eslint',
  extends: [
    'airbnb',
    'plugin:flowtype/recommended',
    'prettier',
    'prettier/flowtype',
    'prettier/react',
  ],
  env: {
    browser: true,
    node: true,
    es6: true,
  },
  plugins: ['flowtype'],
  rules: {
    // import
    'import/prefer-default-export': 'off', // conflict when there is only 1 action

    // jsx-a11y
    'jsx-a11y/anchor-is-valid': 'off',

    // react
    'react/jsx-filename-extension': ['error', { extensions: ['.js', '.jsx'] }],
  },
  settings: {
    'import/resolver': {
      node: {
        moduleDirectory: ['node_modules', 'app'],
      },
    },
  },
};

Use moduleDirectory instead of paths for import/resolver


var express = require('express');
var router = express.Router();
var nodemailer = require('nodemailer');

// create reusable transporter object using the default SMTP transport
var smtp = process.env.SMTPCREDENTIALS || '';
var transporter = nodemailer.createTransport(smtp);

var SECRET = process.env.SPASECRET || '';

router.post('/deliverforme', function(req, res, next) {
  if (req.body.key !== SECRET) { res.status(400).send(); }

  var data = req.body;
  var sended_at = new Date(data.timestamp);
  var received_at = new Date(Date.now());

  var message = [data['form[content]'],
                  "\n\nEnviado em ",
                  sended_at.toString(),
                  ". Processado em ",
                  received_at.toString()
                ].join(' ');

  var mailOptions = {
    to: 'kenner.hp@gmail.com',
    from: [data['form[name]'],"<",data['form[email]'],">"].join(' '),
    subject: data['form[subject]'],
    text: message
  };

  transporter.sendMail(mailOptions, function(error, info){
    if(error){
        res.status(403).send(error);
    }
    res.send(info.response);
  });
});

module.exports = router;

var express = require('express');
var router = express.Router();
var nodemailer = require('nodemailer');

// create reusable transporter object using the default SMTP transport
var smtp = process.env.SMTPCREDENTIALS || '';
var transporter = nodemailer.createTransport(smtp);

var SECRET = process.env.SPASECRET || '';

router.post('/deliverforme', function(req, res, next) {
  var data = req.body;

  if (data.key !== SECRET) { res.status(400).send(); }

  var sended_at = new Date(data.timestamp);
  var received_at = new Date(Date.now());

  var message = [data['form[content]'],
                  "\n\nEnviado em ",
                  sended_at.toString(),
                  ". Processado em ",
                  received_at.toString()
                ].join(' ');

  var mailOptions = {
    to: 'kenner.hp@gmail.com',
    from: [data['form[name]'],"<",data['form[email]'],">"].join(' '),
    subject: data['form[subject]'],
    text: message
  };

  transporter.sendMail(mailOptions, function(error, info){
    if(error){
        res.status(403).send(error);
    }
    res.send(info.response);
  });
});

module.exports = router;

Move conditional to chached data


class LoadingController {
  constructor($log, $scope, $state, $interval, SocketService, GameService) {
    'ngInject';

    this.$log = $log;
    this.$state = $state;
    this.$interval = $interval;
    this.GameService = GameService;
    this.SocketService = SocketService;

    this.waitTime = 5000;
    this.animTime = 850;
    this.ellipsis = '.';

    $scope.$on('server_disconnect', function(event, args) {
      alert('Server disconnected. Game ended.');
      $state.go('home');
    });

    this.setAnimation();
    this.setGameAssetChecker(this.waitTime);
  }

  setAnimation() {
    this.$interval(() => this.changeEllipsis(), this.animTime, 0, true);
  }

  setGameAssetChecker(waitTime) {
    this.$interval(() => this.checkAssets(), waitTime, 1, true);
  }

  changeEllipsis() {
    this.ellipsis += '.';

    if (this.ellipsis.length > 3) {
      this.ellipsis = '.';
    }
  }

  checkAssets() {
    if (this.GameService.isGameReady()) {
      this.$log.log('Game ready');
      this.$state.go('game');
      //TODO: send the info to devices
    } else {
      this.$log.log('Game not ready yet');
      this.setGameAssetChecker(1000);
    }
  }
}

export default LoadingController;

class LoadingController {
  constructor($log, $scope, $state, $interval, SocketService, GameService) {
    'ngInject';

    this.$log = $log;
    this.$state = $state;
    this.$interval = $interval;
    this.GameService = GameService;
    this.SocketService = SocketService;

    this.waitTime = 5000;
    this.animTime = 850;
    this.ellipsis = '.';

    $scope.$on('server_disconnect', function(event, args) {
      alert('Server disconnected. Game ended.');
      $state.go('home');
    });

    this.setAnimation();
    this.setGameAssetChecker(this.waitTime);
  }

  setAnimation() {
    this.$interval(() => this.changeEllipsis(), this.animTime, 0, true);
  }

  setGameAssetChecker(waitTime) {
    this.$interval(() => this.checkAssets(), waitTime, 1, true);
  }

  changeEllipsis() {
    this.ellipsis += '.';

    if (this.ellipsis.length > 3) {
      this.ellipsis = '.';
    }
  }

  checkAssets() {
    if (this.GameService.isGameReady()) {
      this.$log.log('Game ready');
      this.$state.go('game');
      this.SocketService.send({
        type: 'game_ready',
        role: 'owner'
      });
    } else {
      this.$log.log('Game not ready yet');
      this.setGameAssetChecker(1000);
    }
  }
}

export default LoadingController;

Send game_ready to players when game is ready


/* global django */
/* eslint indent:[2,4] */
/* eslint comma-dangle:[2,"never"] */
django.jQuery(function($){
    var context = document.getElementById('admin-ordering-context');
    if (!context) return;

    var data = JSON.parse(context.getAttribute('data-context'));

    if (data.tabular) {
        $('#' + data.prefix + '-group tbody').sortable({
            update: function(event, ui) {
                $('.dynamic-' + data.prefix).each(function(index) {
                    var row = $(this);
                    row.find('.field-' + data.field + ' input').val(10 * (index + 1));
                    row.removeClass('row1 row2').addClass((index % 2) ? 'row2' : 'row1');
                });
            }
        });
    } else if (data.stacked) {
        $('#' + data.prefix + '-group').sortable({
            items: '>.inline-related',
            update: function(event, ui) {
                $('.dynamic-' + data.prefix).each(function(index) {
                    var row = $(this);
                    row.find('.field-' + data.field + ' input').val(10 * (index + 1));
                    row.removeClass('row1 row2').addClass((index % 2) ? 'row2' : 'row1');
                });
            }
        });
    }
});

/* global django */
/* eslint indent:[2,4] */
/* eslint comma-dangle:[2,"never"] */
django.jQuery(function($){
    var context = document.getElementById('admin-ordering-context');
    if (!context) return;

    var data = JSON.parse(context.getAttribute('data-context'));

    if (data.tabular) {
        $('#' + data.prefix + '-group tbody').sortable({
            update: function(event, ui) {
                $('.dynamic-' + data.prefix).each(function(index) {
                    var row = $(this);
                    row.find('.field-' + data.field + ' input').val(10 * (index + 1));
                    row.removeClass('row1 row2').addClass((index % 2) ? 'row2' : 'row1');
                });
            }
        });
    } else if (data.stacked) {
        $('#' + data.prefix + '-group').sortable({
            items: '>.inline-related',
            update: function(event, ui) {
                $('.dynamic-' + data.prefix).each(function(index) {
                    var row = $(this);
                    row.find('.field-' + data.field + ' input').val(10 * (index + 1));
                    row.removeClass('row1 row2').addClass((index % 2) ? 'row2' : 'row1');
                });
            }
        });
    } else {
        $('#result_list tbody').sortable({
            update: function(event, ui) {
                $('#result_list tbody tr').each(function(index) {
                    var row = $(this);
                    row.find('.field-' + data.field + ' input').val(10 * (index + 1));
                    row.removeClass('row1 row2').addClass((index % 2) ? 'row2' : 'row1');
                });
            }
        });
    }
});

Add untested support for change lists


function doConfig() {
    if (window.location.hostname === 'localhost') {
        mcglobals.apihost = window.location.protocol + '//localhost:5002';
    } else {
        mcglobals.apihost = window.location.protocol + '//' + window.location.hostname + '/api';
    }
}

function doConfig() {
    if (window.location.hostname === 'localhost') {
        mcglobals.apihost = window.location.protocol + '//localhost:5002';
    } else {
        mcglobals.apihost = window.location.protocol + '//' + window.location.hostname + ':' + window.location.port + '/api';
    }
}

Support website on port other than 80.


$().ready(function(){
  function init(){
    var initialYear = new Date().getFullYear() - 100;
    renderMap();

    requestYears(function(years, formattedYears){
      renderSlider(years, formattedYears, {
        onChange: function(currentYear){
          requestInfluences(currentYear, function(influences){
            renderInfluencesInMap(influences);
          });
        },
        onInit: function(){
          requestInfluences(initialYear, function(influences){
            renderInfluencesInMap(influences);
          });
        }
      });
    });

    listenSearch({
      onSearch: function(term){
        requestYearByInfluenceName(term, function(year){
          changeSliderTo(year);

          requestInfluences(year, function(influences){
            renderInfluencesInMap(influences);
          });
        })
      }
    });

    listenRequestYear({
      onSearch: function(year){
        changeSliderTo(year);

        requestInfluences(year, function(influences){
          renderInfluencesInMap(influences);
        });
      }
    });
  }
  init();
});

$().ready(function(){
  function init(){
    var initialYear = new Date().getFullYear() - 100;
    renderMap();

    requestYears(function(years, formattedYears){
      renderSlider(years, formattedYears, {
        onChange: function(currentYear){
          requestInfluences(currentYear, function(influences){
            renderInfluencesInMap(influences);
          });
        },
        onInit: function(){
          changeSliderTo(initialYear);
          requestInfluences(initialYear, function(influences){
            renderInfluencesInMap(influences);
          });
        }
      });
    });

    listenSearch({
      onSearch: function(term){
        requestYearByInfluenceName(term, function(year){
          changeSliderTo(year);

          requestInfluences(year, function(influences){
            renderInfluencesInMap(influences);
          });
        })
      }
    });

    listenRequestYear({
      onSearch: function(year){
        changeSliderTo(year);

        requestInfluences(year, function(influences){
          renderInfluencesInMap(influences);
        });
      }
    });
  }
  init();
});

Change initial year in slider for 100 years ago from now


/*global $ */
/*jslint
 white: true,
 vars: true,
 indent: 2
*/
(function($) {
  "use strict";
  $.fn.hideOtherLinks = function() {
    var $el = $(this),
        showHide = $(''),
        shownElements = [],
        hiddenElements = [],
        currentlyAppending = shownElements;

    $($el.contents()).each(function(i, el) {
      if (el.nodeValue && el.nodeValue === ".") {
        return;
      }
      currentlyAppending.push(el);
      if ($(el).is('a')) {
        currentlyAppending = hiddenElements;
      }
    });

    if (hiddenElements.length) {

      $el.empty();

      $(shownElements).each(function(i, el) {
        $el[0].appendChild(el);
      });

      $(hiddenElements).each(function(i, el) {
        showHide[0].appendChild(el);
      });

      $el.append(showHide);
      $el.append(".");

      showHide.hide();

      var toggle = $('+ others');

      toggle.on('click', function(e) {
        e.preventDefault();
        $(this).remove();
        showHide.show().focus();
      });

      showHide.before(toggle);

      $el.attr('aria-live', 'polite');

    }

    return $el;
  };
})(jQuery);

/*global $ */
/*jslint
 white: true,
 vars: true,
 indent: 2
*/
(function($) {
  "use strict";
  $.fn.hideOtherLinks = function() {
    $(this).each(function(i, elm){
      var $el = $(elm),
          showHide = $(''),
          shownElements = [],
          hiddenElements = [],
          currentlyAppending = shownElements;

      $($el.contents()).each(function(i, el) {
        if (el.nodeValue && el.nodeValue === ".") {
          return;
        }
        currentlyAppending.push(el);
        if ($(el).is('a')) {
          currentlyAppending = hiddenElements;
        }
      });

      if (hiddenElements.length) {

        $el.empty();

        $(shownElements).each(function(i, el) {
          $el[0].appendChild(el);
        });

        $(hiddenElements).each(function(i, el) {
          showHide[0].appendChild(el);
        });

        $el.append(showHide);
        $el.append(".");

        showHide.hide();

        var toggle = $('+ others');

        toggle.on('click', function(e) {
          e.preventDefault();
          $(this).remove();
          showHide.show().focus();
        });

        showHide.before(toggle);

        $el.attr('aria-live', 'polite');

      }

    });
    return this;
  };
})(jQuery);

Enable multi-element selectors for hideOtherLinks


import template from './auth-saml2-dialog.html';

const authSaml2Dialog = {
  template,
  bindings: {
    dismiss: '&',
    close: '&',
  },
  controller: class AuthSaml2DialogController {
    // @ngInject
    constructor($sce, ENV, Saml2Service, ncUtilsFlash) {
      this.Saml2Service = Saml2Service;
      this.ncUtilsFlash = ncUtilsFlash;
    }

    $onInit() {
      this.loginUrl = this.Saml2Service.getLoginUrl();
      this.initialized = false;

      this.refreshChoices().then(() => {
        this.initialized = true;
      }).catch(() => {
        this.error = true;
        this.ncUtilsFlash.error(gettext('Could not load a list of identity providers. Please try again.'));
      });
    }

    refreshChoices(name) {
      return this.Saml2Service.getProviders(name).then(response => {
        this.providers = response.data;
      });
    }

    isProviderSelected() {
      return !!this.provider;
    }
  }
};

export default authSaml2Dialog;

import template from './auth-saml2-dialog.html';

const authSaml2Dialog = {
  template,
  bindings: {
    dismiss: '&',
    close: '&',
  },
  controller: class AuthSaml2DialogController {
    // @ngInject
    constructor(Saml2Service, ncUtilsFlash, $rootScope) {
      this.Saml2Service = Saml2Service;
      this.ncUtilsFlash = ncUtilsFlash;
      this.$rootScope = $rootScope;
    }

    $onInit() {
      this.loginUrl = this.Saml2Service.getLoginUrl();
      this.initialized = false;

      this.$rootScope.$broadcast('enableRequests');
      this.refreshChoices().catch(() => {
        this.error = true;
        this.ncUtilsFlash.error(gettext('Could not load a list of identity providers. Please try again.'));
      }).finally(() => {
        this.initialized = true;
      });
    }

    refreshChoices(name) {
      return this.Saml2Service.getProviders(name).then(response => {
        this.providers = response.data;
      });
    }

    isProviderSelected() {
      return !!this.provider;
    }
  }
};

export default authSaml2Dialog;

Enable pending HTTP requests to get list of SAML2 identity providers.


/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */

/* eslint-disable no-console */

import fs from 'fs';
import path from 'path';
import async from 'async';

// /////////////////////////////////////////////////////////////
// Helpers
// /////////////////////////////////////////////////////////////

const distPath = path.resolve.bind(path, path.resolve(__dirname, '../', '.tmp'));

// /////////////////////////////////////////////////////////////
// Tasks
// /////////////////////////////////////////////////////////////

async.series([
	/**
	 * Clean up the package.json
	 */
	(done) => {
		console.log('### Cleaning up the package.json');

		const packageJSON = JSON.parse(fs.readFileSync(distPath('package.json')).toString());
		// Used by documentation site
		// Can be used for CI tests by consuming applications
		packageJSON.SLDS = { gitURL: packageJSON.devDependencies['@salesforce-ux/design-system'] };
		delete packageJSON.scripts;
		delete packageJSON.devDependencies;
		delete packageJSON['pre-push'];
		delete packageJSON['pre-commit'];
		fs.writeFile(
			distPath('package.json'),
			JSON.stringify(packageJSON, null, 2),
			done
		);
	}
], (err) => {
	if (err) throw err;
});

/* Copyright (c) 2015-present, salesforce.com, inc. All rights reserved */
/* Licensed under BSD 3-Clause - see LICENSE.txt or git.io/sfdc-license */

/* eslint-disable no-console */

import fs from 'fs';
import path from 'path';
import async from 'async';

// /////////////////////////////////////////////////////////////
// Helpers
// /////////////////////////////////////////////////////////////

const distPath = path.resolve.bind(path, path.resolve(__dirname, '../', '.tmp'));

// /////////////////////////////////////////////////////////////
// Tasks
// /////////////////////////////////////////////////////////////

async.series([
	/**
	 * Clean up the package.json
	 */
	(done) => {
		console.log('### Cleaning up the package.json');

		const packageJSON = JSON.parse(fs.readFileSync(distPath('package.json')).toString());
		// Used by documentation site
		// Can be used for CI tests by consuming applications
		packageJSON.SLDS = { gitURL: packageJSON.devDependencies['@salesforce-ux/design-system'] };
		delete packageJSON.scripts;

		// This is a UI library, not a node package.
		delete packageJSON.engines.node;
		delete packageJSON.devDependencies;
		delete packageJSON['pre-push'];
		delete packageJSON['pre-commit'];
		fs.writeFile(
			distPath('package.json'),
			JSON.stringify(packageJSON, null, 2),
			done
		);
	}
], (err) => {
	if (err) throw err;
});

Remove node engine version from published package


"use strict";

angular.module("piadinamia").factory("sharedCartService",
    ["$firebase", "Firebase", "FBURL",
    function ($firebase, Firebase, FBURL) {
        var myCustomers = [],
            fburl;

        return {
            init: function (customers, catalogName, userId) {
                var customersRef;

                myCustomers = customers;
                fburl = FBURL + "/users/" + userId +
                    "/catalogs/" + catalogName + "/customers";

                customersRef = new Firebase(fburl);

                $firebase(customersRef).$on("change", function() {
                    $firebase(customersRef).$on("loaded", function (customers) {
                        myCustomers = [];

                        angular.forEach(customers, function(item) {
                            myCustomers.push(item);
                        });
                    });
                });
            },

            getCartByItem: function () {},

            getCartByUser: function () {}

        };

    }]);

"use strict";

angular.module("piadinamia").factory("sharedCartService",
    ["cartService", "$firebase", "Firebase", "FBURL",
    function (cartService, $firebase, Firebase, FBURL) {
        var myCustomers = [],
            myCatalogName,
            fburl;

        return {
            init: function (customers, catalogName, userId) {
                var customersRef;

                myCustomers = customers;
                myCatalogName = catalogName;

                fburl = FBURL + "/users/" + userId +
                    "/catalogs/" + catalogName + "/customers";

                customersRef = new Firebase(fburl);

                $firebase(customersRef).$on("change", function () {
                    $firebase(customersRef).$on("loaded", function (customers) {
                        myCustomers = [];

                        angular.forEach(customers, function (item) {
                            myCustomers.push(item);
                        });
                    });
                });
            },

            getCartByItem: function () {},

            getCartByUser: function () {
                var cartByUser = {};

                myCustomers.forEach(function (userId) {
                    var cartRef,
                        url = FBURL + "/users/" + userId +
                            "/catalogs/" + myCatalogName + "/cart",
                        myCart;

                    cartRef = new Firebase(url);
                    $firebase(cartRef).$on("loaded", function (cart) {
                        myCart = [];

                        angular.forEach(cart, function (item) {
                            myCart.push(item);
                        });

                        cartByUser[userId] = myCart;
                    });

                });
            }

        };

    }]);

Add getCartByUser in shared cart.


Template.feelings.events({
  'click .feeling' (event, templateInstance) {
    console.log(event.currentTarget.id);
  }
});

import Feelings from '/feelings/collection';

Template.feelings.events({
  'click .feeling' (event, templateInstance) {
    const feeling = event.currentTarget.id;

    Feelings.insert({ feeling });
  }
});

Add collection insert on click


const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: "./debugger",

  module: {
    rules: [{
      test: /\.js$/,
      loader: "babel-loader",
      query: {
        presets: [
          [
            'babel-preset-env',
            { targets: { "node": "6.14" } }
          ]
        ],
        plugins: ['transform-object-rest-spread', 'transform-runtime'],
      },
      include: [
        path.resolve(__dirname, "..", 'lib')
      ],
    }],
  },

  target: 'node',

  output: {
    library: "Debugger",
    libraryTarget: "umd",
    umdNamedDefine: true,

    filename: "debugger.js",
    path: path.join(__dirname, "..", "dist"),
    devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]'
  },

  resolve: {
    modules: [path.resolve(__dirname, ".."), "node_modules"]
  },

  // in order to ignore all modules in node_modules folder
  externals: [nodeExternals({
    modulesFromFile: true,
  })],

  devtool: "inline-cheap-module-source-map",
}

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
  entry: "./debugger",

  module: {
    rules: [{
      test: /\.js$/,
      loader: "babel-loader",
      query: {
        presets: [
          [
            'babel-preset-env',
            { targets: { "node": "6.14" } }
          ]
        ],
        plugins: ['transform-object-rest-spread', 'transform-runtime'],
      },
      include: [
        path.resolve(__dirname, "..", 'lib')
      ],
    }],
  },

  target: 'node',

  output: {
    library: "Debugger",
    libraryTarget: "umd",
    umdNamedDefine: true,

    filename: "debugger.js",
    path: path.join(__dirname, "..", "dist"),
    devtoolModuleFilenameTemplate: '[absolute-resource-path]',
    devtoolFallbackModuleFilenameTemplate: '[absolute-resource-path]?[hash]'
  },

  resolve: {
    modules: [path.resolve(__dirname, ".."), "node_modules"]
  },

  // in order to ignore all modules in node_modules folder
  externals: [nodeExternals({
    modulesFromFile: true,
    whitelist: [
      "node-interval-tree"
    ]
  })],

  devtool: "inline-cheap-module-source-map",
}

Include node-interval-tree in debugger bundle


#!/usr/bin/env node

var program = require('commander');
var autometa = require('../lib/autometa.js');
var package = require('../package.json');

program
  .version(package['version'], '-v, --version')
  .usage('[options] <Excel spreadsheet>')
  .option('-o, --stdout', 'place output on stdout')
  .parse(process.argv);

var filename = program.args[0];

if(!program.args.length) {
  program.help();
} else if(program.stdout) {
  output = autometa.generate(filename);
  if(output) {
    console.log(output[1]);
    process.exit(0);
  } else {
    console.log("Error. Check input file.");
    process.exit(1);
  }
} else {
  if(autometa.generateFile(filename)) {
    process.exit(0);
  } else {
    console.log("Error. Check input file.");
    process.exit(1);
  }
}

#!/usr/bin/env node

var program = require('commander');
var autometa = require('../lib/autometa.js');
var package = require('../package.json');

program
  .version(package['version'], '-v, --version')
  .usage('[options] <Excel spreadsheet>')
  .option('-o, --stdout', 'place output on stdout')
  .option('-r, --register <template file>', 'register templates', String)
  .parse(process.argv);

var templates = []

if(!program.args.length) { // No filename found
  if(program.register) {
    templates.push(program.register);
    console.log("register: " + templates);
    process.exit(0);
  } else {
    program.help();
  }
} else { // filename found
  if(program.stdout) {
    output = autometa.generate(program.args[0]);
    if(output) {
      console.log(output[1]); // Print only 1st data
      process.exit(0);
    } else {
      console.log("Error. Check input file.");
      process.exit(1);
    }
  } else if(program.register) { // Count strings as templates
    templates.push(program.register);
    templates = templates.concat(program.args);
    console.log("register: " + templates);
    process.exit(0);
  } else {
    // Only filename specified
    if(autometa.generateFile(program.args[0])) { // Success to generate file
      process.exit(0);
    } else { // Failed to generate file
      console.log("Error. Check input file.");
      process.exit(1);
    }
  }
}

Add register command-line interface option


/**
 * The SpinnerTabsPresenter class for the SpinnerTabsPresenter view.
 *
 * @return SpinnerTabsPresenter class.
 */
define([
  'underscore',
  'mps',
  'map/presenters/PresenterClass',
], function(_, mps, PresenterClass) {

  'use strict';

  var SpinnerTabsPresenter = PresenterClass.extend({

    init: function(view) {
      this.view = view;
      this._super();
    },

    /**
     * Application subscriptions.
     */
    _subscriptions: [{
      'Spinner/start': function(allowCancel) {
        this.view.start();

        if (allowCancel === false) {
          this.view.$el.find('button').hide();
        }
      }
    }, {
      'Spinner/stop': function() {
        this.view.stop();
      }
    }],

    cancel: function() {
      mps.publish('Spinner/cancel');
    }

  });

  return SpinnerTabsPresenter;
});

/**
 * The SpinnerTabsPresenter class for the SpinnerTabsPresenter view.
 *
 * @return SpinnerTabsPresenter class.
 */
define([
  'underscore',
  'mps',
  'map/presenters/PresenterClass',
], function(_, mps, PresenterClass) {

  'use strict';

  var SpinnerTabsPresenter = PresenterClass.extend({

    init: function(view) {
      this.view = view;
      this._super();
    },

    /**
     * Application subscriptions.
     */
    _subscriptions: [{
      'Spinner/start': function(allowCancel) {
        this.view.start();

        if (allowCancel === false) {
          this.view.$el.find('button').hide();
        } else {
          this.view.$el.show('button').hide();
        }
      }
    }, {
      'Spinner/stop': function() {
        this.view.stop();
      }
    }],

    cancel: function() {
      mps.publish('Spinner/cancel');
    }

  });

  return SpinnerTabsPresenter;
});

Fix loading indicator for subscribe view


/* Implementation from: https://github.com/laszlopandy/elm-console/blob/master/elm-io.sh */
module.exports =
  "(function(){\n" +
  "    window = {Date: Date};\n" +
  "    if (typeof Elm === \"undefined\") { throw \"elm-io config error: Elm is not defined. Make sure you call elm-io with a real Elm output file\"}\n" +
  "    if (typeof Elm.Main === \"undefined\" ) { throw \"Elm.Main is not defined, make sure your module is named Main.\" };\n" +
  "    var worker = Elm.worker(Elm.Main);\n" +
  "})();\n";

/* Implementation from: https://github.com/laszlopandy/elm-console/blob/master/elm-io.sh */
module.exports =
  "(function(){\n" +
  "    window = {Date: Date,addEventListener : function() {},removeEventListener : function() {}};\n" +
  "    if (typeof Elm === \"undefined\") { throw \"elm-io config error: Elm is not defined. Make sure you call elm-io with a real Elm output file\"}\n" +
  "    if (typeof Elm.Main === \"undefined\" ) { throw \"Elm.Main is not defined, make sure your module is named Main.\" };\n" +
  "    var worker = Elm.worker(Elm.Main);\n" +
  "})();\n";

Add addEventListener, removeEventListener to the window stub


const express = require('express');
const request = require('request');
const cookies = require('./cookie');

const app = express();

app.use('*', (req, res) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Credentials', 'true');
  console.log(new Date(), ' -- Request Received:', req.originalUrl);
  req.headers.cookie = cookies;
  /**
  * Credit to: https://blog.javascripting.com/2015/01/17/dont-hassle-with-cors/
  */
  const url = 'http://www.mturk.com' + req.originalUrl;
  req.pipe(request(url)).pipe(res);
});

app.set('port', process.env.PORT || 7777);

const server = app.listen(app.get('port'), () => {
  console.log(`Express running → PORT ${server.address().port}`);
});

const express = require('express');
const request = require('request');
const cookies = require('./cookie');

const app = express();

app.use('*', (req, res) => {
  res.header('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.header('Access-Control-Allow-Credentials', 'true');
  console.log(new Date(), ' -- Request Received:', req.originalUrl);
  req.headers.cookie = cookies;
  /**
  * Credit to: https://blog.javascripting.com/2015/01/17/dont-hassle-with-cors/
  */
  const url = 'https://worker.mturk.com' + req.originalUrl;
  req.pipe(request(url)).pipe(res);
});

app.set('port', process.env.PORT || 7777);

const server = app.listen(app.get('port'), () => {
  console.log(`Express running → PORT ${server.address().port}`);
});

Update dev server to send requests to worker site.


'use strict';

var webpack = require('webpack');

var plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
  }),
  new webpack.optimize.OccurenceOrderPlugin()
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        screw_ie8: true,
        warnings: false
      }
    })
  );
}

var reactExternal = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
};

var reduxExternal = {
  root: 'Redux',
  commonjs2: 'redux',
  commonjs: 'redux',
  amd: 'redux'
};

module.exports = {
  externals: {
    'react': reactExternal,
    'react-native': reactExternal,
    'redux': reduxExternal
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'ReduxReact',
    libraryTarget: 'umd'
  },
  plugins: plugins,
  resolve: {
    extensions: ['', '.js']
  }
};

'use strict';

var webpack = require('webpack');

var plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
  }),
  new webpack.optimize.OccurenceOrderPlugin()
];

if (process.env.NODE_ENV === 'production') {
  plugins.push(
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        screw_ie8: true,
        warnings: false
      }
    })
  );
}

var reactExternal = {
  root: 'React',
  commonjs2: 'react',
  commonjs: 'react',
  amd: 'react'
};

var reduxExternal = {
  root: 'Redux',
  commonjs2: 'redux',
  commonjs: 'redux',
  amd: 'redux'
};

module.exports = {
  externals: {
    'react': reactExternal,
    'react-native': reactExternal,
    'redux': reduxExternal
  },
  module: {
    loaders: [
      { test: /\.js$/, loaders: ['babel-loader'], exclude: /node_modules/ }
    ]
  },
  output: {
    library: 'ReactRedux',
    libraryTarget: 'umd'
  },
  plugins: plugins,
  resolve: {
    extensions: ['', '.js']
  }
};

Make webpack's library output name read ReactRedux instead of ReduxReact


'use strict';

const Express = require('express');
const Proxy   = require('express-http-proxy');
const Router  = Express.Router();
const env     = process.env;
/*
 * Helpers, In-House Modules
 */
const hlp_health = require('../helper/healthcheck');

Router.get('/stats/api', (req, res, next) => {
  hlp_health.http('xen-mid-rest', 80, '/').then(() => {
    res.sendStatus(200);
  }).catch((err) => {
    next(err);
  });
});

Router.get('/stats/xen', (req, res, next) => {
  hlp_health.https(env.XAPI_PATH, Number(env.XAPI_PORT), '/', true).then(() => {
    res.sendStatus(200);
  }).catch((err) => {
    next(err);
  });
});

module.exports = Router;

'use strict';

const Express = require('express');
const Proxy   = require('express-http-proxy');
const Router  = Express.Router();
const env     = process.env;
/*
 * Helpers, In-House Modules
 */
const hlp_health = require('../helper/healthcheck');

Router.get('/stats/api', (req, res, next) => {
  hlp_health.http('xen-mid-rest', 4567, '/').then(() => {
    res.sendStatus(200);
  }).catch((err) => {
    next(err);
  });
});

Router.get('/stats/xen', (req, res, next) => {
  hlp_health.https(env.XAPI_PATH, Number(env.XAPI_PORT), '/', true).then(() => {
    res.sendStatus(200);
  }).catch((err) => {
    next(err);
  });
});

module.exports = Router;

Fix Invalid Variable + Session Leak


import React from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

import Header from './components/header'
import Footer from './components/footer'

import Homepage from './screens/homepage'
import UserDashboard from './screens/userDashboard'
import ProjectScreen from './screens/project'

export default () =>
  <Router>
    <div className="wrapper">
      <Header />

      <Route exact path="/" component={Homepage} />
      <Route exact path="/:username" component={UserDashboard} />
      <Switch>
        <Route path="/:username/:project/:mode?" component={ProjectScreen} />
        <Route path="/:username/:owner/:project/:mode?" component={ProjectScreen} />
      </Switch>

      <Footer />
    </div>
  </Router>

import React from 'react'
import { BrowserRouter as Router, Redirect, Route, Switch } from 'react-router-dom'

import Header from './components/header'
import Footer from './components/footer'

import Homepage from './screens/homepage'
import UserDashboard from './screens/userDashboard'
import ProjectScreen from './screens/project'

export default () =>
  <Router>
    <div className="wrapper">
      <Header />

      <Route exact path="/" component={Homepage} />
      <Route exact path="/:username" component={UserDashboard} />
      <Route
        path="/:username/:project"
        render={({ match }) => <Redirect to={`${match.url}/edit`.replace('//', '/')} />}
      />
      <Switch>
        <Route path="/:username/:project/:mode" component={ProjectScreen} />
        <Route path="/:username/:owner/:project/:mode" component={ProjectScreen} />
      </Switch>

      <Footer />
    </div>
  </Router>

Make edit the default project view


'use strict';

var DataStore = require('./data-store/data-store');
var Messenger = require('./messenger/messenger');
var Deployer = require('./deploy/deployer');
var helpers = require('./helpers/helpers');

var deployer = new Deployer();

function register(name, tag, definition) {
    return DataStore.registerModule(name, tag, definition);
}

module.exports = {
    attach: deployer.attach.bind(deployer),
    deploy: deployer.deploy.bind(deployer),
    execute: deployer.execute.bind(deployer),
    requires: deployer.requires.bind(deployer),
    register: register,
    component: register, // alias for 'register'
    module: register, // alias for 'register'
    scene: register, // alias for 'register'
    message: Messenger.message,
    helpers: helpers
};

'use strict';

var DataStore = require('./data-store/data-store');
var Messenger = require('./messenger/messenger');
var Deployer = require('./deploy/deployer');
var helpers = require('./helpers/helpers');

var deployer = new Deployer();

// We use the module's tag for reference, so we need to give
// any modules that happen to not have a tag a default one.
var UNSPECIFIED_TAG = '!unspecified!';
var OBJECT_TYPE = 'object';

function returnUnspecifiedTag(name, tag) {
    console.warn('Tag given for `' + name + '` was `' + tag + '`; defaulting to `unspecified` instead');
    return UNSPECIFIED_TAG;
}

function register(name, tag, definition) {
    // Allow the arguments to `register` to be flexible, i.e. allow:
    // BEST.scene('foo:bar') (e.g. for a timeline-only API)
    // BEST.scene('foo:bar', {...}),
    // BEST.scene('foo:bar', '0.1', {...})
    if (!definition) {
        if (!tag) {
            definition = {};
            tag = returnUnspecifiedTag(name tag);
        }
        else {
            if (typeof tag === OBJECT_TYPE) {
                definition = tag;
                tag = returnUnspecifiedTag(name, tag);
            }
            else {
                definition = {};
                if (typeof tag !== 'string') {
                    tag = returnUnspecifiedTag(name, tag);
                }
            }
        }

    }
    return DataStore.registerModule(name, tag, definition);
}

module.exports = {
    attach: deployer.attach.bind(deployer),
    deploy: deployer.deploy.bind(deployer),
    execute: deployer.execute.bind(deployer),
    requires: deployer.requires.bind(deployer),
    register: register,
    component: register, // alias for 'register'
    module: register, // alias for 'register'
    scene: register, // alias for 'register'
    message: Messenger.message,
    helpers: helpers
};

Allow for more flexible arguments to BEST.register


$(function() {
    function traverse($node, len, maxCount) {
        var reachMaxCount = len > maxCount;
        if (reachMaxCount) {
            $node.hide();
        }
        var $contents = $node.contents();
        for (var i = 0; i < $contents.length; ++i) {
            if (reachMaxCount) {
                $contents.eq(i).hide();
                continue;
            }
            if ($contents[i].nodeType == 3) { // TextNode
                var tmp = len;
                var s = $contents[i].nodeValue;
                len += s.length;
                reachMaxCount = len > maxCount;
                if (reachMaxCount) {
                    $contents[i].nodeValue = s.substring(0, maxCount - tmp);
                }
            }
            else if ($contents[i].nodeType == 1) { // Element
                len = traverse($contents.eq(i), len, maxCount);
            }
        }
        return len;
    }
    $('.post-excerpt').each(function() {
        traverse($(this), 0, 200);
        $(this).after('...');
    });
});

$(function() {
    function traverse($node, len, maxCount) {
        var reachMaxCount = len > maxCount;
        if (reachMaxCount) {
            $node.hide();
        }
        var $contents = $node.contents();
        for (var i = 0; i < $contents.length; ++i) {
            if (reachMaxCount) {
                $contents.eq(i).hide();
                continue;
            }
            if ($contents[i].nodeType == 3) { // TextNode
                var tmp = len;
                var s = $contents[i].nodeValue;
                len += s.length;
                reachMaxCount = len > maxCount;
                if (reachMaxCount) {
                    $contents[i].nodeValue = s.substring(0, maxCount - tmp);
                }
            }
            else if ($contents[i].nodeType == 1) { // Element
                len = traverse($contents.eq(i), len, maxCount);
            }
        }
        return len;
    }
    $('.article-item').find("p").each(function() {
        traverse($(this), 0, 365);
        $(this).append('...');
    });
});

Adjust the style to truncate post index.