import React from 'react';
import Match from 'react-router/Match';
import Miss from 'react-router/Miss';
import Users from './Users';

class UsersRouting extends React.Component {
  NoMatch() {
    return

Uh-oh!

How did you get to <tt>{this.props.location.pathname}</tt>?

  }

  render() {
    var pathname = this.props.pathname;
    var connect = this.props.connect;
    console.log("matching location:", this.props.location.pathname);

    return

Users module

      <Match exactly pattern={`${pathname}`} component={connect(Users)}/>
      <Match exactly pattern={`${pathname}/:query`} component={connect(Users)}/>
      <Match         pattern={`${pathname}/:query?/view/:userid`} component={connect(Users)}/>
      <Miss component={this.NoMatch.bind(this)}/>

  }
}

export default UsersRouting;

import React from 'react';
import Match from 'react-router/Match';
import Miss from 'react-router/Miss';
import Users from './Users';

class UsersRouting extends React.Component {
  constructor(props){
    super(props);
    this.connectedUsers = props.connect(Users);
  }

  NoMatch() {
    return

Uh-oh!

How did you get to <tt>{this.props.location.pathname}</tt>?

  }

  render() {
    var pathname = this.props.pathname;
    var connect = this.props.connect;
    console.log("matching location:", this.props.location.pathname);

    return

Users module

      <Match exactly pattern={`${pathname}`} component={this.connectedUsers}/>
      <Match exactly pattern={`${pathname}/:query`} component={this.connectedUsers}/>
      <Match         pattern={`${pathname}/:query?/view/:userid`} component={this.connectedUsers}/>
      <Miss component={this.NoMatch.bind(this)}/>

  }
}

export default UsersRouting;

Call connect() on the Users component only once, and cache the result. This seems to fix STRIPES-97 at last!


/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-ui-sortable',

  included: function(app) {
    app.import(app.bowerDirectory + '/jquery-ui/ui/version.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/data.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/ie.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/safe-active-element.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/safe-blur.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/scroll-parent.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widget.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widgets/mouse.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widgets/sortable.js');
  }
};

/* jshint node: true */
'use strict';

module.exports = {
  name: 'ember-ui-sortable',

  included: function(app) {
    app.import(app.bowerDirectory + '/jquery-ui/ui/version.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/data.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/ie.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/safe-active-element.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/safe-blur.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/scroll-parent.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/plugin.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widget.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widgets/mouse.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widgets/draggable.js');
    app.import(app.bowerDirectory + '/jquery-ui/ui/widgets/sortable.js');
  }
};

Update dependencies to be an exact copy of jquery-ui's custom download option


'use strict'

const { config, Lambda } = require('aws-sdk')

const { stringify } = JSON

config.update({
  accessKeyId: 'ABC',
  secretAccessKey: 'SECRET',
})

const lambda = new Lambda({
  apiVersion: '2015-03-31',
  endpoint: 'http://localhost:3000',
})

exports.noPayload = async function noPayload() {
  const params = {
    FunctionName: 'lambda-invoke-tests-dev-invokedHandler',
    InvocationType: 'RequestResponse',
  }

  const response = await lambda.invoke(params).promise()

  return {
    body: stringify(response),
    statusCode: 200,
  }
}

exports.testHandler = async function testHandler() {
  const params = {
    FunctionName: 'lambda-invoke-tests-dev-invokedHandler',
    InvocationType: 'RequestResponse',
    Payload: stringify({ event: { foo: 'bar' } }),
  }

  const response = await lambda.invoke(params).promise()

  return {
    body: stringify(response),
    statusCode: 200,
  }
}

exports.invokedHandler = async function invokedHandler(event) {
  return {
    event,
  }
}

'use strict'

const { config, Lambda } = require('aws-sdk')

const { stringify } = JSON

config.update({
  accessKeyId: 'ABC',
  secretAccessKey: 'SECRET',
})

const lambda = new Lambda({
  apiVersion: '2015-03-31',
  endpoint: 'http://localhost:3000',
})

exports.noPayload = async function noPayload() {
  const params = {
    FunctionName: 'lambda-invoke-tests-dev-invokedHandler',
    InvocationType: 'RequestResponse',
  }

  const response = await lambda.invoke(params).promise()

  return {
    body: stringify(response),
    statusCode: 200,
  }
}

exports.testHandler = async function testHandler() {
  const params = {
    FunctionName: 'lambda-invoke-tests-dev-invokedHandler',
    InvocationType: 'RequestResponse',
    Payload: stringify({ foo: 'bar' }),
  }

  const response = await lambda.invoke(params).promise()

  return {
    body: stringify(response),
    statusCode: 200,
  }
}

exports.invokedHandler = async function invokedHandler(event) {
  return {
    event,
  }
}

Fix lambda invoke with no payload


const expect = require('chai').expect

const dataHelper = require('../helpers/data/aggregated-data-helper')

var workloadOwnerId
var workloadOwnerGrade

describe('View overview', function () {
  before(function () {
    return dataHelper.selectIdsForWorkloadOwner()
      .then(function (results) {
        var workloadOwnerIds = results.filter((item) => item.table === 'workload_owner')
        workloadOwnerId = workloadOwnerIds[workloadOwnerIds.length - 1].id
        return results
      })
      .then(function (results) {
        dataHelper.selectGradeForWorkloadOwner(workloadOwnerId)
        .then(function (gradeResult) {
          workloadOwnerGrade = gradeResult
        })
      })
  })

  it('should navigate to the overview page', function () {
    return browser.url('/offender-manager/' + workloadOwnerId + '/overview')
      .waitForExist('.breadcrumbs')
      .waitForExist('.sln-subnav')
      .waitForExist('.sln-grade')
      .getText('.sln-grade')
      .then(function (text) {
        expect(text).to.equal(workloadOwnerGrade)
      })
  })
})

const expect = require('chai').expect

const dataHelper = require('../helpers/data/aggregated-data-helper')

var workloadOwnerId
var workloadOwnerGrade

describe('View overview', function () {
  before(function () {
    return dataHelper.selectIdsForWorkloadOwner()
      .then(function (results) {
        var workloadOwnerIds = results.filter((item) => item.table === 'workload_owner')
        workloadOwnerId = workloadOwnerIds[0].id
        return results
      })
      .then(function (results) {
        dataHelper.selectGradeForWorkloadOwner(workloadOwnerId)
        .then(function (gradeResult) {
          workloadOwnerGrade = gradeResult
        })
      })
  })

  it('should navigate to the overview page', function () {
    return browser.url('/offender-manager/' + workloadOwnerId + '/overview')
      .waitForExist('.breadcrumbs')
      .waitForExist('.sln-subnav')
      .waitForExist('.sln-grade')
      .getText('.sln-grade')
      .then(function (text) {
        expect(text).to.equal(workloadOwnerGrade)
      })
  })
})

Use the first workload owner id in e2e test


(function (env) {
    "use strict";
    env.ddg_spice_tfl_status = function(api_result){

        Spice.add({
            id: "tfl_status",
            name: "Travel",
            data: api_result,
            meta: {
                sourceName: "tfl.gov.uk",
    		sourceUrl: 'http://tfl.gov.uk/tube-dlr-overground/status/#line-' + api_result.id,
            },
            templates: {
                group: 'base',
                options: {
                    content: Spice.tfl_status.content,
                    moreAt: true
                }
            }
        });
    };
}(this));

(function (env) {
    "use strict";
    env.ddg_spice_tfl_status = function(api_result){

        Spice.add({
            id: "tfl_status",
            name: "Travel",
            data: api_result,
            meta: {
                sourceName: "tfl.gov.uk",
    		sourceUrl: 'http://tfl.gov.uk/tube-dlr-overground/status/#line-' + api_result[0].id,
            },
            templates: {
                group: 'base',
                options: {
                    content: Spice.tfl_status.content,
                    moreAt: true
                }
            }
        });
    };
}(this));

Fix for the "More at..." link to correct lineId


/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    // Add options here
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};

/*jshint node:true*/
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');

module.exports = function(defaults) {
  var app = new EmberApp(defaults, {
    fingerprint: {
      prepend: '/Julz.jl/'
    }
  });

  // Use `app.import` to add additional libraries to the generated
  // output files.
  //
  // If you need to use different assets in different
  // environments, specify an object as the first parameter. That
  // object's keys should be the environment name and the values
  // should be the asset to use in that environment.
  //
  // If the library that you are including contains AMD or ES6
  // modules that you would like to import into your application
  // please specify an object with the list of modules as keys
  // along with the exports of each module as its value.

  return app.toTree();
};

Prepend ember fingerprints with Julz.jl path


(function (millisecondsToISO8601Duration) {
	'use strict';

	millisecondsToISO8601Duration.iso8601duration = function(milliseconds) {
		var offset = Math.floor(milliseconds);
		var milliseconds = offset % 1000;
		offset = Math.floor(offset / 1000);
		var seconds = offset % 60;
		offset = Math.floor(offset / 60);
		var minutes = offset % 60;
		offset = Math.floor(offset / 60);
		var hours = offset % 24;
		var days = Math.floor(offset / 24);
		var parts = ['P'];
		if (days) {
			parts.push(days + 'D');
		}
		if (hours || minutes || seconds || milliseconds) {
			parts.push('T');
			if (hours) {
				parts.push(hours + 'H');
			}
			if (minutes) {
				parts.push(minutes + 'M');
			}
			if (seconds || milliseconds) {
				parts.push(seconds);
				if (milliseconds) {
					parts.push('.' + milliseconds);
				}
				parts.push('S');
			}
		}
		return parts.join('')
	};
})(typeof exports === 'undefined' ? millisecondsToISO8601Duration = {} : exports);

(function (millisecondsToISO8601Duration) {
	'use strict';

	millisecondsToISO8601Duration.iso8601duration = function(milliseconds) {
		var offset = Math.floor(milliseconds);
		var milliseconds = offset % 1000;
		offset = Math.floor(offset / 1000);
		var seconds = offset % 60;
		offset = Math.floor(offset / 60);
		var minutes = offset % 60;
		offset = Math.floor(offset / 60);
		var hours = offset % 24;
		var days = Math.floor(offset / 24);
		var parts = ['P'];
		if (days) {
			parts.push(days + 'D');
		}
		if (hours || minutes || seconds || milliseconds) {
			parts.push('T');
			if (hours) {
				parts.push(hours + 'H');
			}
			if (minutes) {
				parts.push(minutes + 'M');
			}
			if (seconds || milliseconds) {
				parts.push(seconds);
				if (milliseconds) {
					milliseconds = milliseconds.toString();
					while (milliseconds.length < 3) {
						milliseconds = '0' + milliseconds;
					}
					parts.push('.' + milliseconds);
				}
				parts.push('S');
			}
		}
		return parts.join('')
	};
})(typeof exports === 'undefined' ? millisecondsToISO8601Duration = {} : exports);

Handle zero-padding for millisecond component


import { Mongo } from 'meteor/mongo';

export const Events = new Mongo.Collection('events');

import { Mongo } from 'meteor/mongo';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';

export const Events = new Mongo.Collection('events');

Events.deny({
  insert() {
    return true;
  },
  update() {
    return true;
  },
  remove() {
    return true;
  }
});

export const createEvent = new ValidatedMethod({
  name: 'events.create',
  validate: new SimpleSchema({
    name: { type: String },
    place: { type: String },
    type: { type: String },
    description: { type: String },
    when: { type: Date },
    howMany: { type: Number }
  }).validator(),
  run({ name, place, type, description, when, howMany }) {
    if (!this.userId) {
      throw new Meteor.Error('not-authorized');
    }
    return Events.insert({
      owner: this.userId,
      name,
      place,
      type,
      description,
      when,
      howMany
    });
  }
});

Add method to create an event


import uglify from "rollup-plugin-uglify"

export default {
    plugins: [
        uglify()
    ]
}

import uglify from "rollup-plugin-uglify"

export default {
    plugins: [
        uglify({
            compress: {
                collapse_vars: true,
                pure_funcs: ["Object.defineProperty"]
            }
        })
    ]
}

Optimize uglifyjs's output via options.


(function () {

  var options = (function () {
    // Holy shit
    var optionsArray = location.href.split('?')[1].split('#')[0].split('=')
    var result = {}

    optionsArray.forEach(function (value, index) {
      // 0 is a property name and 1 the value of 0
      if (index % 2 === 1) {
        return
      }

      result[value] = optionsArray[index + 1]
    });

    return result
  }())

  var toLoadSrc;

  if (options.ionic === 'build') {
    toLoadSrc = 'lib/ionic/local/ionic.bundle.js'
  } else if (options.ionic === 'local' || !options.ionic) {
    toLoadSrc = 'lib/ionic/js/ionic.bundle.js'
  } else {
    // Use options.ionic as ionic version
    toLoadSrc = '//code.ionicframework.com/' + options.ionic + '/js/ionic.bundle.min.js'
  }

  console.log('Ionic From')
  console.log(toLoadSrc)
  document.write('<script src="'+ toLoadSrc +'"></script>')
}())

(function () {

  var options = (function () {
    // Holy shit
    var optionsArray
    var result = {}

    try {
      optionsArray = location.href.split('?')[1].split('#')[0].split('=')
    } catch (e) {
      return {}
    }

    optionsArray.forEach(function (value, index) {
      // 0 is a property name and 1 the value of 0
      if (index % 2 === 1) {
        return
      }

      result[value] = optionsArray[index + 1]
    });

    return result
  }())

  var toLoadSrc;

  if (options.ionic === 'build') {
    toLoadSrc = 'lib/ionic/local/ionic.bundle.js'
  } else if (options.ionic === 'local' || !options.ionic) {
    toLoadSrc = 'lib/ionic/js/ionic.bundle.js'
  } else {
    // Use options.ionic as ionic version
    toLoadSrc = '//code.ionicframework.com/' + options.ionic + '/js/ionic.bundle.min.js'
  }

  console.log('Ionic From')
  console.log(toLoadSrc)
  document.write('<script src="'+ toLoadSrc +'"></script>')
}())

Fix error `cannot read split of undefined`


window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

window.$ = window.jQuery = require('jquery');
require('bootstrap-sass/assets/javascripts/bootstrap');

/**
 * Vue is a modern JavaScript library for building interactive web interfaces
 * using reactive data binding and reusable components. Vue's API is clean
 * and simple, leaving you to focus on building your next great project.
 */

window.Vue = require('vue');
require('vue-resource');

/**
 * We'll register a HTTP interceptor to attach the "CSRF" header to each of
 * the outgoing requests issued by this application. The CSRF middleware
 * included with Laravel will automatically verify the header's value.
 */

Vue.http.interceptors.push((request, next) => {
    request.headers['X-CSRF-TOKEN'] = Laravel.csrfToken;

    next();
});

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from "laravel-echo"

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: 'your-pusher-key'
// });

window._ = require('lodash');

/**
 * We'll load jQuery and the Bootstrap jQuery plugin which provides support
 * for JavaScript based Bootstrap features such as modals and tabs. This
 * code may be modified to fit the specific needs of your application.
 */

window.$ = window.jQuery = require('jquery');
require('bootstrap-sass');

/**
 * Vue is a modern JavaScript library for building interactive web interfaces
 * using reactive data binding and reusable components. Vue's API is clean
 * and simple, leaving you to focus on building your next great project.
 */

window.Vue = require('vue');
require('vue-resource');

/**
 * We'll register a HTTP interceptor to attach the "CSRF" header to each of
 * the outgoing requests issued by this application. The CSRF middleware
 * included with Laravel will automatically verify the header's value.
 */

Vue.http.interceptors.push((request, next) => {
    request.headers['X-CSRF-TOKEN'] = Laravel.csrfToken;

    next();
});

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allows your team to easily build robust real-time web applications.
 */

// import Echo from "laravel-echo"

// window.Echo = new Echo({
//     broadcaster: 'pusher',
//     key: 'your-pusher-key'
// });

Use module name instead of path


import Ember from 'ember';
import layout from '../templates/components/scroll-to-here';

export default Ember.Component.extend({
  layout: layout
});

import Ember from 'ember';
import layout from '../templates/components/scroll-to-here';

let $ = Ember.$;

function Window() {
  let w = $(window);

  this.top = w.scrollTop();
  this.bottom = this.top + (w.prop('innerHeight') || w.height());
}

function Target(selector) {
  let target = $(selector);

  this.isEmpty = !target.length;
  this.top = target.offset().top;
  this.bottom = this.top + target.height();
}

Target.prototype.isOffscreen = function() {
  let w = new Window();

  return this.top < w.top || this.bottom > w.bottom;
};

Target.prototype.scroll = function() {
  if (!this.isEmpty && this.isOffscreen()) {
    Ember.run.schedule('afterRender', () => {
      $('html,body').animate({ scrollTop: this.top }, 1000);
    });
  }
};

function scrollTo(selector) {
  new Target(selector).scroll();
}

export default Ember.Component.extend({
  layout: layout,

  scrollToComponent: Ember.on('didInsertElement', function() {
    scrollTo(`#${this.elementId}`);
  })
});

Add scroll to here logic


import TokenAuthenticator from '../authenticators/token';

export function initialize(application) {
  application.register('authenticator:token', TokenAuthenticator);
}

export default {
  name: 'simple-token',
  initialize
};

import TokenAuthenticator from '../authenticators/token';
import TokenAuthorizer from '../authorizers/token';

export function initialize(application) {
  application.register('authenticator:token', TokenAuthenticator);
  application.register('authorizer:token', TokenAuthorizer);
}

export default {
  name: 'simple-token',
  initialize
};

Fix authorizer missing from container


// This script is used to serve the built files in production and proxy api requests to the service.
// Would be preferrable to replace with apache.

const express = require('express');
const proxy = require('express-http-proxy');
const compression = require('compression');
const path = require('path');

const app = express();

// function forceHttps(request, response, next) {
//   if (request.headers['x-forwarded-proto'] !== 'https') {
//     return response.redirect(301, `https://${request.get('host')}${request.url}`);
//   }
//   return next();
// }

app.use(compression());
// app.use(forceHttps);
app.use(express.static(path.join(__dirname, '..', 'build')));
app.use('/api', proxy('https://onboarding-service.tuleva.ee'));

app.get('/.well-known/acme-challenge/aqfyXwYn_9RtkQy64cwXdzMrRpjW2B4MwtUbtl7kKPk', (request, response) =>
  response.send('aqfyXwYn_9RtkQy64cwXdzMrRpjW2B4MwtUbtl7kKPk.EMEBBxvSam3n_ien1J0z4dXeTuc2JuR3HqfAP6teLjE'));

app.get('*', (request, response) =>
  response.sendFile(path.join(__dirname, '..', 'build', 'index.html')));

const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Static server running on ${port}`)); // eslint-disable-line

// This script is used to serve the built files in production and proxy api requests to the service.
// Would be preferrable to replace with apache.

const express = require('express');
const proxy = require('express-http-proxy');
const compression = require('compression');
const path = require('path');

const app = express();

function forceHttps(request, response, next) {
  if (request.headers['x-forwarded-proto'] !== 'https') {
    return response.redirect(301, `https://${request.get('host')}${request.url}`);
  }
  return next();
}

app.use(compression());
app.use(forceHttps);
app.use(express.static(path.join(__dirname, '..', 'build')));
app.use('/api', proxy('https://onboarding-service.tuleva.ee'));

app.get('*', (request, response) =>
  response.sendFile(path.join(__dirname, '..', 'build', 'index.html')));

const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Static server running on ${port}`)); // eslint-disable-line

Remove acme challenge and enable forcing https


import app from '../app';
import '../services/PlusMinClient';

app.controller('plusMinController', function ($element, $scope, $http, PlusMinClient) {
  let client = PlusMinClient;
  $scope.state = 'loading';

  $scope.toState = function (state) {
    $scope.state = state;
  };

  $scope.openList = function (list) {
    $scope.list = list;
    $scope.list.new = false;
    $scope.state = 'editList';
  };

  $scope.openNewList = function () {
    $scope.list = {
      new: true,
      positives: [],
      negatives: []
    };
    $scope.state = 'editList';
  };

  client.loadLists().then(function (request) {
    let lists = request.data;

    if (lists.length < 2) {
      $scope.state = 'editList';

      if (lists.length === 0) {
        $scope.list = {
          new: true,
          positives: [{
            title: 'Positief dingetje 1'
          }, {
            title: 'Positief dingetje 2'
          }, {
            title: 'Positief dingetje 3'
          }],
          negatives: [{
            title: 'Negatief dingetje 1'
          }]
        };
      } else {
        $scope.list = lists[0];
        $scope.list.new = false;
      }
    } else {
      $scope.state = 'selectList';
      $scope.lists = lists;
    }
  });
});

import app from '../app';
import '../services/PlusMinClient';

app.controller('plusMinController', function ($element, $scope, $http, PlusMinClient) {
  let client = PlusMinClient;
  $scope.state = 'loading';

  $scope.toState = function (state) {
    $scope.state = state;
  };

  $scope.openList = function (list) {
    $scope.list = list;
    $scope.list.new = false;
    $scope.state = 'editList';
  };

  $scope.openNewList = function () {
    $scope.list = {
      new: true,
      positives: [],
      negatives: []
    };
    $scope.state = 'editList';
  };

  client.loadLists().then(function (request) {
    let lists = request.data;

    if (lists.length < 2) {
      $scope.state = 'editList';

      if (lists.length === 0) {
        $scope.list = {
          new: true,
          positives: [],
          negatives: []
        };
      } else {
        $scope.list = lists[0];
        $scope.list.new = false;
      }
    } else {
      $scope.state = 'selectList';
      $scope.lists = lists;
    }
  });
});

Add list editor and list selector


$(document).ready(function () {
    if (!id_category_0.checked && !id_category_1.checked){
        $("#id_institution").parents('.row').hide();
        $("#id_department").parents('.row').hide();
    }
    $("#id_category_0").click(function () {
        $("#id_institution").parents('.row').show();
        $("#id_department").parents('.row').show();
    });
    $("#id_category_1").click(function () {
        $("#id_institution").parents('.row').hide();
        $("#id_department").parents('.row').hide();
    });
});

function ajax_filter_departments(institution_id)
{
   $("#id_department").html('<option value="">Loading...</option>');
   $.ajax({
       type: "GET",
       url: "/order/show_department",
       dataType: "json",
       data: {'institution':institution_id},
       success: function(retorno) {
           $("#id_department").empty();
           $("#id_department").append('<option value="">--------</option>');
           $.each(retorno, function(i, item){
               $("#id_department").append('<option value="'+item.pk+'">'+item.valor+'</option>');
           });
       },
       error: function(error) {
           alert('Error: No request return.');
       }
   });
}

$(document).ready(function () {
    if (!id_category_0.checked && !id_category_1.checked){
        $("#id_institution").parents('.row').hide();
        $("#id_department").parents('.row').hide();
    }
    $("#id_category_0").click(function () {
        $("#id_institution").parents('.row').show();
        $("#id_department").parents('.row').show();
    });
    $("#id_category_1").click(function () {
        $("#id_institution").parents('.row').hide();
        $("#id_department").parents('.row').hide();
    });
    if (id_category_1.checked){
        $("#id_institution").parents('.row').hide();
        $("#id_department").parents('.row').hide();
    }
});

function ajax_filter_departments(institution_id)
{
   $("#id_department").html('<option value="">Loading...</option>');
   $.ajax({
       type: "GET",
       url: "/order/show_department",
       dataType: "json",
       data: {'institution':institution_id},
       success: function(retorno) {
           $("#id_department").empty();
           $("#id_department").append('<option value="">--------</option>');
           $.each(retorno, function(i, item){
               $("#id_department").append('<option value="'+item.pk+'">'+item.valor+'</option>');
           });
       },
       error: function(error) {
           alert('Error: No request return.');
       }
   });
}

Hide fields if "Consumption items" is selected


module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    username: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true
    },
    salt: DataTypes.STRING
  }, {
    classMethods: {
      associate(models) {
        User.hasMany(models.Message, {
          foreignKey: 'userId',
          as: 'userMessages'
        });
        User.belongsToMany(models.Group, {
          as: 'Members',
          foreignKey: 'groupId',
          through: 'UserGroup',
        });
      }
    }
  });
  return User;
};

module.exports = (sequelize, DataTypes) => {
  const User = sequelize.define('User', {
    username: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true,
    },
    password: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    email: {
      type: DataTypes.STRING,
      allowNull: false,
      unique: true
    },
    salt: DataTypes.STRING
  });

  User.associate = (models) => {
    User.hasMany(models.Message, {
      foreignKey: 'userId'
    });
    User.belongsToMany(models.Group, {
      as: 'Members',
      foreignKey: 'groupId',
      through: 'UserGroup',
    });
  };
  return User;
};

Edit model associations using new syntax


Package.describe({
  summary: "Wrapper around the bcrypt npm package",
  version: "0.9.2",
  documentation: null
});

Npm.depends({
  bcryptjs: "2.3.0"
});

Package.onUse(function (api) {
  api.use("modules@0.7.5", "server");
  api.mainModule("wrapper.js", "server");
  api.export("NpmModuleBcrypt", "server");
});

Package.describe({
  summary: "Wrapper around the bcrypt npm package",
  version: "0.9.2",
  documentation: null
});

Npm.depends({
  bcryptjs: "2.3.0"
});

Package.onUse(function (api) {
  api.use("modules", "server");
  api.mainModule("wrapper.js", "server");
  api.export("NpmModuleBcrypt", "server");
});

Remove pinned version of `modules` from `npm-bcrypt`.


/**
 * @flow
 */
import path from "path"

import flattenConfiguration from "./configuration/flattenConfiguration"
import start from "./commands/start"
import build from "./commands/build"

function normalizeConfiguration(config: PhenomicInputConfig): PhenomicConfig {
  return {
    path: config.path || process.cwd(),
    outdir: config.outdir || path.join(process.cwd(), "dist"),
    bundler: config.bundler(),
    renderer: config.renderer(),
    plugins: flattenConfiguration(config).map(plugin => plugin()),
    port: config.port || 1414,
  }
}

export default {
  start(config: PhenomicInputConfig) {
    return start(normalizeConfiguration(config))
  },
  build(config: PhenomicInputConfig) {
    return build(normalizeConfiguration(config))
  },
}

/**
 * @flow
 */
import path from "path"

import flattenConfiguration from "./configuration/flattenConfiguration"
import start from "./commands/start"
import build from "./commands/build"

const normalizePlugin = (plugin) => {
  if (!plugin) {
    throw new Error(
      "phenomic: You provided an undefined plugin"
    )
  }

  if (typeof plugin !== "function") {
    throw new Error(
      "phenomic: You provided an plugin with type is " +
      typeof plugin +
      ". But function is expected instead of " +
      plugin
    )
  }

  // @todo send config here
  return plugin()
}

function normalizeConfiguration(config: PhenomicInputConfig): PhenomicConfig {
  return {
    path: config.path || process.cwd(),
    outdir: config.outdir || path.join(process.cwd(), "dist"),
    bundler: config.bundler(),
    renderer: config.renderer(),
    plugins: flattenConfiguration(config).map(normalizePlugin),
    port: config.port || 1414,
  }
}

export default {
  start(config: PhenomicInputConfig) {
    return start(normalizeConfiguration(config))
  },
  build(config: PhenomicInputConfig) {
    return build(normalizeConfiguration(config))
  },
}

Add poor validation for plugins


'use strict';

module.exports = function(kbox) {

  var events = kbox.core.events;
  var deps = kbox.core.deps;
  var envs = [];

  // EVENT: pre-engine-create
  events.on('pre-engine-create', function(createOptions, done) {
    var codeRoot = deps.lookup('globalConfig').codeDir;
    var kboxCode = 'KBOX_CODEDIR=' + codeRoot;
    envs.push(kboxCode);
    envs.push('KALABOX=true');

    // Add some app opts
    kbox.whenApp(function(app) {
      envs.push('APPNAME=' + app.name);
      envs.push('APPDOMAIN=' + app.domain);
    });

    if (createOptions.Env) {
      envs.forEach(function(env) {
        createOptions.Env.push(env);
      });
    }
    else {
      createOptions.Env = envs;
    }
    done();
  });

};

'use strict';

var _ = require('lodash');

module.exports = function(kbox) {

  var events = kbox.core.events;
  var deps = kbox.core.deps;

  // EVENT: pre-engine-create
  events.on('pre-engine-create', function(createOptions, done) {
    var envs = [];
    var codeRoot = deps.lookup('globalConfig').codeDir;
    var kboxCode = 'KBOX_CODEDIR=' + codeRoot;
    envs.push(kboxCode);
    envs.push('KALABOX=true');

    // Add some app opts
    kbox.whenApp(function(app) {
      envs.push('APPNAME=' + app.name);
      envs.push('APPDOMAIN=' + app.domain);
    });

    if (createOptions.Env) {
      envs.forEach(function(env) {
        if (!_.includes(createOptions.Env, env)) {
          createOptions.Env.push(env);
        }
      });
    }
    else {
      createOptions.Env = envs;
    }
    done();
  });

};

Fix some ENV add bugs


/**
 * head.script.js
 *
 * Essential scripts, to be loaded in the head of the document
 * Use gruntfile.js to include the necessary script files.
 */

// Load respimage if <picture> element is not supported
if(!window.HTMLPictureElement){
	enhance.loadJS('/assets/javascript/lib/polyfills/respimage.min.js');
}

/**
 * head.script.js
 *
 * Essential scripts, to be loaded in the head of the document
 * Use gruntfile.js to include the necessary script files.
 */

// Load respimage if <picture> element is not supported
if(!window.HTMLPictureElement) {
	document.createElement('picture');
	enhance.loadJS('/assets/javascript/lib/polyfills/respimage.min.js');
}

Create hidden picture element when respimage is loaded.


// slack invite links expire after 30 days and you can't(at least as far as i can tell) create tokens for things like slackin anymore

const fs = require('fs')

const slackInviteLink = process.argv[2]

const siteHeaderPath = `${__dirname}/../site/src/components/SiteHeader.js`
const readmePath = `${__dirname}/../README.md`

const slackInviteLinkRegex = /https:\/\/join\.slack\.com\/t\/emotion-slack\/shared_invite\/[^\/]+\//

const siteHeader = fs.readFileSync(siteHeaderPath, 'utf8')

fs.writeFileSync(
  siteHeaderPath,
  siteHeader.replace(slackInviteLinkRegex, slackInviteLink)
)

const readme = fs.readFileSync(readmePath, 'utf8')

fs.writeFileSync(
  readmePath,
  readme.replace(slackInviteLinkRegex, slackInviteLink)
)

// slack invite links expire after 30 days and you can't(at least as far as i can tell) create tokens for things like slackin anymore

const fs = require('fs')

const slackInviteLink = process.argv[2]

const siteHeaderPath = `${__dirname}/../site/src/components/SiteHeader.js`
const readmePath = `${__dirname}/../README.md`

const slackInviteLinkRegex = /https:\/\/join\.slack\.com\/t\/emotion-slack\/shared_invite\/[^/]+\//

const siteHeader = fs.readFileSync(siteHeaderPath, 'utf8')

fs.writeFileSync(
  siteHeaderPath,
  siteHeader.replace(slackInviteLinkRegex, slackInviteLink)
)

const readme = fs.readFileSync(readmePath, 'utf8')

fs.writeFileSync(
  readmePath,
  readme.replace(slackInviteLinkRegex, slackInviteLink)
)

Fix regex to comply with no-useless-escape ESLint rule


'use strict';
import React from 'react';

/**
 * Method to display the title of a variant.
 * 1st option is the ClinVar Preferred Title if it's present.
 * 2nd alternative is a string constructed with the canonical transcript, gene symbol and protein change.
 * The fallback is the GRCh38 NC_ HGVS name.
 * @param {object} variant - A variant object
 */
export function renderVariantTitle(variant) {
    let variantTitle;
    if (variant) {
        if (variant.clinvarVariantId && variant.clinvarVariantTitle) {
            variantTitle = variant.clinvarVariantTitle;
        } else if (variant.carId && variant.canonicalTranscriptTitle) {
            variantTitle = variant.canonicalTranscriptTitle;
        } else if (variant.hgvsNames && Object.keys(variant.hgvsNames).length && !variantTitle) {
            if (variant.hgvsNames.GRCh38) {
                variantTitle = variant.hgvsNames.GRCh38 + ' (GRCh38)';
            } else if (variant.hgvsNames.GRCh37) {
                variantTitle = variant.hgvsNames.GRCh37 + ' (GRCh37)';
            } else {
                variantTitle = variant.carId ? variant.carId : 'A preferred title is not available';
            }
        }
    }
    return {variantTitle};
}

'use strict';
import React from 'react';

/**
 * Method to display the title of a variant.
 * 1st option is the ClinVar Preferred Title if it's present.
 * 2nd alternative is a string constructed with the canonical transcript, gene symbol and protein change.
 * The fallback is the GRCh38 NC_ HGVS name.
 * @param {object} variant - A variant object
 * @param {boolean} stringOnly - Whether the output should be just string
 */
export function renderVariantTitle(variant, stringOnly) {
    let variantTitle;
    if (variant) {
        if (variant.clinvarVariantId && variant.clinvarVariantTitle) {
            variantTitle = variant.clinvarVariantTitle;
        } else if (variant.carId && variant.canonicalTranscriptTitle) {
            variantTitle = variant.canonicalTranscriptTitle;
        } else if (variant.hgvsNames && Object.keys(variant.hgvsNames).length && !variantTitle) {
            if (variant.hgvsNames.GRCh38) {
                variantTitle = variant.hgvsNames.GRCh38 + ' (GRCh38)';
            } else if (variant.hgvsNames.GRCh37) {
                variantTitle = variant.hgvsNames.GRCh37 + ' (GRCh37)';
            } else {
                variantTitle = variant.carId ? variant.carId : 'A preferred title is not available';
            }
        }
    }
    if (stringOnly) {
        return variantTitle;
    } else {
        return {variantTitle};
    }
}

Add option to only return a string instead of JSX


import PropTypes from 'prop-types';
import React from 'react';
import { Col } from 'react-flexbox-grid/lib';
import { DeleteButton } from './IconButton';

const SourceOrCollectionWidget = (props) => {
  const { object, onDelete, onClick, children } = props;
  const isCollection = object.tags_id !== undefined;

  const typeClass = isCollection ? 'collection' : 'source';
  const objectId = object.id || (isCollection ? object.tags_id : object.media_id);
  const name = isCollection ? (object.name || object.label || object.tag) : (object.name || object.label || object.url);
  return (
    <div
      className={`media-widget ${typeClass}`}
      key={`media-widget${objectId}`}
    >
      <Col>
        {name}
        {children}
      </Col>
      <Col>
        <DeleteButton onClick={onDelete} />
      </Col>

  );
};

SourceOrCollectionWidget.propTypes = {
  object: PropTypes.object.isRequired,
  onDelete: PropTypes.func,
  onClick: PropTypes.func,
  children: PropTypes.node,
};

export default SourceOrCollectionWidget;

import PropTypes from 'prop-types';
import React from 'react';
import { Col } from 'react-flexbox-grid/lib';
import { DeleteButton } from './IconButton';

const SourceOrCollectionWidget = (props) => {
  const { object, onDelete, onClick, children } = props;
  const isCollection = object.tags_id !== undefined;

  const typeClass = isCollection ? 'collection' : 'source';
  const objectId = object.id || (isCollection ? object.tags_id : object.media_id);
  const name = isCollection ? (object.name || object.label || object.tag) : (object.name || object.label || object.url);
  // link the text if there is a click handler defined
  let text = name;
  if (onClick) {
    text = ({name});
  }
  return (
    <div
      className={`media-widget ${typeClass}`}
      key={`media-widget${objectId}`}
    >
      <Col>
        {text}
        {children}
      </Col>
      <Col>
        {onDelete && <DeleteButton onClick={onDelete} />}
      </Col>

  );
};

SourceOrCollectionWidget.propTypes = {
  object: PropTypes.object.isRequired,
  onDelete: PropTypes.func,
  onClick: PropTypes.func,
  children: PropTypes.node,
};

export default SourceOrCollectionWidget;

Handle list of media/collections that aren't clickable


'use strict';

import React, {
  Animated,
  Platform,
  StyleSheet,
  View,
} from 'react-native';

import Layout from './Layout';

export default class TabBar extends React.Component {
  static propTypes = {
    ...View.propTypes,
    shadowStyle: View.propTypes.style,
  };

  render() {
    return (
      <Animated.View {...this.props} style={[styles.container, this.props.style]}>
        {this.props.children}
        <View style={[styles.shadow, this.props.shadowStyle]} />
      </Animated.View>
    );
  }
}

let styles = StyleSheet.create({
  container: {
    backgroundColor: '#f8f8f8',
    flexDirection: 'row',
    justifyContent: 'space-around',
    height: Layout.tabBarHeight,
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
  },
  shadow: {
    backgroundColor: 'rgba(0, 0, 0, 0.25)',
    height: Layout.pixel,
    position: 'absolute',
    left: 0,
    right: 0,
    top: Platform.OS === 'android' ? 0 : -Layout.pixel,
  },
});

'use strict';

import React, {
  Animated,
  Platform,
  StyleSheet,
  View,
} from 'react-native';

import Layout from './Layout';

export default class TabBar extends React.Component {
  static propTypes = {
    ...Animated.View.propTypes,
    shadowStyle: View.propTypes.style,
  };

  render() {
    return (
      <Animated.View {...this.props} style={[styles.container, this.props.style]}>
        {this.props.children}
        <View style={[styles.shadow, this.props.shadowStyle]} />
      </Animated.View>
    );
  }
}

let styles = StyleSheet.create({
  container: {
    backgroundColor: '#f8f8f8',
    flexDirection: 'row',
    justifyContent: 'space-around',
    height: Layout.tabBarHeight,
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
  },
  shadow: {
    backgroundColor: 'rgba(0, 0, 0, 0.25)',
    height: Layout.pixel,
    position: 'absolute',
    left: 0,
    right: 0,
    top: Platform.OS === 'android' ? 0 : -Layout.pixel,
  },
});

Use 'Animated.View.propTypes' to avoid warnings.


export default {
  countUpdated: () => ({
    // Run the query each time count updated
    countUpdated: () => true
  })
};

export default {
  countUpdated: () => ({
    // Run the query each time count updated
    countUpdated: {
      filter: () => {
        return true;
      }
    }
  })
};

Fix Counter subscription filter definition


import _ from 'underscore';
import Model from 'girder/models/Model';

import ElementCollection from '../collections/ElementCollection';
import convert from '../annotations/convert';

export default Model.extend({
    resourceName: 'annotation',

    defaults: {
        'annotation': {}
    },

    initialize() {
        this._elements = new ElementCollection(
            this.get('annotation').elements || []
        );
        this._elements.annotation = this;

        this.listenTo(this._elements, 'change add remove', () => {
            // copy the object to ensure a change event is triggered
            var annotation = _.extend({}, this.get('annotation'));

            annotation.elements = this._elements.toJSON();
            this.set('annotation', annotation);
        });
    },

    /**
     * Return the annotation as a geojson FeatureCollection.
     *
     * WARNING: Not all annotations are representable in geojson.
     * Annotation types that cannot be converted will be ignored.
     */
    geojson() {
        const json = this.get('annotation') || {};
        const elements = json.elements || [];
        return convert(elements);
    },

    /**
     * Return a backbone collection containing the annotation elements.
     */
    elements() {
        return this._elements;
    }
});

import _ from 'underscore';
import Model from 'girder/models/Model';

import ElementCollection from '../collections/ElementCollection';
import convert from '../annotations/convert';

export default Model.extend({
    resourceName: 'annotation',

    defaults: {
        'annotation': {}
    },

    initialize() {
        this._elements = new ElementCollection(
            this.get('annotation').elements || []
        );
        this._elements.annotation = this;

        this.listenTo(this._elements, 'change add remove reset', () => {
            // copy the object to ensure a change event is triggered
            var annotation = _.extend({}, this.get('annotation'));

            annotation.elements = this._elements.toJSON();
            this.set('annotation', annotation);
        });
    },

    /**
     * Return the annotation as a geojson FeatureCollection.
     *
     * WARNING: Not all annotations are representable in geojson.
     * Annotation types that cannot be converted will be ignored.
     */
    geojson() {
        const json = this.get('annotation') || {};
        const elements = json.elements || [];
        return convert(elements);
    },

    /**
     * Return a backbone collection containing the annotation elements.
     */
    elements() {
        return this._elements;
    }
});

Update annotation on reset events


import path from 'path';

const projectRoot = path.join(__dirname, '..');

export default {
  cache: true,
  entry: [
    path.join(projectRoot, 'src', 'hibp.js'),
  ],
  output: {
    library: 'hibp',
    libraryTarget: 'umd',
    path: path.join(projectRoot, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [
          path.join(projectRoot, 'src'),
        ],
        use: [
          {
            loader: 'babel-loader',
            options: {
              babelrc: false,
              cacheDirectory: true,
              plugins: [
                'add-module-exports',
              ],
              presets: [
                [
                  'env',
                  {
                    targets: {
                      browsers: [
                        '> 1%',
                        'last 2 versions',
                      ],
                    },
                  },
                ],
              ],
            },
          },
        ],
      },
    ],
  },
  node: {
    fs: 'empty',
    module: 'empty',
    Buffer: false, // axios 0.16.1
  },
};

import path from 'path';

const projectRoot = path.join(__dirname, '..');

export default {
  cache: true,
  entry: [
    path.join(projectRoot, 'src', 'hibp.js'),
  ],
  output: {
    library: 'hibp',
    libraryTarget: 'umd',
    umdNamedDefine: true,
    path: path.join(projectRoot, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: [
          path.join(projectRoot, 'src'),
        ],
        use: [
          {
            loader: 'babel-loader',
            options: {
              babelrc: false,
              cacheDirectory: true,
              plugins: [
                'add-module-exports',
              ],
              presets: [
                [
                  'env',
                  {
                    targets: {
                      browsers: [
                        '> 1%',
                        'last 2 versions',
                      ],
                    },
                  },
                ],
              ],
            },
          },
        ],
      },
    ],
  },
  node: {
    fs: 'empty',
    module: 'empty',
    Buffer: false, // axios 0.16.1
  },
};

Set the AMD module name in the UMD build


var dbm = require('db-migrate');
var type = dbm.dataType;

exports.up = function(db, callback) {
  db.createTable('users', {
    columns: {
      id:         { type: 'int', primaryKey: true, autoIncrement: true },
      firstName:  { type: 'string', notNull: true},
      lastName:   { type: 'string', notNull: true},
      email:      { type: 'string', notNull: true},
      hash:       { type: 'string', notNull: true},
      salt:       { type: 'string', notNull: true}
    },
    ifNotExists: true
  }, callback);
};

exports.down = function(db, callback) {

};

var dbm = require('db-migrate');
var type = dbm.dataType;

exports.up = function(db, callback) {
  db.createTable('users', {
    columns: {
      id:         { type: 'int', primaryKey: true, autoIncrement: true },
      firstName:  { type: 'string', notNull: true},
      lastName:   { type: 'string', notNull: true},
      email:      { type: 'string', notNull: true},
      hash:       { type: 'string', notNull: true},
      salt:       { type: 'string', notNull: true}
    },
    ifNotExists: true
  }, callback);
};

exports.down = function(db, callback) {
  console.log('not dropping table users');
  callback();
};

Call user migrate down callback


"use strict";

const electron = require("electron");
const {app} = electron;
const {Menu} = electron;
const {BrowserWindow} = electron;

module.exports.setDevMenu = function () {
    var devMenu = Menu.buildFromTemplate([{
        label: "Development",
        submenu: [{
            label: "Reload",
            accelerator: "CmdOrCtrl+R",
            click: function () {
                BrowserWindow.getFocusedWindow().reload();
            }
        },{
            label: "Toggle DevTools",
            accelerator: "Alt+CmdOrCtrl+I",
            click: function () {
                BrowserWindow.getFocusedWindow().toggleDevTools();
            }
        },{
            label: "Quit",
            accelerator: "CmdOrCtrl+Q",
            click: function () {
                app.quit();
            }
        }]
    }]);
    Menu.setApplicationMenu(devMenu);
};

"use strict";

const electron = require("electron");
const {app} = electron;
const {Menu} = electron;
const {BrowserWindow} = electron;

module.exports.setDevMenu = function () {
    var devMenu = Menu.buildFromTemplate([{
        label: "Development",
        submenu: [{
            label: "Reload",
            accelerator: "F5",
            click: function () {
                BrowserWindow.getFocusedWindow().reload();
            }
        },{
            label: "Toggle DevTools",
            accelerator: "Alt+CmdOrCtrl+I",
            click: function () {
                BrowserWindow.getFocusedWindow().toggleDevTools();
            }
        },{
            label: "Quit",
            accelerator: "CmdOrCtrl+Q",
            click: function () {
                app.quit();
            }
        }]
    }]);
    Menu.setApplicationMenu(devMenu);
};

Change development reload shortcut to F5


#!/usr/bin/env node

var assert = require('assert');
var jade = require('jade');

var source = [
'each v, i in list',
'  div #{v},#{i}'
].join('\n');

var fn = jade.compile(source);
var html = fn({ list:['a', 'b', 'c'] });

assert.strictEqual(html, '
a,0

b,1

c,2
');

// #{} と !{}
var source = [
'|#{str}',
'|!{str}'
].join('\n');

var fn = jade.compile(source);
var text = fn({ str:'a&b' });

assert.strictEqual(text, 'a&b\na&b');

Add a sample of jade


import array from 'role:@sanity/form-builder/input/array?'
import boolean from 'role:@sanity/form-builder/input/boolean?'
import date from 'role:@sanity/form-builder/input/date?'
import email from 'role:@sanity/form-builder/input/email?'
import geopoint from 'role:@sanity/form-builder/input/geopoint?'
import number from 'role:@sanity/form-builder/input/number?'
import object from 'role:@sanity/form-builder/input/object?'
import reference from 'role:@sanity/form-builder/input/reference?'
import string from 'role:@sanity/form-builder/input/string?'
import text from 'role:@sanity/form-builder/input/text?'
import url from 'role:@sanity/form-builder/input/url?'

import DefaultReference from '../inputs/Reference'

const coreTypes = {
  array,
  boolean,
  date,
  email,
  geopoint,
  number,
  object,
  reference: reference || DefaultReference,
  string,
  text,
  url
}

const inputResolver = (field, fieldType) => {
  const inputRole = coreTypes[field.type] || coreTypes[fieldType.name]
  return field.input || inputRole
}

export default inputResolver

import array from 'role:@sanity/form-builder/input/array?'
import boolean from 'role:@sanity/form-builder/input/boolean?'
import date from 'role:@sanity/form-builder/input/date?'
import email from 'role:@sanity/form-builder/input/email?'
import geopoint from 'role:@sanity/form-builder/input/geopoint?'
import number from 'role:@sanity/form-builder/input/number?'
import object from 'role:@sanity/form-builder/input/object?'
import reference from 'role:@sanity/form-builder/input/reference?'
import string from 'role:@sanity/form-builder/input/string?'
import text from 'role:@sanity/form-builder/input/text?'
import url from 'role:@sanity/form-builder/input/url?'

import DefaultReference from '../inputs/Reference'

const primitiveTypes = {
  array,
  boolean,
  date,
  number,
  object,
  reference: reference || DefaultReference,
  string
}
const bundledTypes = {
  email,
  geopoint,
  text,
  url
}
const coreTypes = Object.assign({}, primitiveTypes, bundledTypes)

const inputResolver = (field, fieldType) => {
  const inputRole = coreTypes[field.type] || coreTypes[fieldType.name]
  return field.input || inputRole
}

export default inputResolver

Split up vars for consistency with official Sanity terms


# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

 // Place all the behaviors and hooks related to the matching controller here.
 // All this logic will automatically be available in application.js.
 // You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/

Remove HipsterScript-style comments from JS sources.


// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Parse.Cloud.define("hello", function(request, response) {
  response.success("Doms Cloud Code!");
});

// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:
Parse.Cloud.define("hello", function(request, response) {
console.log("hello5");
response.success("Doms Cloud Code");
});

//test function
Parse.Cloud.beforeSave("MatchScore", function(request, response) {
  if (request.object.get("P10Score") > 3) {
	response.error("Games are first to 3");
    //return response.error(JSON.stringify({code: ErrorCodes["450"], message: "Games are first to 3"}));
  } else {
    response.success();
  }
});

//User opt in/out of leaderboard
   Parse.Cloud.define("joinLeaderboard", function(request, response) {
		//set the leaderboard flag to true
	   var currentUser = Parse.User.current();
	   currentUser.set("Leaderboard", true);
	   currentUser.save();
	   var AddLeaderboard = Parse.Object.extend("LeaderBoard");

	    var AddLeaderboard = Parse.Object.extend("LeaderBoard");
		var query = new Parse.Query(AddLeaderboard);
		query.notEqualTo("Ranking", 0);
		query.count().then(function(count) {
				//success
				console.log(count);
				return count;
			}).then (function(count) {
				var currentUser = Parse.User.current();
				var addLeaderboard = new AddLeaderboard();
				var newPlayerRanking = count + 1;
				addLeaderboard.save({Ranking: newPlayerRanking, playerID: currentUser}, {
				   success: function(object) {
						console.log("User added to the leaderboard55");
						response.success("Learderboard Joined!!")
					  },
					  error: function(model, error) {
						console.error("Error User could not be added to the leaderboard");
					  }
				  });
			}, function(error) {
				//error
				console.log("error5");
				response.error("error5");
			});
	});

Add user to the leaderboard


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

const moment = require('moment');
const mocha = require('mocha');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
const { TimeInterval } = require('../../common/TimeInterval');

mocha.describe('Time Intervals', () => {
	mocha.it('can be created', async () => {
		const start = moment('1970-01-01 00:01:00');
		const end = moment('2069-12-31 00:01:00');
		const ti = new TimeInterval(start, end);
		expect(ti.toString()).to.equal('1970-01-01T06:01:00Z_2069-12-31T06:01:00Z');
	});

});

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

const moment = require('moment');
const mocha = require('mocha');
const chai = require('chai');
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
const expect = chai.expect;
const { TimeInterval } = require('../../common/TimeInterval');

mocha.describe('Time Intervals', () => {
	mocha.it('can be created', async () => {
		const start = moment('1970-01-01T00:01:00Z');
		const end = moment('2069-12-31T00:01:00Z');
		const ti = new TimeInterval(start, end);
		expect(ti.toString()).to.equal('1970-01-01T00:01:00Z_2069-12-31T00:01:00Z');
	});

});

Fix TimeInterval test by acknowledging time zones


const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const program = require('commander')
const getConfig = require('lingui-conf').default
const plurals = require('make-plural')

const config = getConfig()

program.parse(process.argv)

function validateLocales (locales) {
  const unknown = locales.filter(locale => !(locale in plurals))
  if (unknown.length) {
    console.log(chalk.red(`Unknown locale(s): ${unknown.join(', ')}.`))
    process.exit(1)
  }
}

function addLocale (locales) {
  if (!fs.existsSync(config.localeDir)) {
    fs.mkdirSync(config.localeDir)
  }

  locales.forEach(locale => {
    const localeDir = path.join(config.localeDir, locale)

    if (fs.existsSync(localeDir)) {
      console.log(chalk.yellow(`Locale ${chalk.underline(locale)} already exists.`))
    } else {
      fs.mkdirSync(localeDir)
      console.log(chalk.green(`Added locale ${chalk.underline(locale)}.`))
    }
  })
}

validateLocales(program.args)

addLocale(program.args)
console.log()
console.log(`(use "${chalk.yellow('lingui extract')}" to extract messages)`)

const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const program = require('commander')
const getConfig = require('lingui-conf').default
const plurals = require('make-plural')

const config = getConfig()

function validateLocales (locales) {
  const unknown = locales.filter(locale => !(locale in plurals))
  if (unknown.length) {
    console.log(chalk.red(`Unknown locale(s): ${unknown.join(', ')}.`))
    process.exit(1)
  }
}

function addLocale (locales) {
  if (!fs.existsSync(config.localeDir)) {
    fs.mkdirSync(config.localeDir)
  }

  locales.forEach(locale => {
    const localeDir = path.join(config.localeDir, locale)

    if (fs.existsSync(localeDir)) {
      console.log(chalk.yellow(`Locale ${chalk.underline(locale)} already exists.`))
    } else {
      fs.mkdirSync(localeDir)
      console.log(chalk.green(`Added locale ${chalk.underline(locale)}.`))
    }
  })
}

program
  .description('Add target locales. Remove locale by removing <locale> directory from your localeDir (e.g. ./locale)')
  .arguments('<locale...>')
  .on('--help', function () {
    console.log('\n  Examples:\n')
    console.log('    # Add single locale')
    console.log('    $ lingui add-locale en')
    console.log('')
    console.log('    # Add multiple locales')
    console.log('    $ lingui add-locale en es fr ru')
  })
  .parse(process.argv)

if (!program.args.length) program.help()

validateLocales(program.args)

addLocale(program.args)

console.log()
console.log(`(use "${chalk.yellow('lingui extract')}" to extract messages)`)

Add help to add-locale command


module.exports = function allowQueryParams(params) {
    return function allowQueryParamsMiddleware(req, res, next) {
        req.context.allowedQueryParams = params;
        next();
    };
};

module.exports = function allowQueryParams(params) {
    if (!Array.isArray(params)) {
        throw new Error('allowQueryParams must receive an Array of params');
    }
    return function allowQueryParamsMiddleware(req, res, next) {
        req.context.allowedQueryParams = params;
        next();
    };
};

Throw on invalid params argument


'use strict';

require.config({
    paths: {
        raphael: '../raphael'
        //you will need eve if you use the nodeps version
        /*eve: '../bower_components/eve/eve'*/
    }
});

require(['raphael'], function(Raphael) {
    var paper = Raphael(0, 0, 640, 720, "container");
    paper.circle(100, 100, 100); //example

    // Work here
});

'use strict';

require.config({
    paths: {
        raphael: '../raphael'
        //you will need eve if you use the nodeps version
        /*eve: '../bower_components/eve/eve'*/
    }
});

require(['raphael'], function(Raphael) {
    var paper = Raphael(0, 0, 640, 720, "container");
    paper.circle(100, 100, 100).attr({'fill':'270-#FAE56B:0-#E56B6B:100'}); //example

    // Work here
});

Add gradient to test page


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require highlight.pack
//= require_tree .

$(document).ready(function() {
    $('pre').each(function(i, el) {
        hljs.highlightBlock(el);
    });

    $('code').each(function(i, el) {
        hljs.highlightBlock(el);
    });

    $('.vivus-documentation h1').each(function(i, el) {
        $('#vivus-navigation ul').append("
" + $(el).text() + "
");
        $(el).prepend("");
    })
});

Fix the navigation generating js


/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
var _      = require('lodash');
var events = require('events');

var CleanKill   = require('./cleankill');
var CliReporter = require('./clireporter');
var config      = require('./config');
var steps       = require('./steps');

module.exports = function test(options, done) {
  options = _.merge(config.defaults(), options);
  var emitter = new events.EventEmitter();

  new CliReporter(emitter, options.output, options);

  // Add plugin reporters
  _.values(options.plugins).forEach(function(plugin) {
    if (plugin.reporter) {
        new plugin.reporter(emitter, options.output, plugin);
    }
  });

  var cleanOptions = _.omit(options, 'output');
  emitter.emit('log:debug', 'Configuration:', cleanOptions);

  steps.runTests(options, emitter, function(error) {
    CleanKill.close(done.bind(null, error));
  });
  return emitter;
};

/**
 * @license
 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
 * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
 * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
 * Code distributed by Google as part of the polymer project is also
 * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
 */
var _      = require('lodash');
var events = require('events');

var CleanKill   = require('./cleankill');
var CliReporter = require('./clireporter');
var config      = require('./config');
var steps       = require('./steps');

module.exports = function test(options, done) {
  options = _.merge(config.defaults(), options);
  var emitter = new events.EventEmitter();

  new CliReporter(emitter, options.output, options);

  // Add plugin event listeners
  _.values(options.plugins).forEach(function(plugin) {
    if (plugin.listener) {
        new plugin.listener(emitter, options.output, plugin);
    }
  });

  var cleanOptions = _.omit(options, 'output');
  emitter.emit('log:debug', 'Configuration:', cleanOptions);

  steps.runTests(options, emitter, function(error) {
    CleanKill.close(done.bind(null, error));
  });
  return emitter;
};

Rename 'reporter' plugin hook to 'listener' as it's more semantic


import React from 'react';
import {
  Router,
  Route,
  hashHistory,
  IndexRoute
} from 'react-router';
import App from './App';
import RecentTracks from './components/RecentTracks';
import TopArtists from './components/TopArtists';

let AppRouter = React.createClass ({

  render() {
    return (
      <Router history={hashHistory}>
        <Route path="/" component={App}>
          <IndexRoute component={RecentTracks}/>
          <Route path="/recent-tracks" component={RecentTracks} />
          <Route path="/top-artists" component={TopArtists} />
        </Route>
      </Router>
    );
  }
});

export default AppRouter;

import React from 'react';
import {
  Router,
  Route,
  browserHistory,
  IndexRoute
} from 'react-router';
import App from './App';
import RecentTracks from './components/RecentTracks';
import TopArtists from './components/TopArtists';

let AppRouter = React.createClass ({

  render() {
    return (
      <Router history={browserHistory}>
        <Route path="/" component={App}>
          <IndexRoute component={RecentTracks}/>
          <Route path="/recent-tracks" component={RecentTracks} />
          <Route path="/top-artists" component={TopArtists} />
        </Route>
      </Router>
    );
  }
});

export default AppRouter;

Use browserHistory to get rid of url queries


var DEFAULT_MIN = 1;
var DEFAULT_MAX = 3;

App.QuantityWidgetComponent = Ember.Component.extend({

  tagName: 'div',
  classNameBindings: [ ':quantity-widget', 'isMin', 'isMax' ],
  attributeBindings: [ 'name:data-icon' ],

  actions: {
    increment: function () {
      if (this.get('isMax')) return;
      this.set('quantity', this.incrementProperty('quantity') );
    },

    decrement: function () {
      if (this.get('isMin')) return;
      this.set('quantity', this.decrementProperty('quantity') );
    }
  },

  quantity: DEFAULT_MIN,  // pass in your own to override.
  max: DEFAULT_MAX,
  min: DEFAULT_MIN,

  isMin: function () {
    return this.get('quantity') === this.get('min');
  }.property('quantity'),

  isMax: function () {
    return this.get('quantity') >= this.get('max');
  }.property('quantity')

});

var DEFAULT_MIN = 1;
var DEFAULT_MAX = 3;

App.QuantityWidgetComponent = Ember.Component.extend({

  tagName: 'div',
  classNameBindings: [ ':quantity-widget', 'isMin', 'isMax' ],
  attributeBindings: [ 'name:data-icon' ],

  actions: {
    increment: function () {
      if (this.get('isMax')) return;
      this.set('quantity', this.incrementProperty('quantity') );
    },

    decrement: function () {
      if (this.get('isMin')) return;
      this.set('quantity', this.decrementProperty('quantity') );
    }
  },

  quantity: DEFAULT_MIN,  // pass in your own to override.
  max: DEFAULT_MAX,
  min: DEFAULT_MIN,

  isMin: function () {
    return this.get('quantity') === this.get('min');
  }.property('quantity'),

  isMax: function () {
    return this.get('quantity') >= this.get('max');
  }.property('quantity'),

  maxTooltip: function () {
    return '%@ is the maximum quantity.'.fmt(this.get('max'));
  }.property('max')
});

Update quantity widget tooltips per prototype


import {
  addParameters,
  addDecorator,
  setCustomElements,
  withA11y
} from '@open-wc/demoing-storybook';

async function run() {
  const customElements = await (
    await fetch(new URL('../custom-elements.json', import.meta.url))
  ).json();
  setCustomElements(customElements);

  addDecorator(withA11y);

  addParameters({
    a11y: {
      config: {},
      options: {
        checks: { 'color-contrast': { options: { noScroll: true } } },
        restoreScroll: true
      }
    },
    docs: {
      iframeHeight: '200px'
    }
  });
}

run();

import {
  addParameters,
  addDecorator,
  setCustomElements,
  withA11y,
} from '@open-wc/demoing-storybook';

async function run() {
  const customElements = await (
    await fetch(new URL('../custom-elements.json', import.meta.url))
  ).json();
  setCustomElements(customElements);

  addDecorator(withA11y);

  addParameters({
    a11y: {
      config: {},
      options: {
        checks: { 'color-contrast': { options: { noScroll: true } } },
        restoreScroll: true,
      },
    },
    docs: {
      iframeHeight: '200px',
    },
  });
}

run();

Fix linting errors in generated code


import {
  AUTH_USER,
  UNAUTH_USER,
  AUTH_ERROR,
  SET_USER_DATA,
  SET_CREDIT_CARDS,
  SET_DEFAULT_CARD
} from '../constants/';

const initialState = {
  authenticated: false,
  errors: null,
  user: null,
  creditCardDefault: null,
  creditCards: null
};

const AuthReducer = (state=initialState, action) => {
  switch (action.type) {
    case AUTH_USER:
      return {
        ...state,
        authenticated: true,
        errors: []
      };
    case UNAUTH_USER:
      return {
        ...state,
        user: null,
        authenticated: false,
        errors: []
      }
    case AUTH_ERROR:
      return {
        ...state,
        errors: action.payload
      };
    case SET_USER_DATA:
      return {
        ...state,
        user: action.payload,
        errors: []
      };
    case SET_CREDIT_CARDS:
      return {
        ...state,
        creditCards: action.payload
      };
    case SET_DEFAULT_CARD:
      return {
        ...state,
        creditCardDefault: action.payload
      }
    default:
      return state;
  }
}

export default AuthReducer;

import {
  AUTH_USER,
  UNAUTH_USER,
  AUTH_ERROR,
  SET_USER_DATA,
  SET_CREDIT_CARDS,
  SET_DEFAULT_CARD,
  ADD_CREDIT_CARD
} from '../constants/';

const initialState = {
  authenticated: false,
  errors: null,
  user: null,
  creditCardDefault: null,
  creditCards: null
};

const AuthReducer = (state=initialState, action) => {
  switch (action.type) {
    case AUTH_USER:
      return {
        ...state,
        authenticated: true,
        errors: []
      };
    case UNAUTH_USER:
      return {
        ...state,
        user: null,
        authenticated: false,
        errors: []
      }
    case AUTH_ERROR:
      return {
        ...state,
        errors: action.payload
      };
    case SET_USER_DATA:
      return {
        ...state,
        user: action.payload,
        errors: []
      };
    case SET_CREDIT_CARDS:
      return {
        ...state,
        creditCards: action.payload
      };
    case SET_DEFAULT_CARD:
      return {
        ...state,
        creditCardDefault: action.payload
      }
    case ADD_CREDIT_CARD:
      return {
        ...state,
        creditCards: [
          ...state.creditCards,
          action.payload
        ]
      };
    default:
      return state;
  }
}

export default AuthReducer;

Refactor auth reducer to handler the new auth-card actions


if (typeof buster == "undefined") {
    var buster = {};
}

buster.util = (function () {
    var toString = Object.prototype.toString;
    var div = typeof document != "undefined" && document.createElement("div");

    return {
        isNode: function (obj) {
            if (!div) {
                return false;
            }

            try {
                div.appendChild(obj);
                div.removeChild(obj);
            } catch (e) {
                return false;
            }

            return true;
        },

        isElement: function (obj) {
            return obj && this.isNode(obj) && obj.nodeType === 1;
        },

        isArguments: function (obj) {
            if (typeof obj != "object" || typeof obj.length != "number" ||
                toString.call(obj) == "[object Array]") {
                return false;
            }

            if (typeof obj.callee == "function") {
                return true;
            }

            try {
                obj[obj.length] = 6;
                delete obj[obj.length];
            } catch (e) {
                return true;
            }

            return false;
        },

        keys: Object.keys || function (object) {
            var keys = [];

            for (var prop in object) {
                if (Object.prototype.hasOwnProperty.call(object, prop)) {
                    keys.push(prop);
                }
            }

            return keys;
        }
    };
}());

if (typeof module != "undefined") {
    module.exports = buster.util;
}

if (typeof buster == "undefined") {
    var buster = {};
}

buster.util = (function () {
    var toString = Object.prototype.toString;
    var div = typeof document != "undefined" && document.createElement("div");

    return {
        isNode: function (obj) {
            if (!div) {
                return false;
            }

            try {
                div.appendChild(obj);
                div.removeChild(obj);
            } catch (e) {
                return false;
            }

            return true;
        },

        isElement: function (obj) {
            return obj && this.isNode(obj) && obj.nodeType === 1;
        },

        isArguments: function (obj) {
            if (typeof obj != "object" || typeof obj.length != "number" ||
                toString.call(obj) == "[object Array]") {
                return false;
            }

            if (typeof obj.callee == "function") {
                return true;
            }

            try {
                obj[obj.length] = 6;
                delete obj[obj.length];
            } catch (e) {
                return true;
            }

            return false;
        },

        keys: function (object) {
            var keys = [];

            for (var prop in object) {
                if (Object.prototype.hasOwnProperty.call(object, prop)) {
                    keys.push(prop);
                }
            }

            return keys;
        }
    };
}());

if (typeof module != "undefined") {
    module.exports = buster.util;
}

Fix keys implementation - Object.keys does not work on functions


'use strict';

function TestResults(dataTable) {
    var Cucumber = require('cucumber');
    var TestResult = require('./testResult');
    var maximums = [0, 0, 0, 0];

    var testCollection = Cucumber.Type.Collection();

    (function rowToTestResult() {
        dataTable.getRows().syncForEach(function(row) {
            var testResult = new TestResult(row.raw()[0], row.raw()[1], row.raw()[2], row.raw()[3]);
            testCollection.add(testResult);
            row.raw().forEach(function(element, index) {
                if (maximums[index] < element.length) {
                    maximums[index] = element.length;
                }
            });
        });
    })();

    var self = {
        getTestResults: function getTestResults() {
            var newTests = Cucumber.Type.Collection();
            testCollection.syncForEach(function(test) {
                newTests.add(test);
            });
            return newTests;
        },
        attachTest: function attachTest(test) {
            testCollection.add(test);
        },
        getMaximums: function getMaximums() {
            return maximums;
        },
        raw: function raw() {
            var rawTests = [];
            testCollection.syncForEach(function(test) {
                rawTests.push(test.raw());
            });
            return rawTests;
        }
    };
    return self;
}

module.exports = TestResults;

'use strict';

function TestResults(dataTable) {
    var Cucumber = require('cucumber');
    var TestResult = require('./testResult');
    var maximums = [0, 0, 0, 0];

    var testCollection = Cucumber.Type.Collection();

    (function rowToTestResult() {
        var rows = dataTable.getRows();
        rows = rows.sort(function(a, b) {
            return (a.raw()[1]) < (b.raw()[1]);
        });

        rows.syncForEach(function(row) {
            var testResult = new TestResult(row.raw()[0], row.raw()[1], row.raw()[2], row.raw()[3]);
            testCollection.add(testResult);
            row.raw().forEach(function(element, index) {
                if (maximums[index] < element.length) {
                    maximums[index] = element.length;
                }
            });
        });
    })();

    var self = {
        getTestResults: function getTestResults() {
            var newTests = Cucumber.Type.Collection();
            testCollection.syncForEach(function(test) {
                newTests.add(test);
            });
            return newTests;
        },
        attachTest: function attachTest(test) {
            testCollection.add(test);
        },
        getMaximums: function getMaximums() {
            return maximums;
        },
        raw: function raw() {
            var rawTests = [];
            testCollection.syncForEach(function(test) {
                rawTests.push(test.raw());
            });
            return rawTests;
        }
    };
    return self;
}

module.exports = TestResults;

Sort test results according to version


var route = Ember.Route.extend({
    model: function() {
        return this.store.all('task');
    },
    afterModel: function(tasks, transition) {
        if (transition.targetName == "tasks.index") {
            if($(document).width() > 700) {
                Ember.run.next(this, function(){
                    var task = this.controllerFor('tasks')
                            .get('pendingTasks.firstObject');
                    if(task) {
                            this.transitionTo('task', tasks.get('firstObject'));
                    }
                })
            } else {
                this.transitionToRoute('mobileTasks');
            }
        }
    },
    actions: {
        error: function(reason, tsn) {
            var application = this.controllerFor('application');
            application.get('handleError').bind(application)(reason, tsn);
        }
    }
});

module.exports = route;

var route = Ember.Route.extend({
    model: function() {
        return this.store.all('task');
    },
    afterModel: function(tasks, transition) {
        if (transition.targetName == "tasks.index" || transition.targetName == "tasks") {
            if($(document).width() > 700) {
                Ember.run.next(this, function(){
                    var task = this.controllerFor('tasks')
                            .get('pendingTasks.firstObject');
                    if(task) {
                            this.transitionTo('task', tasks.get('firstObject'));
                    }
                })
            } else {
                this.transitionToRoute('mobileTasks');
            }
        }
    },
    actions: {
        error: function(reason, tsn) {
            var application = this.controllerFor('application');
            application.get('handleError').bind(application)(reason, tsn);
        }
    }
});

module.exports = route;

Check for multiple target routes for deciding when to transition.


import React from 'react'
import _ from 'lodash'
import fp from 'lodash/fp'

export default props => {
  const { children: text } = props

  const linkPattern = /([a-z]+:\/\/[^,\s]+)/g

  const parts = fp.filter(s => s !== '')(text.split(linkPattern))

  const textNodes = _.map(parts, (part, i) => {
    if (linkPattern.test(part)) {
      return {part}
    } else {
      return {part}
    }
  })

  return {textNodes}
}

import React from 'react'
import _ from 'lodash'
import fp from 'lodash/fp'

export default props => {
  const { children: text } = props

  // Anything starting with one or more word characters followed by :// is considered a link.
  const linkPattern = /(\w+:\/\/\S+)/g

  const parts = fp.filter(s => s !== '')(text.split(linkPattern))

  const textNodes = _.map(parts, (part, i) => {
    if (linkPattern.test(part)) {
      return {part}
    } else {
      return {part}
    }
  })

  return {textNodes}
}

Simplify regex for finding links


import BaseComponent from './flexberry-base';

export default BaseComponent.extend({
  tagName: 'td',
  classNames: [],
  column: null,
  record: null
});

import BaseComponent from './flexberry-base';

export default BaseComponent.extend({
  tagName: 'td',
  classNames: [],
  column: null,
  record: null,

  didInsertElement: function() {
    var _this = this;
    this.$('input').change(function() {
      _this.record.set(_this.column.propName, _this.$(this).val());
    });
  }
});

Add support of two way binding


import dissolve from 'dissolve'

function createDataStream() {
  return dissolve()
    .loop(function() {
      this
        .uint32("length")
        .int8("type")
        .tap(function() {
          if (this.vars.length) {
            this.buffer("data", this.vars.length);
          }
        })
        .tap(function() {
          this.push(this.vars);
          this.vars = {};
        });
    });
}

import dissolve from 'dissolve'

function createDataStream() {
  return dissolve()
    .loop(function() {
      this
        .uint32("length")
        .int8("type")
        .tap(function() {
          if (this.vars.length) {
            this.buffer("payload", this.vars.length);
          }
        })
        .tap(function() {
          this.push(this.vars);
          this.vars = {};
        });
    });
}

Modify binary payload to be called payload instead of data


export default {
  authToken: process.env.AUTH_TOKEN || 'secret',
  env: process.env.NODE_ENV,
  host: process.env.HOST || 'localhost',
  github: {
    apiUrl: 'https://api.github.com',
    username: process.env.GITHUB_USERNAME || 'username'
  },
  mongo: {
    url: process.env.MONGO_URL || 'mongodb://localhost:27017/FranVarney'
  },
  port: process.env.PORT || 8000
}

export default {
  authToken: process.env.AUTH_TOKEN || 'secret',
  env: process.env.NODE_ENV,
  host: process.env.HOST || 'localhost',
  github: {
    apiUrl: 'https://api.github.com',
    username: process.env.GITHUB_USERNAME || 'username'
  },
  jobs: {
    frequency: {
      githubActivity: process.env.JOBS_FREQUENCY_GITHUB || '00 */1 * * * *' // '00 00 03 * * *'
    }
  },
  mongo: {
    url: process.env.MONGO_URL || 'mongodb://localhost:27017/FranVarney'
  },
  port: process.env.PORT || 8000
}

Add github activity job frequency option


import React from 'react';
import renderHTML from 'react-render-html';
import SocketClient from './socket-client';
import PropTypes from 'prop-types';

class HTMLRenderer extends React.Component {
  constructor(props) {
    super(props);
    this.state = { html: '' };
  }
  componentDidMount() {
    this.socketClient = new SocketClient(this.props.location);
    this.socketClient.onData(html => this.setState({ html }));
  }
  componentDidUpdate() {
    if (this.props.onUpdate) {
      this.props.onUpdate();
    }
  }
  render() {
    return React.createElement('div', null, renderHTML(this.state.html));
  }
}

HTMLRenderer.propTypes = {
  location: PropTypes.shape({
    host: PropTypes.string.isRequired,
    pathname: PropTypes.string.isRequired,
  }).isRequired,
  onUpdate: PropTypes.func,
};

export default HTMLRenderer;

Add line breaks between methods in HTMLRenderer


import '@webcomponents/webcomponentsjs';

class View extends HTMLElement {
    static wrapped() {
        const Cls = document.registerElement(this.name, this);
        return (params) => Object.assign(new Cls(), params);
    }

    createdCallback() {
        if (!this.constructor.html) {
            return;
        }

        const template = new DOMParser().parseFromString(this.constructor.html, 'text/html');
        const content = document.importNode(template.head.firstChild.content, true);
        this.appendChild(content);
    }
}

export default View;

import '@webcomponents/webcomponentsjs';

class View extends HTMLElement {
    static wrapped() {
        customElements.define(this.name, this);
        return (params) => Object.assign(new this(), params);
    }

    constructor() {
        super();

        if (!this.constructor.html) {
            return;
        }

        const template = new DOMParser().parseFromString(this.constructor.html, 'text/html');
        const content = document.importNode(template.head.firstChild.content, true);
        this.appendChild(content);
    }
}

export default View;

Update to proper customElements spec


var ContextReplacementPlugin = require("webpack/lib/ContextReplacementPlugin");

module.exports = {
  entry: './build/index.js',
  output: {
    path: './build',
    filename: 'bundle.js'
  },
  node: {
    fs: "empty"
  },
  bail: true,
  debug: true,
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader' },
    ]
  },
  plugins: [
    new ContextReplacementPlugin(
      /codemirror\/mode.*$/,
      /codemirror\/mode.*\.js$/
    )
  ]
}

var ContextReplacementPlugin = require("webpack/lib/ContextReplacementPlugin");

module.exports = {
  entry: './build/index.js',
  output: {
    path: './build',
    filename: 'bundle.js'
  },
  node: {
    fs: "empty"
  },
  bail: true,
  debug: true,
  module: {
    loaders: [
      { test: /\.css$/, loader: 'style-loader!css-loader' },
      { test: /\.html$/, loader: "file?name=[name].[ext]" }
    ]
  }
}

Fix the codemirror bundle handling


// @flow

import { RGB_NEAREST, RGB_APPROX, LAB_NEAREST } from "constants/color";

export const BOOL = "BOOL";
export const ENUM = "ENUM";
export const RANGE = "RANGE";
export const STRING = "STRING";
export const PALETTE = "PALETTE";
export const COLOR_ARRAY = "COLOR_ARRAY";

export const COLOR_DISTANCE_ALGORITHM = {
  type: ENUM,
  options: [
    { name: "RGB", value: RGB_NEAREST },
    { name: "RGB (perceptual approx.)", value: RGB_APPROX },
    { name: "Lab", value: LAB_NEAREST }
  ],
  default: LAB_NEAREST
};

// @flow

import { RGB_NEAREST, RGB_APPROX, LAB_NEAREST } from "constants/color";

export const BOOL = "BOOL";
export const ENUM = "ENUM";
export const RANGE = "RANGE";
export const STRING = "STRING";
export const PALETTE = "PALETTE";
export const COLOR_ARRAY = "COLOR_ARRAY";

export const COLOR_DISTANCE_ALGORITHM = {
  type: ENUM,
  options: [
    { name: "RGB", value: RGB_NEAREST },
    { name: "RGB (perceptual approx.)", value: RGB_APPROX },
    { name: "Lab", value: LAB_NEAREST }
  ],
  default: RGB_APPROX
};

Switch default color distance algorithm for user to RGB_APPROX


import Ember from 'ember';
import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  store: Ember.inject.service(),
  flashMessages: Ember.inject.service(),
  isDisabled: false,
  isSelected: Ember.computed(
    'member',
    'participants.@each.member',
    function(){
      let mapped = this.get('participants').mapBy('member.id');
      if (mapped.includes(this.get('member.id'))) {
        return true;
      } else {
        return false;
      }
  }),
  toggleParticipant: task(function* (property, value){
    if (value) {
      let newParticipant = this.get('store').createRecord('participant', {
        member: this.get('member'),
        entry: this.get('model'),
      });
      try {
        yield newParticipant.save();
        this.get('flashMessages').success("Saved");
      } catch(e) {
        e.errors.forEach((error) => {
          this.get('flashMessages').danger(error.detail);
        });
        newParticipant.deleteRecord();
      }
    } else {
      let participant = this.get('model.participants').findBy('contest.id', this.get('contest.id'));
      if (participant) {
        try {
          yield participant.destroyRecord();
          this.get('flashMessages').success("Saved");
        } catch(e) {
          e.errors.forEach((error) => {
            this.get('flashMessages').danger(error.detail);
          });
        }
      }
    }
  }).restartable(),
});

import Ember from 'ember';
import { task } from 'ember-concurrency';

export default Ember.Component.extend({
  store: Ember.inject.service(),
  flashMessages: Ember.inject.service(),
  isDisabled: false,
  isSelected: Ember.computed(
    'member',
    'participants.@each.member',
    function(){
      let mapped = this.get('participants').mapBy('member.id');
      if (mapped.includes(this.get('member.id'))) {
        return true;
      } else {
        return false;
      }
  }),
  toggleParticipant: task(function* (property, value){
    if (value) {
      let newParticipant = this.get('store').createRecord('participant', {
        member: this.get('member'),
        entry: this.get('model'),
      });
      try {
        yield newParticipant.save();
        this.get('flashMessages').success("Saved");
      } catch(e) {
        e.errors.forEach((error) => {
          this.get('flashMessages').danger(error.detail);
        });
        newParticipant.deleteRecord();
      }
    } else {
      let participant = this.get('model.participants').findBy('member.id', this.get('member.id'));
      if (participant) {
        try {
          yield participant.destroyRecord();
          this.get('flashMessages').success("Saved");
        } catch(e) {
          e.errors.forEach((error) => {
            this.get('flashMessages').danger(error.detail);
          });
        }
      }
    }
  }).restartable(),
});

Fix double-no clicking on participants


import ActionTypes from '../constants/ActionTypes';
var AppDispatcher = require('./AppDispatcher');
var Config = require('../config/Config');
var RequestUtil = require('../utils/RequestUtil');

module.exports = {

  fetchApps: RequestUtil.debounceOnError(
    Config.getRefreshRate(),
    function (resolve, reject) {
      return function () {
        var url = Config.rootUrl + '/marathon/v2/apps';

        RequestUtil.json({
          url: url,
          success: function (response) {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_SUCCESS,
              data: response
            });
            resolve();
          },
          error: function (e) {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_ERROR,
              data: e.message
            });
            reject();
          },
          hangingRequestCallback: function () {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_ONGOING
            });
          }
        });
      };
    },
    {delayAfterCount: Config.delayAfterErrorCount}
  )

};

import ActionTypes from '../constants/ActionTypes';
var AppDispatcher = require('./AppDispatcher');
var Config = require('../config/Config');
var RequestUtil = require('../utils/RequestUtil');

module.exports = {

  fetchApps: RequestUtil.debounceOnError(
    Config.getRefreshRate(),
    function (resolve, reject) {
      return function () {
        const embed = 'embed=group.groups&embed=group.apps&' +
          'embed=group.apps.deployments&embed=group.apps.counts';
        let url = `${Config.rootUrl}/marathon/v2/groups?${embed}`;

        RequestUtil.json({
          url: url,
          success: function (response) {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_SUCCESS,
              data: response
            });
            resolve();
          },
          error: function (e) {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_ERROR,
              data: e.message
            });
            reject();
          },
          hangingRequestCallback: function () {
            AppDispatcher.handleServerAction({
              type: ActionTypes.REQUEST_MARATHON_APPS_ONGOING
            });
          }
        });
      };
    },
    {delayAfterCount: Config.delayAfterErrorCount}
  )

};

Change marathon endpoint to groups


class BpmCounter {
  constructor() {
    this.numTaps = 0;
    this.bpm = 0;
    this.startTapTime = new Date();
  }

  restart() {
    this.numTaps = 0;
    this.bpm = 0;
  }

  tick() {
    if (this.numTaps === 0) {
      this.startTapTime = new Date();
    }

    this.numTaps++;

    let currentTime = new Date();

    let timeDifferenceInMS = currentTime - this.startTapTime;

    this.bpm = this.numTaps / (timeDifferenceInMS / 1000) * 60;
  }
}

class BpmCounter {
  constructor() {
    this.numTaps = 0;
    this.bpm = 0;
    this.startTapTime = new Date();
  }

  restart() {
    this.numTaps = 0;
    this.bpm = 0;
  }

  tick() {
    if (this.numTaps === 0) {
      this.startTapTime = new Date();
    }

    this.numTaps++;

    let currentTime = new Date();

    let timeDifferenceInMS = currentTime - this.startTapTime;

    if (timeDifferenceInMS === 0) {
      this.bpm = "First tap";
    } else {
      this.bpm = this.numTaps / (timeDifferenceInMS / 1000) * 60;
    }
  }
}

Fix bug where the first tap gave a bpm of infinity


import React, { PropTypes } from 'react';

import APINotLoaded from 'es6!display/not_loaded';
import ChangesUI from 'es6!display/changes/ui';

import * as api from 'es6!server/api';

import custom_content_hook from 'es6!utils/custom_content';

/*
 * Shows artifacts for a jobstep
 */
export var JobstepDetails = React.createClass({
  propTypes: {
    jobstepID: PropTypes.string,
  },

  getInitialState: function() {
    return {};
  },

  componentDidMount: function() {
    api.fetch(this, {
      artifacts: `/api/0/jobsteps/${this.props.jobstepID}/artifacts/`
    });
  },

  render: function() {
    var { jobstepID, className, ...props} = this.props;

    if (!api.isLoaded(this.state.artifacts)) {
      return <APINotLoaded calls={this.state.artifacts} />;
    }
    var artifacts = this.state.artifacts.getReturnedData();

    className = (className || "") + " jobstepDetails";

    return

      {this.renderArtifacts(artifacts)}

;
  },

  renderArtifacts(artifacts) {
    var markup = [];
    if (artifacts.length > 0) {
      markup.push(
Artifacts
);
      _.each(artifacts, a => {
        markup.push(

            {a.name}

        );
      });
    }

    return markup;
  }
});

import React, { PropTypes } from 'react';

import APINotLoaded from 'es6!display/not_loaded';
import ChangesUI from 'es6!display/changes/ui';

import * as api from 'es6!server/api';

import custom_content_hook from 'es6!utils/custom_content';

/*
 * Shows artifacts for a jobstep
 */
export var JobstepDetails = React.createClass({
  propTypes: {
    jobstepID: PropTypes.string,
  },

  getInitialState: function() {
    return {};
  },

  componentDidMount: function() {
    api.fetch(this, {
      details: `/api/0/jobsteps/${this.props.jobstepID}/artifacts/`
    });
  },

  render: function() {
    var { jobstepID, className, ...props} = this.props;

    if (!api.isLoaded(this.state.details)) {
      return <APINotLoaded calls={this.state.details} />;
    }
    var details = this.state.details.getReturnedData();

    className = (className || "") + " jobstepDetails";

    return

      {this.renderArtifacts(details.artifacts)}

;
  },

  renderArtifacts(artifacts) {
    var markup = [];
    if (artifacts.length > 0) {
      markup.push(
Artifacts
);
      _.each(artifacts, a => {
        markup.push(

            {a.name}

        );
      });
    }

    return markup;
  }
});

Fix artifact display on job steps (which broke because the API changes to return an object rather than a list)


const util = require('util');
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const request = require('./request');

class Server {

  constructor(verbose) {
    this.app = new Koa();

    this.app.use(async (ctx, next) => {
      try {
        await next();
      } catch (error) {
        ctx.status = 400;
        ctx.body = {error: error.message};
      }
    });

    this.app.use(bodyParser({
      enableTypes: ['json'],
      strict: true,
    }));

    this.app.use(async (ctx) => {
      let url = ctx.request.body.url;
      if (!url) throw new Error('Missing parameter url');
      let options = ctx.request.body.options;
      if (verbose) {
        if (options) {
          console.log(url, util.inspect(options, {depth: null, breakLength: Infinity}));
        } else {
          console.log(url);
        }
      }
      options = Object.assing({forever: true, gzip: true}, options);
      ctx.body = await request(url, options);
    });
  }

  listen(port = 80, address) {
    return new Promise((resolve, reject) => {
      try {
        this.app.listen(port, address, () => {
          resolve();
        });
      } catch (error) {
        reject(error);
      }
    });
  }

}

module.exports = Server;

const util = require('util');
const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const request = require('./request');

class Server {

  constructor(verbose) {
    this.app = new Koa();

    this.app.use(async (ctx, next) => {
      try {
        await next();
      } catch (error) {
        ctx.status = 400;
        ctx.body = {error: error.message};
      }
    });

    this.app.use(bodyParser({
      enableTypes: ['json'],
      strict: true,
    }));

    this.app.use(async (ctx) => {
      let url = ctx.request.body.url;
      if (!url) throw new Error('Missing parameter url');
      let options = ctx.request.body.options;
      if (verbose) {
        if (options) {
          console.log(url, util.inspect(options, {depth: null, breakLength: Infinity}));
        } else {
          console.log(url);
        }
      }
      options = Object.assing({forever: true, gzip: true}, options);
      try {
        ctx.body = await request(url, options);
      } catch (error) {
        ctx.status = 502;
        ctx.body = {error: error.message};
      }
    });
  }

  listen(port = 80, address) {
    return new Promise((resolve, reject) => {
      try {
        this.app.listen(port, address, () => {
          resolve();
        });
      } catch (error) {
        reject(error);
      }
    });
  }

}

module.exports = Server;

Return HTTP 502 and error message if upstream server error.


import Ember from 'ember';

export default Ember.Controller.extend({
  sortProperties: [
    'statusSort:asc',
    'organizationKindSort:asc',
    'nomen:asc',
  ],
  sortedSessions: Ember.computed.sort(
    'model',
    'sortProperties'
  ),
  actions: {
    sortBy(sortProperties) {
      this.set('sortProperties', [sortProperties]);
    },
  }
});

import Ember from 'ember';

export default Ember.Controller.extend({
  sortProperties: [
    'statusSort:asc',
    'organizationKindSort:asc',
    'nomen:asc',
  ],
  uniqueSessions: Ember.computed.uniq(
    'model',
  ),
  sortedSessions: Ember.computed.sort(
    'uniqueSessions',
    'sortProperties'
  ),
  actions: {
    sortBy(sortProperties) {
      this.set('sortProperties', [sortProperties]);
    },
  }
});

Fix duplicates on session manager