var logger = require('log4js').getLogger('vaildMessage');

var nconf = require('nconf');
nconf.file('bots', __dirname + '/../config/bots.json')
     .file('receviers', __dirname + '/../config/receivers.json')
     .file('senders', __dirname + '/../config/senders.json');

function vaildMessage(receiver,message,botname,sender,password){

  //If miss message, return error code 369

  if(message === undefined){

    return {error:369};
  }

  //If receiver not found, return error code 333

  if(nconf.get(receiver) === undefined){

    return {error:333};
  }

  if(nconf.get(sender) === undefined){

    return {error:380};
  }

  //If bot not found, return error code 360

  if(nconf.get(botname) === undefined){

    return {error:360};
  }

  //If password missmatch, return error code 361

  if(password !== nconf.get(sender).password1 &&
     password !== nconf.get(sender).password2){

    return {error:361};
  }
}

module.exports = {
  'vaildMessage':vaildMessage
};

var logger = require('log4js').getLogger('vaildMessage');

var nconf = require('nconf');
nconf.file('bots', __dirname + '/../config/bots.json')
     .file('receviers', __dirname + '/../config/receivers.json')
     .file('senders', __dirname + '/../config/senders.json');

function vaildMessage(receiver,message,botname,sender,password){

  //If miss message, return error code 369

  if(message === undefined){

    return {error:369};
  }

  //If receiver not found, return error code 333

  if(nconf.get(receiver) === undefined){

    return {error:333};
  }

  //If sender not found, return error code 380

  if(nconf.get(sender) === undefined){

    return {error:380};
  }

  //If bot not found, return error code 360

  if(nconf.get(botname) === undefined){

    return {error:360};
  }

  //If password missmatch, return error code 361

  if(password !== nconf.get(sender).password1 &&
     password !== nconf.get(sender).password2){

    return {error:361};
  }

  //If there are not any error, return null error

  return {error:null};

}

module.exports = {
  'vaildMessage':vaildMessage
};

Add comment to undefined sender


var odbc = require("../");
//odbc.library = '/usr/lib/odbc/libsqlite3odbc-0.91';
//odbc.library = '/usr/lib/x86_64-linux-gnu/odbc/libtdsodbc';

exports.connectionString = "DRIVER={SQLite3};DATABASE=data/sqlite-test.db";
//exports.connectionString = "DRIVER={MySQL};DATABASE=test;HOST=localhost;USER=test;";
//exports.connectionString = process.env.ODBC_CONNETION_STRING;

exports.connectionObject = {
	DRIVER : "{SQLITE3}",
	DATABASE : "data/sqlite-test.db"
};

exports.connections = [
	{
		DRIVER : "{SQLITE3}",
		DATABASE : "data/sqlite-test.db"
	}
];

exports.databaseName = "MAIN";
exports.tableName = "NODE_ODBC_TEST_TABLE";

exports.dropTables = function (db, cb) {
  db.query("drop table " + exports.tableName, cb);
};

exports.createTables = function (db, cb) {
  db.query("create table " + exports.tableName + " (COLINT INTEGER, COLDATETIME DATETIME, COLTEXT TEXT)", cb);
};

var odbc = require("../");
//odbc.library = '/usr/lib/odbc/libsqlite3odbc-0.91';
//odbc.library = '/usr/lib/x86_64-linux-gnu/odbc/libtdsodbc';
//odbc.library = '/opt/sqlncli-11.0.1790.0/lib64/libsqlncli-11.0';

exports.connectionString = "DRIVER={SQLite3};DATABASE=data/sqlite-test.db";
//exports.connectionString = "DRIVER={MySQL};DATABASE=test;HOST=localhost;USER=test;";
//exports.connectionString = process.env.ODBC_CONNETION_STRING;

exports.connectionObject = {
	DRIVER : "{SQLITE3}",
	DATABASE : "data/sqlite-test.db"
};

exports.connections = [
	{
		DRIVER : "{SQLITE3}",
		DATABASE : "data/sqlite-test.db"
	}
];

exports.databaseName = "MAIN";
exports.tableName = "NODE_ODBC_TEST_TABLE";

exports.dropTables = function (db, cb) {
  db.query("drop table " + exports.tableName, cb);
};

exports.createTables = function (db, cb) {
  db.query("create table " + exports.tableName + " (COLINT INTEGER, COLDATETIME DATETIME, COLTEXT TEXT)", cb);
};

Add libsqlncli library to test with


const BaseStep = require('../step');
const path = require('path');
const fs = require('fs');
const analytics = require('../../helpers/analytics/analytics')('fs');
const debugError = require('debug')('mendel:reader:error');

class FileReader extends BaseStep {
    constructor({registry}, {projectRoot}) {
        super();

        this.projectRoot = projectRoot;
        this.registry = registry;
        this.sourceExt = new Set();
    }

    perform(entry) {
        const filePath = path.resolve(this.projectRoot, entry.id);

        analytics.tic('read');
        fs.readFile(filePath, 'utf8', (error, source) => {
            analytics.toc('read');
            if (error) {
                debugError(`Errored while reading ${filePath}`);
                // TODO: uncomment line below, fix resolver
                // throw error;
            }

            this.registry.addRawSource(entry.id, source);
            this.emit('done', {entryId: entry.id});
        });
    }
}

module.exports = FileReader;

const BaseStep = require('../step');
const path = require('path');
const fs = require('fs');
const analytics = require('../../helpers/analytics/analytics')('fs');
const debugError = require('debug')('mendel:reader:error');

class FileReader extends BaseStep {
    constructor({registry}, {projectRoot, types}) {
        super();

        this.projectRoot = projectRoot;
        this.registry = registry;
        this._typeMap = new Map();
        types.forEach(type => this._typeMap.set(type.name, type));
        this.sourceExt = new Set();
    }

    perform(entry) {
        const filePath = path.resolve(this.projectRoot, entry.id);
        const entryType = this.registry.getType(entry.id);
        const isBinary = !this._typeMap.has(entryType) || this._typeMap.get(entryType).isBinary;

        if (entryType === 'virtual') {
            return this.emit('done', {entryId: entry.id});
        }

        analytics.tic('read');
        fs.readFile(filePath, isBinary ? 'binary' : 'utf8', (error, source) => {
            analytics.toc('read');
            if (error) {
                debugError(`Errored while reading ${filePath}`);
                // TODO: uncomment line below, fix resolver
                // throw error;
            }

            this.registry.addRawSource(entry.id, source);
            this.emit('done', {entryId: entry.id});
        });
    }
}

module.exports = FileReader;

Read file in appropriate encoding according to type


angular.module('zeus.reviews', [])
.controller('ReviewsController', function($location, $stateParams, Details, authService) {
  var ReviewsVm = this;
  ReviewsVm.id = $stateParams.id;
  ReviewsVm.review = {};
  ReviewsVm.user = {};
  ReviewsVm.movie = {};
  ReviewsVm.currentUser = JSON.parse(localStorage.getItem('profile'));
  Details.getReviewById(ReviewsVm.id)
    .then(function(reviewInfo){
      ReviewsVm.review = reviewInfo.review;
      ReviewsVm.user = reviewInfo.user;
      Details.getDetails(reviewInfo.review.type, reviewInfo.review.typeId)
      .then(function(movieInfo){
        ReviewsVm.movie = movieInfo;
        console.log(movieInfo)
      })
    });

  ReviewsVm.vote = function(vote) {
    if(ReviewsVm.currentUser !== null){
      Details.upvote(ReviewsVm.review._id, vote)
        .then(function(reviewInfo) {
          ReviewsVm.review.voteCount = reviewInfo.voteCount;
          ReviewsVm.review.votes = reviewInfo.votes;
        });
    } else {
      ReviewsVm.login();
    }
  };

  ReviewsVm.edit = function(){
    $location.path($location.url()+"/edit");
  }

  ReviewsVm.delete = function() {
      Details.deleteReview(ReviewsVm.review._id);
      $location.path('/') //Needs to redirect to somewhere useful
    };

  ReviewsVm.login = authService.login;
});

angular.module('zeus.reviews', [])
.controller('ReviewsController', function($location, $stateParams, Details, authService, Reviews) {

  var ReviewsVm = this;
  ReviewsVm.id = $stateParams.id;
  ReviewsVm.review = {};
  ReviewsVm.user = {};
  ReviewsVm.movie = {};
  ReviewsVm.currentUser = JSON.parse(localStorage.getItem('profile'));
  Reviews.getReviewById(ReviewsVm.id)
    .then(function(reviewInfo){
      ReviewsVm.review = reviewInfo.review;
      ReviewsVm.user = reviewInfo.user;
      Details.getDetails(reviewInfo.review.type, reviewInfo.review.typeId)
      .then(function(movieInfo){
        ReviewsVm.movie = movieInfo;
        console.log(movieInfo);
      });
    });

  ReviewsVm.vote = function(vote) {
    if(ReviewsVm.currentUser !== null){
      Reviews.upvote(ReviewsVm.review._id, vote)
        .then(function(reviewInfo) {
          ReviewsVm.review.voteCount = reviewInfo.voteCount;
          ReviewsVm.review.votes = reviewInfo.votes;
        });
    } else {
      ReviewsVm.login();
    }
  };

  ReviewsVm.edit = function(){
    $location.path($location.url()+"/edit");
  };

  ReviewsVm.delete = function() {
      Reviews.deleteReview(ReviewsVm.review._id);
      $location.path('/'); //Needs to redirect to somewhere useful
    };

  ReviewsVm.login = authService.login;
});

Change functions removed from Details factory to run from new Reviews Factory


// @flow

import { PropTypes } from "react";

export const statusIds = ["ontrack", "atrisk", "intervention", "onhold"];
export type Status = "ontrack" | "atrisk" | "intervention" | "onhold";

export const tabIds = ["edit"];
export type TabId = "edit";

export type Label = {
  id: string,
  title: string
};

export const labelInfoShape = {
  id: PropTypes.string.isRequired,
  initial: PropTypes.string.isRequired,
  colour: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired
};
export type LabelInfo = {
  id: string,
  initial: string,
  colour: string,
  title: string
};

export const projectShape = {
  title: PropTypes.string.isRequired,
  person: PropTypes.string.isRequired,
  time: PropTypes.string.isRequired,
  progress: PropTypes.number.isRequired,
  status: PropTypes.oneOf(statusIds).isRequired,
  labels: PropTypes.arrayOf(PropTypes.string).isRequired
};
export type Project = {
  id: string,
  title: string,
  person: string,
  time: string,
  progress: number,
  status: Status,
  labels: string[]
};

export type ProjectWithLabelInfo = {
  id: string,
  title: string,
  person: string,
  time: string,
  progress: number,
  status: Status,
  labels: LabelInfo[]
};

// @flow

export const statusIds = ["ontrack", "atrisk", "intervention", "onhold"];
export type Status = "ontrack" | "atrisk" | "intervention" | "onhold";

export const tabIds = ["edit"];
export type TabId = "edit";

export type Label = {
  id: string,
  title: string
};

export type LabelInfo = {
  id: string,
  initial: string,
  colour: string,
  title: string
};

export type Project = {
  id: string,
  title: string,
  person: string,
  time: string,
  progress: number,
  status: Status,
  labels: string[]
};

export type ProjectWithLabelInfo = {
  id: string,
  title: string,
  person: string,
  time: string,
  progress: number,
  status: Status,
  labels: LabelInfo[]
};

Remove PropTypes, which are used anymore


import Phaser from 'phaser'

export const centerGameObjects = objects => {
  objects.forEach(
    object => object.anchor.setTo(0.5)
  )
}

export const enableMusicForState = (trackName, state) => {
  const music = state.game.add.audio(trackName, 0, true, true)
  music.play()

  const muteButton = state.game.input.keyboard.addKey(Phaser.Keyboard.M)
  muteButton.onDown.add(() => {
    if (music.volume > 0) {
      music.volume = 0
    } else {
      music.volume = 1
    }
  }, state)

  return () => {
    music.stop()
  }
}

import Phaser from 'phaser'

export const centerGameObjects = objects => {
  objects.forEach(
    object => object.anchor.setTo(0.5)
  )
}

export const enableMusicForState = (trackName, state) => {
  const music = state.game.add.audio(trackName, 0, true, true)
  music.play()

  const muteButton = state.game.input.keyboard.addKey(Phaser.Keyboard.M)
  muteButton.onDown.add(() => {
    if (music.volume > 0) {
      music.volume = 0
    } else {
      music.volume = 0.25
    }
  }, state)

  return () => {
    music.stop()
  }
}

Make music quieter by default


// @flow

import * as React from 'react';
import { TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

import { connect } from 'lib/utils/redux-utils';

import type { AppState } from '../../redux/redux-setup';
import { styleSelector } from '../../themes/colors';

type Props = {|
  onPress: () => void,
  // Redux state
  styles: typeof styles,
|};
function SaveSettingButton(props: Props) {
  return (
    <TouchableOpacity onPress={props.onPress} style={props.styles.container}>
      <Icon
        name="md-checkbox-outline"
        size={24}
        style={props.styles.editIcon}
      />
    </TouchableOpacity>
  );
}

const styles = {
  container: {
    width: 26,
  },
  editIcon: {
    color: 'greenButton',
    position: 'absolute',
    right: 0,
    top: -3,
  },
};
const stylesSelector = styleSelector(styles);

export default connect((state: AppState) => ({
  styles: stylesSelector(state),
}))(SaveSettingButton);

// @flow

import * as React from 'react';
import { TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';

import { useStyles } from '../../themes/colors';

type Props = {|
  +onPress: () => void,
|};
function SaveSettingButton(props: Props) {
  const styles = useStyles(unboundStyles);
  return (
    <TouchableOpacity onPress={props.onPress} style={styles.container}>
      <Icon name="md-checkbox-outline" size={24} style={styles.editIcon} />
    </TouchableOpacity>
  );
}

const unboundStyles = {
  container: {
    width: 26,
  },
  editIcon: {
    color: 'greenButton',
    position: 'absolute',
    right: 0,
    top: -3,
  },
};

export default SaveSettingButton;

Use hook instead of connect functions and HOC in SaveSettingButton


UI.once('init', function(){
	var c = $('#chat'),
	hide_userlist_at = 650,
	layout_delay = 200,
	narrow_at = 800,
	resizeTimer;

	setTimeout(doLayout, 1000);

	$(window).resize(function(){
		clearTimeout(resizeTimer);
		resizeTimer = setTimeout(onResize, layout_delay);
	});

	function doLayout(){
		var w = c.width();
		c[(w < hide_userlist_at ? 'add' : 'remove') + 'Class']('hide_userlist');
		$('.container')[(w < narrow_at ? 'add' : 'remove') + 'Class']('narrow');
		var taller = $('body').height() >= $(window).height();
		console.log("Taller?: " + taller);
		console.log("Body: " +  $('body').height()  + "   Window:" + $(window).height() + "  HTML:" +  $('html').height());
		$('.main')[(taller ? 'add' : 'remove') + "Class"]('taller');
	}

	function onResize(){
		doLayout();
		UI.emit('resize');
	}

	//stick the footer at the bottom of the page if we're on an iPad/iPhone due to viewport/page bugs in mobile webkit
	if(navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod'){
		$("#footer_container").css("position", "static");
	};
});

UI.once('init', function(){
	var c = $('#chat'),
	hide_userlist_at = 650,
	layout_delay = 200,
	narrow_at = 800,
	resizeTimer;

	setTimeout(doLayout, 1000);

	$(window).resize(function(){
		clearTimeout(resizeTimer);
		resizeTimer = setTimeout(onResize, layout_delay);
	});

	function doLayout(){
		var w = c.width();
		c[(w < hide_userlist_at ? 'add' : 'remove') + 'Class']('hide_userlist');
		$('.container')[(w < narrow_at ? 'add' : 'remove') + 'Class']('narrow');
		var taller = $('body').height() >= $(window).height();
		$('.main')[(taller ? 'add' : 'remove') + "Class"]('taller');
	}

	function onResize(){
		doLayout();
		UI.emit('resize');
	}

	//stick the footer at the bottom of the page if we're on an iPad/iPhone due to viewport/page bugs in mobile webkit
	if(navigator.platform == 'iPad' || navigator.platform == 'iPhone' || navigator.platform == 'iPod'){
		$("#footer_container").css("position", "static");
	};
});

Remove Console.log statements in client.


var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var SpecialofferSchema   = new Schema({
	name: { type: String, unique: true, index: true, set: toLower },
	img: String,
	description: String, // Short description
	body: String, // Page body
	partner: String,
	partner_product_id: String,
	urlid: { type: String, unique: true, index: true },
	date: { type: Date, default: Date.now, required: true, index: true },
	start_date: { type: Date, default: Date.now, index: true },
	end_date: { type: Date, default: Date.now, index: true },
});

SpecialofferSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "cr"
});

function toLower (v) {
	return v.toLowerCase();
}

module.exports = mongoose.model('Specialoffer', SpecialofferSchema);

var mongoose     = require('mongoose');
var Schema       = mongoose.Schema;

var ObjectId = mongoose.Schema.Types.ObjectId;
var Mixed = mongoose.Schema.Types.Mixed;

var Location = require("./location_model");

var SpecialofferSchema   = new Schema({
	name: { type: String, unique: true, index: true },
	img: String,
	description: String, // Short description
	body: String, // Page body
	link: String,
	partner: String,
	partner_code: String,
	locations: [ { type: ObjectId, ref: "Location" } ],
	date: { type: Date, default: Date.now, required: true, index: true },
	start_date: { type: Date, default: Date.now, index: true },
	end_date: { type: Date, default: Date.now, index: true },
});

SpecialofferSchema.set("_perms", {
	admin: "crud",
	user: "cr",
	all: "cr"
});

function toLower (v) {
	return v.toLowerCase();
}

module.exports = mongoose.model('Specialoffer', SpecialofferSchema);

Rename some stuff and add locations


/**
 * Password authentication handler.
 *
 * This component provides an HTTP handler that authenticates a username and
 * password.  The credentials are submitted via an HTML form.
 */
exports = module.exports = function(parse, csrfProtection, authenticate, ceremony) {

  function establishSession(req, res, next) {
    req.login(req.user, function(err) {
      if (err) { return next(err); }
      return next();
    });
  }

  return [
    parse('application/x-www-form-urlencoded'),
    ceremony(
      csrfProtection(),
      authenticate('www-password', { session: false }),
      establishSession
    )
  ];

  /*
  return [
    parse('application/x-www-form-urlencoded'),
    ceremony('login/password',
      csrfProtection(),
      authenticate('password'),
    { through: 'login' })
  ];
  */
};

exports['@require'] = [
  'http://i.bixbyjs.org/http/middleware/parse',
  'http://i.bixbyjs.org/http/middleware/csrfProtection',
  'http://i.bixbyjs.org/http/middleware/authenticate',
  'http://i.bixbyjs.org/http/middleware/ceremony'
];

/**
 * Password authentication handler.
 *
 * This component provides an HTTP handler that authenticates a username and
 * password.  The credentials are submitted via an HTML form.
 */
exports = module.exports = function(parse, csrfProtection, authenticate, ceremony) {

  function establishSession(req, res, next) {
    req.login(req.user, function(err) {
      if (err) { return next(err); }
      return next();
    });
  }

  return [
    parse('application/x-www-form-urlencoded'),
    ceremony(
      csrfProtection(),
      authenticate('www-password', { session: false }),
      [ establishSession ]
    )
  ];

  /*
  return [
    parse('application/x-www-form-urlencoded'),
    ceremony('login/password',
      csrfProtection(),
      authenticate('password'),
    { through: 'login' })
  ];
  */
};

exports['@require'] = [
  'http://i.bixbyjs.org/http/middleware/parse',
  'http://i.bixbyjs.org/http/middleware/csrfProtection',
  'http://i.bixbyjs.org/http/middleware/authenticate',
  'http://i.bixbyjs.org/http/middleware/ceremony'
];

Establish session in default handler.


var repos = {};
var labels = {};
var configurable = require('../lib/configurable');

function addRepo(name, key, label) {
  configurable.get(key) && (repos[name] = configurable.get(key));
  configurable.get(key) && (labels[name] = (label || repos[name]));
}

configurable.setSilentMode(true);
addRepo('user-agent', 'PX_USER_AGENT', 'User Agent');
addRepo('dispatcher', 'PX_DISPATCHER', 'Dispatcher');
addRepo('platform', 'PX_PLATFORM', 'Platform');
addRepo('project-issues', 'PX_PROJECT_ISSUES', 'Project Issues');
addRepo('website', 'PX_PAGES', 'Website');

var maxDynaReposQuantity = 5;
for (i = 0; i < maxDynaReposQuantity; i++) {
  addRepo(configurable.get('REPO_' + i + '_NAME') || i + 'th', 'REPO_' + i + '_URL');
}

configurable.get('REPOS', function (value) {
  var chunks = value.split(';');
  chunks.forEach(function (chunk) {
    var val = chunk,
      nameRegex = /(https:\/\/api\.github\.com\/repos\/)?(.*)/;
    name = nameRegex.exec(val)[2],
      key = name.toLowerCase().replace('/', '_');

    var gitHubApiPrefix = 'https://api.github.com/repos/';
    repos[key] = gitHubApiPrefix + name;
    labels[key] = name;
  });
});

module.exports = {
  repos: repos,
  labels: labels
};

var repos = {};
var labels = {};
var configurable = require('../lib/configurable');

function addRepo(name, key, label) {
  configurable.get(key) && (repos[name] = configurable.get(key));
  configurable.get(key) && (labels[name] = (label || repos[name]));
}

configurable.setSilentMode(true);
addRepo('user-agent', 'PX_USER_AGENT', 'User Agent');
addRepo('dispatcher', 'PX_DISPATCHER', 'Dispatcher');
addRepo('puppet-pixelated', 'PX_PUPPET_PIXELATED', 'Puppet Pixelated');
addRepo('project-issues', 'PX_PROJECT_ISSUES', 'Project Issues');
addRepo('website', 'PX_PAGES', 'Website');

var maxDynaReposQuantity = 5;
for (i = 0; i < maxDynaReposQuantity; i++) {
  addRepo(configurable.get('REPO_' + i + '_NAME') || i + 'th', 'REPO_' + i + '_URL');
}

configurable.get('REPOS', function (value) {
  var chunks = value.split(';');
  chunks.forEach(function (chunk) {
    var val = chunk,
      nameRegex = /(https:\/\/api\.github\.com\/repos\/)?(.*)/;
    name = nameRegex.exec(val)[2],
      key = name.toLowerCase().replace('/', '_');

    var gitHubApiPrefix = 'https://api.github.com/repos/';
    repos[key] = gitHubApiPrefix + name;
    labels[key] = name;
  });
});

module.exports = {
  repos: repos,
  labels: labels
};

Change pixelated platform repo name


(function($) {
    'use strict';

    /**
     * Form Collection
     */
    $(document.body).on('click', '.contact_details_collection li', function(event) {

        var value,
            collectionHolder,
            prototype,
            regex,
            form,
            prototype_name,
            collectionContainer = $(this).closest('.contact-type-list').siblings('.collection-container');

        collectionHolder = collectionContainer.find('.' + $(this).parents('ul').data('target'));
        collectionHolder = collectionHolder.filter('[data-type=' + $(this).data('type')  + ']');

        value = $(this).data('value');

        prototype = collectionHolder.data('prototype');

        if(undefined !== prototype && null !== prototype) {
            if(collectionHolder.data('prototype-name')) {
                prototype_name = collectionHolder.data('prototype-name');
            } else {
                prototype_name = '__name__';
            }

            regex = new RegExp(prototype_name, "g");
            form = $(prototype.replace(regex, collectionHolder.children().length - 1)).hide();

            collectionContainer.append(form);

            form.slideDown();
        }
    });

})(window.jQuery);

(function($) {
    'use strict';

    /**
     * Form Collection
     */
    $(document.body).on('click', '.contact_details_collection li', function(event) {

        var $this = $(this),
            value,
            collectionHolder,
            prototype,
            regex,
            form,
            prototype_name,
            collectionContainer = $this.closest('.contact-type-list').siblings('.collection-container');

        collectionHolder = collectionContainer.find('.' + $this.parents('ul').data('target') + '[data-type=' + $this.data('type')  + ']');

        value = $(this).data('value');

        prototype = collectionHolder.data('prototype');

        if(undefined !== prototype && null !== prototype) {
            if(collectionHolder.data('prototype-name')) {
                prototype_name = collectionHolder.data('prototype-name');
            } else {
                prototype_name = '__name__';
            }

            regex = new RegExp(prototype_name, "g");
            form = $(prototype.replace(regex, collectionHolder.children().length)).hide();

            collectionHolder.append(form);

            form.slideDown();
        }
    });

})(window.jQuery);

Fix for adding contact details


jest.dontMock('../block_list')
jest.dontMock('../../utils/uid')

describe('Models - Block List', function() {
  var BlockList = require('../block_list')

  it ('can insert a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)

    expect(b.all()).toEqual([ 0 ])
  })

  it ('can insert a block at a given index', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)
    b.insertBlock(1, 1)

    expect(b.all()).toEqual([ 0, 1])
  })

  it ('can remove a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)
    b.insertBlock(1, 1)
    b.removeBlock(1)

    expect(b.all()).toEqual([ 0 ])
  })

  it ('can move a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)
    b.insertBlock(1, 1)
    b.move(1, 0)

    expect(b.all()).toEqual([ 1, 0 ])
  })

})

jest.dontMock('../block_list')
jest.dontMock('../../utils/uid')

describe('Models - Block List', function() {
  var BlockList = require('../block_list')

  it ('can insert a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)

    expect(b.all()).toEqual([ 0 ])
  })

  it ('can insert a block at a given index', function() {
    var b = new BlockList({})

    b.insertBlock(0, 1)
    b.insertBlock(1, 0)

    expect(b.all()).toEqual([ 1, 0])
  })

  it ('can remove a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)
    b.insertBlock(1, 1)
    b.removeBlock(1)

    expect(b.all()).toEqual([ 0 ])
  })

  it ('can move a block', function() {
    var b = new BlockList({})

    b.insertBlock(0, 0)
    b.insertBlock(1, 1)
    b.move(1, 0)

    expect(b.all()).toEqual([ 1, 0 ])
  })

})

Insert test to check for special types of insertion


var React = require('react');
var PropTypes = require('./PropTypes');

var RouteHandlerMixin = {

  contextTypes: {
    getRouteAtDepth: PropTypes.func.isRequired,
    setRouteComponentAtDepth: PropTypes.func.isRequired,
    routeHandlers: PropTypes.array.isRequired
  },

  childContextTypes: {
    routeHandlers: PropTypes.array.isRequired
  },

  getChildContext: function () {
    return {
      routeHandlers: this.context.routeHandlers.concat([ this ])
    };
  },

  getDefaultProps: function () {
    return {
      ref: '__routeHandler__'
    };
  },

  componentDidMount: function () {
    this._updateRouteComponent();
  },

  componentDidUpdate: function () {
    this._updateRouteComponent();
  },

  _updateRouteComponent: function () {
    this.context.setRouteComponentAtDepth(this.getRouteDepth(), this.refs[this.props.ref]);
  },

  getRouteDepth: function () {
    return this.context.routeHandlers.length;
  },

  createChildRouteHandler: function (props) {
    var route = this.context.getRouteAtDepth(this.getRouteDepth());
    return route ? React.createElement(route.handler, props || this.props) : null;
  }

};

module.exports = RouteHandlerMixin;

var React = require('react');
var assign = require('react/lib/Object.assign');
var PropTypes = require('./PropTypes');

var REF_NAME = '__routeHandler__';

var RouteHandlerMixin = {

  contextTypes: {
    getRouteAtDepth: PropTypes.func.isRequired,
    setRouteComponentAtDepth: PropTypes.func.isRequired,
    routeHandlers: PropTypes.array.isRequired
  },

  childContextTypes: {
    routeHandlers: PropTypes.array.isRequired
  },

  getChildContext: function () {
    return {
      routeHandlers: this.context.routeHandlers.concat([ this ])
    };
  },

  componentDidMount: function () {
    this._updateRouteComponent();
  },

  componentDidUpdate: function () {
    this._updateRouteComponent();
  },

  _updateRouteComponent: function () {
    this.context.setRouteComponentAtDepth(this.getRouteDepth(), this.refs[REF_NAME]);
  },

  getRouteDepth: function () {
    return this.context.routeHandlers.length;
  },

  createChildRouteHandler: function (props) {
    var route = this.context.getRouteAtDepth(this.getRouteDepth());
    return route ? React.createElement(route.handler, assign({}, props || this.props, { ref: REF_NAME })) : null;
  }

};

module.exports = RouteHandlerMixin;

Use constant instead of prop


const bunyan = require('bunyan')
const {getLogStreams} = require('./log-streams')
const NODE_ENV = process.env.NODE_ENV || 'unknown'

function createLogger(name, env = NODE_ENV) {
  if (process.env.USE_CONSOLE_LOG) {
    console.forAccount = () => {
      return console;
    }
    console.child = () => {
      return console;
    }
    return console;
  }

  const childLogs = new Map()
  const logger = bunyan.createLogger({
    name,
    env,
    serializers: bunyan.stdSerializers,
    streams: getLogStreams(name, env),
  })

  return Object.assign(logger, {
    forAccount(account = {}) {
      if (!childLogs.has(account.id)) {
        const childLog = logger.child({
          account_id: account.id,
          account_email: account.emailAddress,
        })
        childLogs.set(account.id, childLog)
      }
      return childLogs.get(account.id)
    },
  })
}

module.exports = {
  createLogger,
}

const bunyan = require('bunyan')
const {getLogStreams} = require('./log-streams')
const NODE_ENV = process.env.NODE_ENV || 'unknown'

function createLogger(name, env = NODE_ENV) {
  const childLogs = new Map()
  const logger = bunyan.createLogger({
    name,
    env,
    serializers: bunyan.stdSerializers,
    streams: getLogStreams(name, env),
  })

  return Object.assign(logger, {
    forAccount(account = {}) {
      if (!childLogs.has(account.id)) {
        const childLog = logger.child({
          account_id: account.id,
          account_email: account.emailAddress,
        })
        childLogs.set(account.id, childLog)
      }
      return childLogs.get(account.id)
    },
  })
}

module.exports = {
  createLogger,
}

Revert change, @evan’s fix is better


Ext.namespace('Kwc.List.Switch');

Kwc.List.Switch.Component = Ext.extend(Kwf.EyeCandy.List,
{
    //transition: {},
    showArrows: true,

    defaultState: 'normal',

    childSelector: '> div > .listSwitchItem',

    _init: function() {
        this.states = [
            'normal'
        ];

        if (!this.plugins) this.plugins = [];

        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveListener.LargeContentAjax({
            largeContainerSelector: '.listSwitchLargeContent',
            transition: this.transition.type,
            transitionConfig: this.transition
        }));
        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.Click({}));
        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.DefaultActiveClass({}));
        if (this.showArrows) {
            this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.NextPreviousLinks({
            }));
        }
        if (this.showPlayPause) {
            this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.PlayPauseLink({
                autoPlay: this.autoPlay
            }));
        }
        if (this.useHistoryState) {
            new Kwf.EyeCandy.List.Plugins.ActiveChanger.HistoryState({
            });
        }

        Kwc.List.Switch.Component.superclass._init.call(this);
    }
});

Ext.namespace('Kwc.List.Switch');

Kwc.List.Switch.Component = Ext.extend(Kwf.EyeCandy.List,
{
    //transition: {},
    showArrows: true,

    defaultState: 'normal',

    childSelector: '> div > .listSwitchItem',

    _init: function() {
        this.states = [
            'normal'
        ];

        if (!this.plugins) this.plugins = [];

        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveListener.LargeContentAjax({
            largeContainerSelector: '.listSwitchLargeContent',
            transition: this.transition.type,
            transitionConfig: this.transition
        }));
        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.Click({}));
        this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.DefaultActiveClass({}));
        if (this.showArrows) {
            this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.NextPreviousLinks({
            }));
        }
        if (this.showPlayPause) {
            this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.PlayPauseLink({
                autoPlay: this.autoPlay
            }));
        }
        if (this.useHistoryState) {
            this.plugins.push(new Kwf.EyeCandy.List.Plugins.ActiveChanger.HistoryState({
            }));
        }

        Kwc.List.Switch.Component.superclass._init.call(this);
    }
});

Add useHistoryState-plugin to plugins. (not only create)


export const ALERT_BANNER_ACTIVE = true

// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  tag: 'June 8-11',
  url: 'https://hashiconf.com/europe/?utm_source=DocsBanner',
  text: 'HashiConf Europe is happening now. Join all sessions live June 8 & 9.',
  linkText: 'Join Now',
  // Set the `expirationDate prop with a datetime string (e.g. `2020-01-31T12:00:00-07:00`)
  // if you'd like the component to stop showing at or after a certain date
  expirationDate: `2021-06-12T12:00:00-07:00`,
}

export const ALERT_BANNER_ACTIVE = true

// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  tag: 'Thank you',
  url: 'https://hashiconf.com/europe',
  text: 'HashiConf Europe is a wrap. Watch this year’s sessions on-demand.',
  linkText: 'Watch Now',
  // Set the `expirationDate prop with a datetime string (e.g. `2020-01-31T12:00:00-07:00`)
  // if you'd like the component to stop showing at or after a certain date
  expirationDate: `2021-06-20T12:00:00-07:00`,
}

Adjust alert banner for the end of HashiConf


var sass = require('node-sass');
var includePaths = '../stylesheets/lib-sass';

describe('validate type function', function() {
    var error = false;

    it('should return an error message when (1px "string" "") is passed', function(done) {
        sass.render({
           data: '$error: validate-type(1px "string" "")',
           includePaths: includePaths
        },
        function(error, result) { // node-style callback from v3.0.0 onwards
            if (error) {
                error = true;
                done();
            }
        });

        expect(error).toBe(true);
    });
    it('should return an error message when (1px "string" "") is passed', function() {
        sass.render({
           data: '$error: validate-type(1px "string" "")',
           includePaths: includePaths
        },
        function(error, result) { // node-style callback from v3.0.0 onwards
            if (error) {
                console.log(error.status); // used to be "code" in v2x and below
                console.log(error.column);
                console.log(error.message);
                console.log(error.line);
            } else {
            }
        });
    });
});

// var sass = require('node-sass');
var expect = require('chai').expect;
// var includePaths = '../stylesheets/lib-sass';

describe('validate type function', function() {
    it('should return an error message when (1px "string" "") is passed', function() {
        var foo = true;
        expect(foo).to.equal(true);
    });
});

// describe('validate type function', function() {
//     var error = false;

//     it('should return an error message when (1px "string" "") is passed', function(done) {
//         sass.render({
//         data: '$error: validate-type(1px "string" "")',
//         includePaths: includePaths
//     },
//         function(error) { // node-style callback from v3.0.0 onwards
//             if (error) {
//                 error = true;
//                 done();
//             }
//         });

//         expect(error).not.toBe(true);
//     });
// });

Use a dummy test to see if mocha works


const duration = require('@maxdome/duration');
const Throttle = require('redis-throttle');

module.exports = config => {
  Throttle.configure(config);
  return (key, limit, callback, fallback) => {
    let span = '1 second';
    if (typeof limit === 'string') {
      [limit, span] = limit.split(' per ');
    }
    span = duration(span).milliseconds();
    const throttle = new Throttle(key, { span, accuracy: span / 10 });
    return new Promise((resolve, reject) => {
      throttle.read((err, count) => {
        if (err) {
          reject(err);
          return;
        }
        if (count <= limit) {
          throttle.increment(1, err => {
            if (err) {
              reject(err);
              return;
            }
            resolve(callback());
          });
        } else {
          if (fallback) {
            resolve(fallback());
          } else {
            resolve();
          }
        }
      });
    });
  };
};

const duration = require('@dnode/duration');
const Throttle = require('redis-throttle');

module.exports = config => {
  Throttle.configure(config);
  return (key, limit, callback, fallback) => {
    let span = '1 second';
    if (typeof limit === 'string') {
      [limit, span] = limit.split(' per ');
    }
    span = duration(span).milliseconds();
    const throttle = new Throttle(key, { span, accuracy: span / 10 });
    return new Promise((resolve, reject) => {
      throttle.read((err, count) => {
        if (err) {
          reject(err);
          return;
        }
        if (count <= limit) {
          throttle.increment(1, err => {
            if (err) {
              reject(err);
              return;
            }
            resolve(callback());
          });
        } else {
          if (fallback) {
            resolve(fallback());
          } else {
            resolve();
          }
        }
      });
    });
  };
};

Use the right duration lib


// Handle endpoints for /config in this file

const configRouter = require('express').Router();
const keys = require('../config.js');

configRouter.get('/db', (req, res) => {
  res.status(200).send(keys.firebaseKey);
});

configRouter.get('/mapbox', (req, res) => {
  res.status(200).send(keys.mapboxKey);
});

module.exports = configRouter;

// Handle endpoints for /config in this file

const configRouter = require('express').Router();
const keys = require('../config.js');

configRouter.get('/db', (req, res) => {
  res.status(200).send(keys.firebaseKey);
});

// Not currently used due to syncState issue
// that is noted in resultBox.jsx
configRouter.get('/mapbox', (req, res) => {
  res.status(200).send(keys.mapboxKey);
});

module.exports = configRouter;

Add comment on unused /config route


define([
  'extensions/views/view',
  'common/views/visualisations/volumetrics/number',
  'common/views/visualisations/volumetrics/completion-graph'
],
function (View, VolumetricsNumberView, CompletionGraphView) {
  var CompletionRateView = View.extend({

    valueAttr: 'completion',
    totalAttr: 'totalCompletion',

    views: function () {
      return {
        '#volumetrics-completion-selected': {
          view: VolumetricsNumberView,
          options: {
            valueAttr: this.totalAttr,
            selectionValueAttr: this.valueAttr,
            formatValue: function (value) {
              return this.format(value, 'percent');
            }
          }
        },
        '#volumetrics-completion': {
          view: CompletionGraphView,
          options: {
            valueAttr: this.valueAttr
          }
        }
      };
    }
  });

  return CompletionRateView;
});

define([
  'extensions/views/view',
  'common/views/visualisations/volumetrics/number',
  'common/views/visualisations/volumetrics/completion-graph'
],
function (View, VolumetricsNumberView, CompletionGraphView) {
  return View.extend({

    valueAttr: 'completion',
    totalAttr: 'totalCompletion',

    views: function () {
      return {
        '.volumetrics-completion-selected': {
          view: VolumetricsNumberView,
          options: {
            valueAttr: this.totalAttr,
            selectionValueAttr: this.valueAttr,
            formatValue: function (value) {
              return this.format(value, 'percent');
            }
          }
        },
        '.volumetrics-completion': {
          view: CompletionGraphView,
          options: {
            valueAttr: this.valueAttr
          }
        }
      };
    }

  });
});

Swap ids for classes in completion rate template


const {mix} = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/assets/js/vue.js', 'public/build-js')
    .version();

const {mix} = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js('resources/assets/js/app.js', 'public/build-js')
    .version();

Make npm fail to test travis ci


const { mix } = require('laravel-mix');

/*
 |--------------------------------------------------------------------------
 | Mix Asset Management
 |--------------------------------------------------------------------------
 |
 | Mix provides a clean, fluent API for defining some Webpack build steps
 | for your Laravel application. By default, we are compiling the Sass
 | file for the application as well as bundling up all the JS files.
 |
 */

mix.js([
        'resources/assets/js/app.js'
    ], 'public/js/app.js')
   .sass('resources/assets/sass/app.scss', 'public/css/app.css')
   .sourceMaps();

if (mix.inProduction()) {
    mix.version();
}

Add Cache Busting in Production Code


export default function($stateProvider) {
    this.$get = function() {
        return {
            getResolves: function(state){
                var resolve = state.resolve || {},
                routes = ["login", "logout", "socket"];
                if(_.indexOf(routes, state.name)>-1){
                    return;
                }
                else{
                    resolve.features = ['FeaturesService', function(FeaturesService) {
                            return FeaturesService.get();
                        }];
                    return resolve;
                }
            },

            addState: function(state) {
                var route = state.route || state.url,
                resolve = this.getResolves(state);

                $stateProvider.state(state.name, {
                    url: route,
                    controller: state.controller,
                    templateUrl: state.templateUrl,
                    resolve: resolve,
                    params: state.params,
                    data: state.data,
                    ncyBreadcrumb: state.ncyBreadcrumb,
                    onEnter: state.onEnter,
                    onExit: state.onExit,
                    template: state.template,
                    controllerAs: state.controllerAs,
                    views: state.views
                });
            }
        };
    };
}

export default function($stateProvider) {
    this.$get = function() {
        return {
            getResolves: function(state){
                var resolve = state.resolve || {},
                routes = ["signIn", "signOut"];
                if(_.indexOf(routes, state.name)>-1){
                    return;
                }
                else{
                    resolve.features = ['FeaturesService', function(FeaturesService) {
                            return FeaturesService.get();
                        }];
                    return resolve;
                }
            },

            addState: function(state) {
                var route = state.route || state.url,
                resolve = this.getResolves(state);

                $stateProvider.state(state.name, {
                    url: route,
                    controller: state.controller,
                    templateUrl: state.templateUrl,
                    resolve: resolve,
                    params: state.params,
                    data: state.data,
                    ncyBreadcrumb: state.ncyBreadcrumb,
                    onEnter: state.onEnter,
                    onExit: state.onExit,
                    template: state.template,
                    controllerAs: state.controllerAs,
                    views: state.views
                });
            }
        };
    };
}

Remove route resolves from login/logout routes


const path = require('path');
const packagejson = require('./package.json');

const dashLibraryName = packagejson.name.replace(/-/g, '_');

module.exports = {
    entry: {main: './src/index.js'},
    output: {
        path: path.resolve(__dirname, dashLibraryName),
        filename: 'bundle.js',
        library: dashLibraryName,
        libraryTarget: 'window',
    },
    externals: {
        react: 'React',
        'react-dom': 'ReactDOM',
        'plotly.js': 'Plotly',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                },
            }
        ],
    },
};

const path = require('path');
const packagejson = require('./package.json');

const dashLibraryName = packagejson.name.replace(/-/g, '_');

module.exports = (env, argv) => ({
    entry: {main: './src/index.js'},
    output: {
        path: path.resolve(__dirname, dashLibraryName),
        filename: 'bundle.js',
        library: dashLibraryName,
        libraryTarget: 'window',
    },
    externals: {
        react: 'React',
        'react-dom': 'ReactDOM',
        'plotly.js': 'Plotly',
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                },
            }
        ],
    },
    devtool: argv.mode === 'development' ? "eval-source-map" : 'source-map'
});

Use eval-source-maps for dev package.


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

// eslint-disable-next-line import/no-extraneous-dependencies
const webpack = require('webpack');

const nodeModules = {};

// This is to filter out node_modules as we don't want them
// to be made part of any bundles.
fs.readdirSync('node_modules')
  .filter((x) => {
    return ['.bin'].indexOf(x) === -1;
  })
  .forEach((mod) => {
    nodeModules[mod] = `commonjs ${mod}`;
  });

module.exports = {
  entry: './src/main.js',
  target: 'node',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'addons-linter.js',
    libraryTarget: 'commonjs2',
  },
  module: {
    rules: [
      {
        use: 'babel-loader',
        // babel options are in .babelrc
        exclude: /(node_modules|bower_components)/,
        test: /\.js$/,
      },
      {
        use: 'raw-loader',
        exclude: /(node_modules|bower_components)/,
        test: /\.txt$/,
      },
    ],
  },
  externals: nodeModules,
  plugins: [
    new webpack.BannerPlugin(
      {
        banner: 'require("source-map-support").install();',
        raw: true,
        entryOnly: false,
      }
    ),
  ],
  resolve: {
    extensions: ['.js', '.json'],
    modules: [
      path.join(__dirname, 'src'),
      path.resolve(__dirname, 'node_modules'),
    ],
  },
  devtool: 'sourcemap',
};

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

// eslint-disable-next-line import/no-extraneous-dependencies
const webpack = require('webpack');

const nodeModules = {};

// This is to filter out node_modules as we don't want them
// to be made part of any bundles.
fs.readdirSync('node_modules')
  .filter((x) => {
    return ['.bin'].indexOf(x) === -1;
  })
  .forEach((mod) => {
    nodeModules[mod] = `commonjs ${mod}`;
  });

module.exports = {
  entry: './src/main.js',
  target: 'node',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'addons-linter.js',
    libraryTarget: 'commonjs2',
  },
  module: {
    rules: [
      {
        use: 'babel-loader',
        // babel options are in .babelrc
        exclude: /(node_modules|bower_components)/,
        test: /\.js$/,
      },
      {
        use: 'raw-loader',
        exclude: /(node_modules|bower_components)/,
        test: /\.txt$/,
      },
    ],
  },
  externals: nodeModules,
  plugins: [
    new webpack.BannerPlugin(
      {
        banner: 'require("source-map-support").install();',
        raw: true,
        entryOnly: false,
      }
    ),
  ],
  resolve: {
    extensions: ['.js', '.json'],
    modules: [
      'node_modules',
    ],
  },
  devtool: 'sourcemap',
};

Revert "Resolve src/ folder too"


define(["module"], function (module) {
  "use strict";

  function getInternetExplorerVersion() {
    var rv = -1;
    if (navigator.appName == "Microsoft Internet Explorer") {
      var ua = navigator.userAgent;
      var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
      if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
    } else if (navigator.appName == "Netscape") {
      var ua = navigator.userAgent;
      var re = new RegExp("Trident/.*rv:([0-9]{1,}[\\.0-9]{0,})");
      if (re.exec(ua) != null) rv = parseFloat(RegExp.$1);
    }
    return rv;
  }

  window.onload = function () {
    if (getInternetExplorerVersion()) {
      var labels = document.getElementsByTagName("label");
      for (var i = 0; i < labels.length; i++) {
        var label = labels[i];
        var labelImages = label.getElementsByTagName("img");

        for (var a = 0; a < labelImages.length; a++) {
          var labelImage = labelImages[a];
          labelImage.forid = label.htmlFor;
          labelImage.onclick = function () {
            var e = document.getElementById(this.forid);
            switch (e.type) {
              case "radio":
                e.checked |= 1;
                break;
              case "checkbox":
                e.checked = !e.checked;
                break;
              case "text":
              case "password":
              case "textarea":
                e.focus();
                break;
            }
          };
        }
      }
    }
  };
});

define(["module"], function (module) {
  "use strict";

  function getInternetExplorerVersion() {
    // https://stackoverflow.com/questions/21825157/internet-explorer-11-detection
    var isIE11 = !!window.MSInputMethodContext && !!document.documentMode;
    return isIE11;
  }

  function ready(fn) {
    if (document.readyState != "loading") {
      fn();
    } else {
      document.addEventListener("DOMContentLoaded", fn);
    }
  }

  function bindImageClickEvents() {
    document.addEventListener(
      "click",
      function (e) {
        if (e.target.tagName === "IMG") {
          var parent = e.target.parentNode;
          while (true) {
            if (!parent) {
              return;
            } else if (parent.tagName === "LABEL") {
              return parent.click();
            }
            parent = parent.parentNode;
          }
        }
      },
      false
    );
  }

  if (getInternetExplorerVersion()) {
    ready(function () {
      bindImageClickEvents();
    });
  }
});

Refactor IE11 image label fix


module.exports = {
  theme: "default",
  addons: {
    prependHeader: true,
    maxJsonSize: 400,
    alwaysFold: false,
    alwaysRenderAllContent: false,
    sortKeys: false,
    clickableUrls: true,
    openLinksInNewWindow: true,
    autoHighlight: true
  },
  structure: {
    readOnly: true,
    lineNumbers: true,
    lineWrapping: true,
    foldGutter: true,
    tabSize: 2,
    indentCStyle: false,
    showArraySize:true
  },
  style: [
    ".CodeMirror {",
    "  font-family: monaco, Consolas, Menlo, Courier, monospace;",
    "  font-size: 16px;",
    "  line-height: 1.5em;",
    "}"
  ].join('\n')
}

module.exports = {
  theme: "default",
  addons: {
    prependHeader: true,
    maxJsonSize: 400,
    alwaysFold: false,
    alwaysRenderAllContent: false,
    sortKeys: false,
    clickableUrls: true,
    openLinksInNewWindow: true,
    autoHighlight: true
  },
  structure: {
    readOnly: true,
    lineNumbers: true,
    lineWrapping: true,
    foldGutter: true,
    tabSize: 2,
    indentCStyle: false,
    showArraySize: false
  },
  style: [
    ".CodeMirror {",
    "  font-family: monaco, Consolas, Menlo, Courier, monospace;",
    "  font-size: 16px;",
    "  line-height: 1.5em;",
    "}"
  ].join('\n')
}

Set showArraySize to false by default


/*
 * HomePage
 *
 * This is the first thing users see of our App, at the '/' route
 *
 * NOTE: while this component should technically be a stateless functional
 * component (SFC), hot reloading does not currently support SFCs. If hot
 * reloading is not a necessity for you then you can refactor it and remove
 * the linting exception.
 */

import React from 'react';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
// import Img from './Img';
// import Headshot from './headshot.png';

export default class HomePage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
  render() {
    return (

              <FormattedMessage {...messages.header} />

                <FormattedMessage {...messages.header} />

    );
  }
}

/*
 * HomePage
 *
 * This is the first thing users see of our App, at the '/' route
 *
 * NOTE: while this component should technically be a stateless functional
 * component (SFC), hot reloading does not currently support SFCs. If hot
 * reloading is not a necessity for you then you can refactor it and remove
 * the linting exception.
 */

import React from 'react';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
// import Img from './Img';
// import Headshot from './headshot.png';

export default class HomePage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function
  render() {
    return (

              <FormattedMessage {...messages.header} />

                <FormattedMessage {...messages.header} />

                <FormattedMessage {...messages.header} />

    );
  }
}

Add more text to homepage


'use strict';

Darwinator.Helpers = {

  convertTileMap: function(layer) {
    var indexes = [];

    for (var i = 0; i < layer.length; i++) {
      indexes[i] = [];
      for(var l = 0; l < layer.length; l++) {
        indexes[i][l] = layer[i][l].index;
      }
    }
    return indexes;
  },

  pixelsToTile: function(x, y) {
    var pos = [];
    if (x < 0) {
      x = 0;
    }
    if (y < 0) {
      y = 0;
    }
    pos[0] = Math.floor(x / Darwinator.TILE_WIDTH);
    pos[1] = Math.floor(y / Darwinator.TILE_HEIGHT);
    return pos;
  },

  tileToPixels: function(x, y) {
    var pos = [];
    var tileWidth = Darwinator.TILE_WIDTH;
    var tileHeight = Darwinator.TILE_HEIGHT;
    pos[0] = Math.floor(x * tileWidth + (tileWidth / 2));
    pos[1] = Math.floor(y * tileHeight + (tileHeight / 2));
    return pos;
  }

};

'use strict';

Darwinator.Helpers = {

  convertTileMap: function(layer) {
    var indexes = [];

    for (var i = 0; i < layer.length; i++) {
      indexes[i] = [];
      for(var l = 0; l < layer.length; l++) {
        indexes[i][l] = layer[i][l].index;
      }
    }
    return indexes;
  },

  pixelsToTile: function(x, y) {
    var pos = [];
    if (x < 0) {
      x = 0;
    }
    if (y < 0) {
      y = 0;
    }
    pos[0] = Math.floor(x / Darwinator.TILE_WIDTH);
    pos[1] = Math.floor(y / Darwinator.TILE_HEIGHT);
    return pos;
  },

  tileToPixels: function(x, y) {
    var pos = [];
    var tileWidth = Darwinator.TILE_WIDTH;
    var tileHeight = Darwinator.TILE_HEIGHT;
    pos[0] = Math.floor(x * tileWidth + (tileWidth / 2));
    pos[1] = Math.floor(y * tileHeight + (tileHeight / 2));
    return pos;
  },

  /**
  * Calculates distance between two points. Works for both distance in pixels and distance in tiles.
  * @method Darwinator.Helpers#calculateDistance
  * @param {Array} - The first point, given as [x,y]
  * @param {Array} - The second point, given as [x,y]
  * @return {Number} The distance between the two points.
  */
  calculateDistance: function(pos1, pos2) {
    var dx = pos1[0] - pos2[0];
    var dy = pos1[1] - pos2[1];
    return Math.sqrt(dx*dx + dy*dy);
  }
};

Add helper for calculating distance between points


$(document).ready(function(){
  $('.container').on('click', '#favorite-icon', function(event) {
    var $favorite = $(event.target)
    $.ajax({
      type: "POST",
      //dan's localhost below
      url: "http://10.0.2.89:3000/favorites",
      data: $favorite.data()
    });
  });
});

$(document).ready(function(){
  $('.container').on('click', '#favorite-icon', function(event) {
    var sessionInfo = window.localStorage.getItem("sessionId");
    if (sessionInfo){
      var $favorite = $(event.target)
      $.ajax({
        type: "POST",
        //dan's localhost below
        url: "http://10.0.2.89:3000/favorites",
        data: $favorite.data()
      }).then(function(response){
        alert(response.status);
      });
    } else { alert("Sorry, please sign in to create favorites!") }
  });
});

Create ajax function in favroties.js to create new favorite


export function shortLabelFromNextGenMcasScore(score) {
  if (score >= 400 && score < 450) return 'NM'; // Not Meeting Expectations
  if (score >= 450 && score < 500) return 'PM'; // Partially Meeting
  if (score >= 500 && score < 550) return 'M'; // Meeting Expectations
  if (score >= 550 && score < 600) return 'E'; // Exceeding Expectations
  return null;
}

export function shortLabelFromOldMcasScore(score) {
  if (score >= 200 && score < 218) return 'W'; // Warning
  if (score >= 220 && score < 238) return 'NI'; // Needs Improvement
  if (score >= 240 && score < 258) return 'P'; // Proficient
  if (score >= 260 && score < 280) return 'E'; // Advanced
  return null;
}

export function shortLabelFromNextGenMcasScore(score) {
  if (score >= 400 && score < 450) return 'NM'; // Not Meeting Expectations
  if (score >= 450 && score < 500) return 'PM'; // Partially Meeting
  if (score >= 500 && score < 550) return 'M'; // Meeting Expectations
  if (score >= 550 && score < 600) return 'E'; // Exceeding Expectations
  return null;
}

export function shortLabelFromOldMcasScore(score) {
  if (score >= 200 && score <= 218) return 'W'; // Warning
  if (score >= 220 && score <= 238) return 'NI'; // Needs Improvement
  if (score >= 240 && score <= 258) return 'P'; // Proficient
  if (score >= 260 && score <= 280) return 'E'; // Advanced
  return null;
}

Update old MCAS score names to be inclusive ranges


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

/**
* Creates a that handles server redirects;
*/
exports.create = function (maximumRetries) {
  return function handle (resource, next, callback) {
    var currentRetries = 0;

    function handleRedirect(err, response, body) {
      if (response && response.headers &&
          response.headers.location &&
          response.statusCode >= 300 &&
          response.statusCode < 400 &&
          (!maximumRetries ||
          currentRetries < maximumRetries)) {
        currentRetries++;

        resource.url = response.headers.location;
        next(resource, handleRedirect);
      } else {
        callback(err, response, body);
      }
    }

    return next(resource, handleRedirect);
  };
};

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

/**
* Creates a that handles server redirects;
*/
exports.create = function (maximumRetries) {
  return function handle (resource, next, callback) {
    var currentRetries = 0;

    function handleRedirect(err, response, body) {
      if (response && response.headers &&
          response.headers.location &&
          response.statusCode >= 300 &&
          response.statusCode < 400 &&
          (!maximumRetries ||
          currentRetries < maximumRetries)) {
        currentRetries++;

        resource.url = response.headers.location;
        next(resource, handleRedirect);
      } else if (callback) {
        callback(err, response, body);
      }
    }

    return next(resource, handleRedirect);
  };
};

Check if callback before invoking it


function StorageManager(storageMethod) {
    this.storageMethod = storageMethod;
}

StorageManager.prototype.setCurrentLevel = function(level) {
    this.storageMethod.setItem('currentLevel', level);
};

StorageManager.prototype.incrementCurrentLevel = function() {
   this.setCurrentLevel(this.getCurrentLevel() + 1);
};

StorageManager.prototype.getCurrentLevel = function() {
    return parseInt(this.storageMethod.getItem('currentLevel')) || 1;
};

StorageManager.prototype.setCurrentLevelHistory = function(history) {
    this.history = history;
};

StorageManager.prototype.updateCurrentLevelHistory = function() {
    if(typeof this.history === 'undefined' ) {
        throw "Cannot update history without history object";
    }
    this.storageMethod.setItem('currentLevelHistory', JSON.stringify(this.history));
};

StorageManager.prototype.getCurrentLevelHistory = function(history) {
    var history = this.storageMethod.getItem('currentLevelHistory');
    return history ? JSON.parse(history) : [];
};

StorageManager.prototype.getLevelResults = function() {
    var results = this.storageMethod.getItem('levelResults');
    return results ? JSON.parse(results) : [];
};

StorageManager.prototype.setLevelResult = function(level, result) {
    var results = this.getLevelResults();
    results[level - 1] = result;
    this.storageMethod.setItem('levelResults', JSON.stringify(results));
};

StorageManager.prototype.getLevelResult = function(level) {
    return this.getLevelResults()[level - 1];
};

function StorageManager(storageMethod, prefix) {
    try {
        storageMethod.setItem('__available__', true);
        if(storageMethod.removeItem) {
            storageMethod.removeItem('__available__');
        }
    } catch(e) {
        throw "Storage method is not currently available.";
    }
    this.storageMethod = storageMethod;
    this.prefix = prefix || '';
}

StorageManager.prototype.setCurrentLevel = function(level) {
    this.storageMethod.setItem(this.prefix + 'level_current', level);
};

StorageManager.prototype.incrementCurrentLevel = function() {
   this.setCurrentLevel(this.getCurrentLevel() + 1);
};

StorageManager.prototype.getCurrentLevel = function() {
    return parseInt(this.storageMethod.getItem(this.prefix + 'level_current')) || 1;
};

StorageManager.prototype.getLevelResults = function() {
    var results = this.storageMethod.getItem(this.prefix + 'level_results');
    return results ? JSON.parse(results) : [];
};

StorageManager.prototype.setLevelResult = function(level, result) {
    var results = this.getLevelResults();
    results[level - 1] = result;
    this.storageMethod.setItem(this.prefix + 'level_results', JSON.stringify(results));
};

StorageManager.prototype.getLevelResult = function(level) {
    return this.getLevelResults()[level - 1];
};

Improve storage manager with method validation and key prefixing


var _ = require('lodash');
var crc = require('crc');

// Base structure for a configuration
module.exports = function(options) {
    options = _.defaults(options, {
        // Port for running the webserver
        'port': 3000,

        // Root folder
        'root': process.cwd(),

        // Workspace id
        'id': null,

        // Secret identifier for the workspace
        'secret': null,

        // Events reporting
        'reporting': {
            'timeout': 180 * 1e3
        },

        // Hooks
        'hooks': {
            'users.auth': function(data) {
                if (!data.email || !data.token) throw "Need 'token' and 'email' for auth hook";

                var userId = data.email;
                var token = data.token;

                if (_.size(options.auth.users) > 0) {
                    if (!options.auth.users[userId] || token != options.auth.users[userId]) throw "Invalid user";
                }

                return {
                    'id': userId,
                    'name': userId,
                    'token': data.token,
                    'email': data.email
                };
            },
        }
    });

    // Unique id for workspace
    options.id = options.id ||  crc.hex32(crc.crc32(options.root))

    return options;
};

var _ = require('lodash');
var crc = require('crc');

// Base structure for a configuration
module.exports = function(options) {
    options = _.defaults(options, {
        // Port for running the webserver
        'port': 3000,

        // Root folder
        'root': process.cwd(),

        // Workspace id
        'id': null,

        // Secret identifier for the workspace
        'secret': null,

        // Events reporting
        'reporting': {
            'timeout': 180 * 1e3
        },

        // Authentication settings
        'auth': {},

        // Hooks
        'hooks': {
            'users.auth': function(data) {
                if (!data.email || !data.token) throw "Need 'token' and 'email' for auth hook";

                var userId = data.email;
                var token = data.token;

                if (_.size(options.auth.users) > 0) {
                    if (!options.auth.users[userId] || token != options.auth.users[userId]) throw "Invalid user";
                }

                return {
                    'id': userId,
                    'name': userId,
                    'token': data.token,
                    'email': data.email
                };
            },
        }
    });

    // Unique id for workspace
    options.id = options.id ||  crc.hex32(crc.crc32(options.root))

    return options;
};

Fix error when loading without auth config


import history from '!json!../assets/data/history.json'
import metadata from '!json!../assets/data/metadata.json'
import latestSeasonData from '!json!../assets/data/season-latest.json'

const req = require.context(
  'file-loader!../assets/data/',
  false,
  /^\.\/.*\.json$/
)

const seasonDataUrls = req.keys().reduce((acc, key) => {
  if (key.startsWith('./season-2')) {
    acc[key.slice(9, -5)] = req(key)
  }
  return acc
}, {})

export { seasonDataUrls, latestSeasonData, history, metadata }

import history from '!json!../assets/data/history.json'
import metadata from '!json!../assets/data/metadata.json'
// Loading latest season in the main bundle itself
import latestSeasonData from '!json!../assets/data/season-latest.json'

const seasonDataCtx = require.context(
  'file-loader!../assets/data/',
  false,
  /^\.\/.*\.json$/
)

const distDataCtx = require.context(
  'file-loader!../assets/data/distributions/',
  false,
  /^\.\/.*\.json$/
)

const seasonDataUrls = seasonDataCtx.keys().reduce((acc, key) => {
  if (key.startsWith('./season-')) {
    // Identifier is like '2013-2014'
    acc[key.slice(9, -5)] = req(key)
  }
  return acc
}, {})

const distDataUrls = distDataCtx.keys().reduce((acc, key) => {
  if (key.startsWith('./season-')) {
    // Identifier is like '2013-2014-hhs10'
    acc[key.slice(9, -5)] = req(key)
  }
  return acc
}, {})

export { seasonDataUrls, distDataUrls, latestSeasonData, history, metadata }

Load distributions directory using file-loader


angular.module('mwUI.UiComponents')

//TODO rename to mwCollapsible
  .directive('mwCollapsable', function () {
    return {
      transclude: true,
      scope: {
        mwCollapsable: '=',
        title: '@mwTitle'
      },
      templateUrl: 'uikit/mw-ui-components/directives/templates/mw_collapsible.html',
      link: function (scope, el) {
        scope.viewModel = {};
        scope.viewModel.collapsed = false;

        var getHeight = function (el) {
          var totalHeight = 0;

          el.children().filter(':visible').each(function () {
            totalHeight += angular.element(this).outerHeight(true);
          });
          return totalHeight;
        };

        scope.toggle = function () {
          var collapsedBody = el.find('.mw-collapsible-body'),
            maxHeight;

          if (!scope.viewModel.collapsed) {
            maxHeight = getHeight(collapsedBody);
          } else {
            maxHeight = 0;
          }

          collapsedBody.css('max-height', maxHeight);
          scope.viewModel.collapsed = !scope.viewModel.collapsed;
        };

        scope.$watch('mwCollapsable', function () {
          if (scope.mwCollapsable === false) {
            scope.viewModel.collapsed = true;
          } else {
            scope.viewModel.collapsed = false;
          }
        });
      }
    };
  });

angular.module('mwUI.UiComponents')

//TODO rename to mwCollapsible
  .directive('mwCollapsable', function () {
    return {
      transclude: true,
      scope: {
        mwCollapsable: '=',
        title: '@mwTitle'
      },
      templateUrl: 'uikit/mw-ui-components/directives/templates/mw_collapsible.html',
      link: function (scope, el) {
        scope.viewModel = {};
        scope.viewModel.collapsed = false;

        var getHeight = function (el) {
          var totalHeight = 0;

          el.children().filter(':visible').each(function () {
            totalHeight += angular.element(this).outerHeight(true);
          });
          return totalHeight;
        };

        var open = function(){
          var collapsedBody = el.find('.mw-collapsible-body');

          collapsedBody.css('max-height', getHeight(collapsedBody));
          scope.viewModel.collapsed = false;
        };

        var close = function(){
          var collapsedBody = el.find('.mw-collapsible-body');

          collapsedBody.css('max-height', 0);
          scope.viewModel.collapsed = true;
        };

        scope.toggle = function () {
          if (scope.mwCollapsable === false) {
            close();
          } else {
            open();
          }
        };

        scope.$watch('mwCollapsable', function () {
          if (scope.mwCollapsable === false) {
            close();
          } else {
            open();
          }
        });
      }
    };
  });

Use open and close function


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

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

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

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

'use strict';

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

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

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

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

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

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

module.exports = env;

Add database connection bit required by AppFog


/* @flow */
'use strict';

import React, {Component} from 'react';
import {View, TouchableOpacity} from 'react-native';
import computeProps from '../Utils/computeProps';
import _ from 'lodash';
import Col from './Col';
import Row from './Row';

export default class GridNB extends Component {
    prepareRootProps() {

        var type = {
            flex: 1,
            flexDirection: this.ifRow() ? 'column' : 'row'
        }

        var defaultProps = {
            style: type
        }

        return computeProps(this.props, defaultProps);

    }

    ifRow() {
        var row = false;
        React.Children.forEach(this.props.children, function (child) {
            if(child.type == Row)
                row = true;
        })
        return row;
    }

    setNativeProps(nativeProps) {
      this._root.setNativeProps(nativeProps);
    }

  render() {
    if(this.props.onPress){
      return(
        <TouchableOpacity onPress={this.props.onPress}>
    <View
      ref={component => this._root = component}
      {...this.props}
      {...this.prepareRootProps()}
    >{this.props.children}</View>
      </TouchableOpacity>
    );
    }
    else{
      return(
        <View
      ref={component => this._root = component}
      {...this.props}
      {...this.prepareRootProps()}
    >{this.props.children}</View>
    );
    }
  }

}

/* @flow */
'use strict';

import React, {Component} from 'react';
import {View, TouchableOpacity} from 'react-native';
import computeProps from '../Utils/computeProps';
import _ from 'lodash';
import Col from './Col';
import Row from './Row';

export default class GridNB extends Component {
    prepareRootProps() {

        var type = {
            flex: 1,
            flexDirection: this.ifRow() ? 'column' : 'row'
        }

        var defaultProps = {
            style: type
        }

        return computeProps(this.props, defaultProps);

    }

    ifRow() {
        var row = false;
        React.Children.forEach(this.props.children, function (child) {
            if(child && child.type == Row)
                row = true;
        })
        return row;
    }

    setNativeProps(nativeProps) {
      this._root.setNativeProps(nativeProps);
    }

  render() {
    if(this.props.onPress){
      return(
        <TouchableOpacity onPress={this.props.onPress}>
    <View
      ref={component => this._root = component}
      {...this.props}
      {...this.prepareRootProps()}
    >{this.props.children}</View>
      </TouchableOpacity>
    );
    }
    else{
      return(
        <View
      ref={component => this._root = component}
      {...this.props}
      {...this.prepareRootProps()}
    >{this.props.children}</View>
    );
    }
  }

}

Check for null while checking for rows in grid children


import {JSONReducer as constraints} from './serviceForm/Constraints';
import {JSONReducer as container} from './serviceForm/Container';
import {JSONReducer as env} from './serviceForm/EnvironmentVariables';
import {JSONReducer as fetch} from './serviceForm/Artifacts';
import {JSONReducer as healthChecks} from './serviceForm/HealthChecks';
import {JSONReducer as labels} from './serviceForm/Labels';
import {JSONReducer as portDefinitions} from './serviceForm/PortDefinitions';
import {JSONReducer as volumes} from './serviceForm/Volumes';
import {
  simpleFloatReducer,
  simpleIntReducer,
  simpleReducer
} from '../../../../../src/js/utils/ReducerUtil';

import ValidatorUtil from '../../../../../src/js/utils/ValidatorUtil';

module.exports = {
  id: simpleReducer('id'),
  instances: simpleIntReducer('instances'),
  container() {
    const newState = container.apply(this, arguments);
    if (ValidatorUtil.isEmpty(newState)) {
      return null;
    }
    return newState;
  },
  cpus: simpleFloatReducer('cpus'),
  mem: simpleIntReducer('mem'),
  disk: simpleIntReducer('disk'),
  gpus: simpleIntReducer('gpus'),
  cmd: simpleReducer('cmd'),
  env,
  labels,
  healthChecks,
  constraints,
  fetch,
  portDefinitions,
  volumes
};

import {JSONReducer as constraints} from './serviceForm/Constraints';
import {JSONReducer as container} from './serviceForm/Container';
import {JSONReducer as env} from './serviceForm/EnvironmentVariables';
import {JSONReducer as fetch} from './serviceForm/Artifacts';
import {JSONReducer as healthChecks} from './serviceForm/HealthChecks';
import {JSONReducer as labels} from './serviceForm/Labels';
import {JSONReducer as portDefinitions} from './serviceForm/PortDefinitions';
import {JSONReducer as volumes} from './serviceForm/Volumes';
import {JSONReducer as ipAddress} from './serviceForm/IpAddress';
import {
  simpleFloatReducer,
  simpleIntReducer,
  simpleReducer
} from '../../../../../src/js/utils/ReducerUtil';

import ValidatorUtil from '../../../../../src/js/utils/ValidatorUtil';

module.exports = {
  id: simpleReducer('id'),
  instances: simpleIntReducer('instances'),
  container() {
    const newState = container.apply(this, arguments);
    if (ValidatorUtil.isEmpty(newState)) {
      return null;
    }
    return newState;
  },
  cpus: simpleFloatReducer('cpus'),
  mem: simpleIntReducer('mem'),
  disk: simpleIntReducer('disk'),
  gpus: simpleIntReducer('gpus'),
  cmd: simpleReducer('cmd'),
  env,
  labels,
  healthChecks,
  constraints,
  fetch,
  portDefinitions,
  volumes,
  ipAddress
};

Add ipAddress reducer to jsonReducers


'use strict'; // eslint-disable-line strict, lines-around-directive

const socketIo = require('socket.io');
const gatherOsMetrics = require('./gather-os-metrics');

let io;

module.exports = (server, spans) => {
  if (io === null || io === undefined) {
    io = socketIo(server);

    io.on('connection', (socket) => {
      socket.emit('start', spans);
      socket.on('change', () => {
        socket.emit('start', spans);
      });
    });

    spans.forEach((currentSpan) => {
      const span = currentSpan;
      span.os = [];
      span.responses = [];

      const interval = setInterval(() => gatherOsMetrics(io, span), span.interval * 1000);
      interval.unref(); // don't keep node.js process up
    });
  }
};

Add support for Node.js v4 and v5


const $ = require('jquery');
const stageConfigs = require('./stages.json');
const Game = require('./game');

$(document).ready(() => {
	const game = new Game(stageConfigs);

	let clicked = false;
	$('body').click(() => {
		if (!clicked) {
			setTimeout(() => {
				alert('そろそろ次の人に代わってね');
				clicked = false;
			}, 5 * 60 * 1000);
			clicked = true;
		}
	})

	$('.modal').each((index, element) => {
		const $modal = $(element);
		$modal.find('.close').click(() => {
			$modal.remove();
		});
	});
});

const $ = require('jquery');
const stageConfigs = require('./stages.json');
const Game = require('./game');

$(document).ready(() => {
	const game = new Game(stageConfigs);

	let clicked = false;
	$('body').click(() => {
		if (!clicked) {
			setTimeout(() => {
				alert('そろそろ次の人に代わってね');
				clicked = false;
			}, 5 * 60 * 1000);
			clicked = true;
		}
	})

	$('.modal').each((index, element) => {
		const $modal = $(element);
		$modal.find('.close').click(() => {
			$modal.remove();
		});
	});

	$(window).resize(() => game.currentStage.updateStyles());
});

Update styles when window is resized


import { get, post, put } from '../lib/apiService';

export function getUser(id) {
  return get('nominations', `users/${id}`);
}

export function getMe() {
  return get('nominations', 'users/me/profile');
}

export function getUserList(pageNumber = 1, search, affiliationId) {
  pageNumber = pageNumber < 1 ? 1 : pageNumber;
  return get('nominations', 'users', {
    page: pageNumber,
    search,
    affiliationId
  });
}

export function getPendingUserList(pageNumber = 1, search) {
  return get('nominations', 'users/pending', {
    page: pageNumber,
    search: search
  });
}

export function createUser(user) {
  return post('nominations', 'users', user);
}

export function updateUser({ households, ...user }) {
  return put('nominations', `users/${user.id}`, user);
}

export function approveUser(id) {
  return post('nominations', `users/${id}/approve`);
}

export function declineUser(id) {
  return post('nominations', `users/${id}/decline`);
}

import { get, post, put } from '../lib/apiService';

export function getUser(id) {
  return get('nominations', `users/${id}`);
}

export function getMe() {
  return get('v2', 'auth/account');
}

export function getUserList(pageNumber = 1, search, affiliationId) {
  pageNumber = pageNumber < 1 ? 1 : pageNumber;
  return get('nominations', 'users', {
    page: pageNumber,
    search,
    affiliationId
  });
}

export function getPendingUserList(pageNumber = 1, search) {
  return get('nominations', 'users/pending', {
    page: pageNumber,
    search: search
  });
}

export function createUser(user) {
  return post('nominations', 'users', user);
}

export function updateUser({ households, ...user }) {
  return put('nominations', `users/${user.id}`, user);
}

export function approveUser(id) {
  return post('nominations', `users/${id}/approve`);
}

export function declineUser(id) {
  return post('nominations', `users/${id}/decline`);
}

Change profile call to auth/account


var User = zooniverse.models.User;

var ProjectBasedCollection = Backbone.Collection.extend({
  initialize: function() {
    User.on('change', _.bind(this.fetch, this));
    this.listenTo(require('lib/state'), 'change:project', this.fetch);
  },

  sync: require('lib/sync'),

  comparator: function(m) {
    return -(new Date(m.get('updated_at')).getTime());
  },

  fetch: function() {
    if (!(User.current && require('lib/state').get('project')))
      return;
    return ProjectBasedCollection.__super__.fetch.call(this);
  }
});

module.exports = ProjectBasedCollection;

var User = zooniverse.models.User;

var ProjectBasedCollection = Backbone.Collection.extend({
  initialize: function() {
    User.on('change', _.bind(this.fetch, this));
    this.listenTo(require('lib/state'), 'change:project', this.fetch);
  },

  sync: require('lib/sync'),

  comparator: function(m) {
    return -(new Date(m.get('updated_at')).getTime());
  },

  fetch: function() {
    this.reset();
    if (!(User.current && require('lib/state').get('project')))
      return;
    return ProjectBasedCollection.__super__.fetch.call(this);
  }
});

module.exports = ProjectBasedCollection;

Reset collections when switching projects


import React, { Component, PropTypes } from 'react';
import { Link } from 'react-router';

class MediaMetadataSummary extends Component {

  render() {
    const { media, data } = this.props;
    const annotationsCount = media.annotations_count; // TODO: filter to count of annotations displayed on timeline

    return (

        {annotationsCount} note{annotationsCount === 1 ? '' : 's'}
        {media.domain}
        {data.username ? '@' + data.username : null}

    );
  }
}

export default MediaMetadataSummary;

import React, { Component, PropTypes } from 'react';
import { Link } from 'react-router';
import util from './MediaUtil';

class MediaMetadataSummary extends Component {

  render() {
    const { media, data } = this.props;
    const annotationsCount = media.annotations_count; // TODO: filter to count of annotations displayed on timeline

    return (

        {annotationsCount} note{annotationsCount === 1 ? '' : 's'}
        {media.domain}
        {util.authorUsername(media, data)}

    );
  }
}

export default MediaMetadataSummary;

Standardize author username in media metadata


var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-line-height/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-line-height/tachyons-line-height.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_line-height.css', 'utf8')

var template = fs.readFileSync('./templates/docs/line-height/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS
})

fs.writeFileSync('./docs/typography/line-height/index.html', html)

var _ = require('lodash')
var fs = require('fs')
var gzip = require('gzip-size')
var filesize = require('filesize')
var cssstats = require('cssstats')

var module = require('tachyons-line-height/package.json')
var moduleCss = fs.readFileSync('node_modules/tachyons-line-height/tachyons-line-height.min.css', 'utf8')
var moduleObj = cssstats(moduleCss)
var moduleSize = filesize(moduleObj.gzipSize)

var srcCSS = fs.readFileSync('./src/_line-height.css', 'utf8')
var navDocs = fs.readFileSync('./templates/nav_docs.html', 'utf8')

var template = fs.readFileSync('./templates/docs/line-height/index.html', 'utf8')
var tpl = _.template(template)
var html = tpl({
  moduleVersion: module.version,
  moduleSize: moduleSize,
  moduleObj: moduleObj,
  srcCSS: srcCSS,
  navDocs: navDocs
})

fs.writeFileSync('./docs/typography/line-height/index.html', html)

Update with reference to global nav partial


"use strict"

// Module dependencies
var util = require("util");
var crypto = require("crypto");
var winston = require("winston");
var openVeoAPI = require("openveo-api");
var applicationStorage = openVeoAPI.applicationStorage;

// Retrieve logger
var logger = winston.loggers.get("openveo");

/**
 * Gets the list of scopes and return it as a JSON object.
 * Returns a JSON object as :
 * {
 *  "videos" : {
 *    "name" : "Name of the scope",
 *    "description" : "Scope description"
 *  }
 * }
 */
module.exports.getScopesAction = function(request, response, next){
  var scopes = applicationStorage.getWebServiceScopes();
  var lightScopes = {};

  for(var scopeId in scopes){
    lightScopes[scopeId] = {
      name : scopes[scopeId].name,
      description : scopes[scopeId].description
    };
  }
  response.send({ scopes : lightScopes });
};

"use strict"

// Module dependencies
var util = require("util");
var crypto = require("crypto");
var winston = require("winston");
var openVeoAPI = require("openveo-api");
var applicationStorage = openVeoAPI.applicationStorage;

/**
 * Gets the list of scopes and return it as a JSON object.
 * Returns a JSON object as :
 * {
 *  "videos" : {
 *    "name" : "Name of the scope",
 *    "description" : "Scope description"
 *  }
 * }
 */
module.exports.getScopesAction = function(request, response, next){
  var scopes = applicationStorage.getWebServiceScopes();
  var lightScopes = {};

  for(var scopeId in scopes){
    lightScopes[scopeId] = {
      name : scopes[scopeId].name,
      description : scopes[scopeId].description
    };
  }
  response.send({ scopes : lightScopes });
};

Remove unused logger dependency on application controller


var STATES = {
  ready: 'ready',
  loading: 'loading',
  fetched: 'fetched',
  error: 'error'
};

module.exports = {
  track: function (view, callback) {
    if (view.modelView === undefined) throw new Error('modelView is required');
    if (view._querySchemaModel === undefined) throw new Error('querySchemaModel is required');

    this.modelView = view.modelView;
    this.querySchemaModel = view._querySchemaModel;

    this.querySchemaModel.on('change:query_errors', this._checkErrors, this);
    view.add_related_model(this.querySchemaModel);

    this.modelView.on('change:state', callback);
    view.add_related_model(this.modelView);

    if (this.querySchemaModel.canFetch() && !this._hasErrors()) {
      this.querySchemaModel.fetch();
    }

    this._checkErrors();
  },

  _checkErrors: function () {
    if (this._hasErrors()) {
      this.modelView.set({state: STATES.error});
    } else {
      if (this.querySchemaModel.isFetched()) {
        this.modelView.set({state: STATES.ready});
      } else {
        this.modelView.set({state: STATES.loading});
      }
    }
  },

  _hasErrors: function () {
    var errors = this.querySchemaModel.get('query_errors');
    return (errors && errors.length > 0);
  }
};

var STATES = {
  ready: 'ready',
  loading: 'loading',
  fetched: 'fetched',
  error: 'error'
};

module.exports = {
  track: function (view, callback) {
    if (view.modelView === undefined) throw new Error('modelView is required');
    if (view._querySchemaModel === undefined) throw new Error('querySchemaModel is required');

    this.modelView = view.modelView;
    this.querySchemaModel = view._querySchemaModel;

    this.querySchemaModel.on('change:query_errors change:status', this._setState, this);
    view.add_related_model(this.querySchemaModel);

    this.modelView.on('change:state', callback);
    view.add_related_model(this.modelView);

    if (this.querySchemaModel.canFetch() && !this._hasErrors()) {
      this.querySchemaModel.fetch();
    }

    this._setState();
  },

  _setState: function () {
    if (this._hasErrors()) {
      this.modelView.set({state: STATES.error});
    } else {
      if (this.querySchemaModel.isFetched()) {
        this.modelView.set({state: STATES.ready});
      } else {
        this.modelView.set({state: STATES.loading});
      }
    }
  },

  _hasErrors: function () {
    var errors = this.querySchemaModel.get('query_errors');
    return (errors && errors.length > 0);
  }
};

Check query schema model status cahnges in oder to set state correctly


// Copyright (c) Martin Costello, 2016. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

"use strict";

console.log("Started Service Worker.", self);

self.addEventListener("install", function (event) {
    event.waitUntil(
        caches.open("martincostello.com").then(function (cache) {
            return cache.addAll([
                "/",
                "/assets/css/site.css",
                "/assets/css/site.min.css",
                "/assets/js/site.js",
                "/assets/js/site.min.js",
                "/assets/img/browserstack.svg"
            ]);
        }).then(function () {
            return self.skipWaiting();
        })
    );
    console.log("Installed Service Worker.");
});

self.addEventListener("activate", function (event) {
    console.log("Activated Service Worker.");
});

/*
self.addEventListener("fetch", function (event) {
    if (event.request.method !== "GET") {
        return;
    }
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                return response || fetch(event.request);
            })
    );
});
*/

// Copyright (c) Martin Costello, 2016. All rights reserved.
// Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information.

"use strict";

console.log("Started Service Worker.", self);

self.addEventListener("install", function (event) {
    event.waitUntil(
        caches.open("martincostello.com").then(function (cache) {
            return cache.addAll([
                "/",
                "/assets/css/site.css",
                "/assets/css/site.min.css",
                "/assets/js/site.js",
                "/assets/js/site.min.js"
            ]);
        }).then(function () {
            return self.skipWaiting();
        })
    );
    console.log("Installed Service Worker.");
});

self.addEventListener("activate", function (event) {
    console.log("Activated Service Worker.");
});

/*
self.addEventListener("fetch", function (event) {
    if (event.request.method !== "GET") {
        return;
    }
    event.respondWith(
        caches.match(event.request)
            .then(function (response) {
                return response || fetch(event.request);
            })
    );
});
*/

Fix 404 error in service worker


import Notify from './notification';
import React, { PropTypes } from 'react';
import { connect } from 'react-redux';

function App(props) {
  const isLoading = props.loading.isLoading;
  return (

      {props.children}

        {Object.keys(props.loading.wip).map((loadingKey, ndx) => {
          return (
{loadingKey}
);
        })}

      <Notify />

  );
}

App.displayName = 'App';

App.propTypes = {
  children: PropTypes.node,
  loading: PropTypes.object,
};

function select(state) {
  return {
    loading: state.loading,
  };
}

export default connect(select)(App);

import Notify from './notification';
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';

class App extends Component { // eslint-disable-line react/prefer-stateless-function
  render() {
    const { children, loading: { isLoading, wip } } = this.props;

    return (

        {children}

          {Object.keys(wip).map((loadingKey, ndx) => {
            return (
{loadingKey}
);
          })}

        <Notify />

    );
  }
}

App.displayName = 'App';

App.propTypes = {
  children: PropTypes.node,
  loading: PropTypes.object,
};

function select(state) {
  return {
    loading: state.loading,
  };
}

export default connect(select)(App);

Change root component to actual React component.


/**
 * @provide pskl.tools.drawing.DitheringTool
 *
 * @require pskl.utils
 */
(function() {
  var ns = $.namespace('pskl.tools.drawing');

  ns.DitheringTool = function() {
    ns.SimplePen.call(this);
    this.toolId = 'tool-dithering';
    this.helpText = 'Dithering tool';
  };
  pskl.utils.inherit(ns.DitheringTool, ns.SimplePen);

  /**
   * @override
   */
  ns.DitheringTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
    // Use primary selected color on cell with either an odd col or row.
    // Use secondary color otherwise.
    // When using the right mouse button, invert the above behavior to allow quick corrections.
    var usePrimaryColor = (col + row) % 2;
    var invertColors = event.button === Constants.RIGHT_BUTTON;
    usePrimaryColor = invertColors ? !usePrimaryColor : usePrimaryColor;

    var selectedColors = pskl.app.selectedColorsService.getColors();
    var ditheringColor = usePrimaryColor ? selectedColors[0] : selectedColors[1];
    this.superclass.applyToolAt.call(this, col, row, ditheringColor, frame, overlay, event);
  };
})();

/**
 * @provide pskl.tools.drawing.DitheringTool
 *
 * @require pskl.utils
 */
(function() {
  var ns = $.namespace('pskl.tools.drawing');

  ns.DitheringTool = function() {
    ns.SimplePen.call(this);
    this.toolId = 'tool-dithering';
    this.helpText = 'Dithering tool';
  };
  pskl.utils.inherit(ns.DitheringTool, ns.SimplePen);

  /**
   * @override
   */
  ns.DitheringTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
    // On Firefox/IE, the clicked button type is not part of the mousemove event.
    // Ensure we record the pressed button on the initial mousedown only.
    if (event.type == 'mousedown') {
      this.invertColors_ = event.button === Constants.RIGHT_BUTTON;
    }

    // Use primary selected color on cell with either an odd col or row.
    // Use secondary color otherwise.
    // When using the right mouse button, invert the above behavior to allow quick corrections.
    var usePrimaryColor = (col + row) % 2;
    usePrimaryColor = this.invertColors_ ? !usePrimaryColor : usePrimaryColor;

    var selectedColors = pskl.app.selectedColorsService.getColors();
    var ditheringColor = usePrimaryColor ? selectedColors[0] : selectedColors[1];
    this.superclass.applyToolAt.call(this, col, row, ditheringColor, frame, overlay, event);
  };
})();

Fix dithering right-click color inversion on FF/IE


/**
 * @providesModule react-native-device-info
 */

var KDSocialShare = require('react-native').NativeModules.KDSocialShare;

module.exports = {
  shareOnTwitter: function(params, callback) {
    return KDSocialShare.tweet(params, callback);
  },
  shareOnFacebook: function(params, callback) {
    return KDSocialShare.shareOnFacebook(params, callback);
  }
};

/**
 * @providesModule react-native-social-share
 */

var KDSocialShare = require('react-native').NativeModules.KDSocialShare;

module.exports = {
  shareOnTwitter: function(params, callback) {
    return KDSocialShare.tweet(params, callback);
  },
  shareOnFacebook: function(params, callback) {
    return KDSocialShare.shareOnFacebook(params, callback);
  }
};

Update module name in header comment


angular
  .module('app')
  .factory('MetaMachine', function($rootScope) {

    var metaDefaults = {
      metaTitle: "Home | Rootstrikers",
      metaDescription: "We fight the corrupting influence of money in politics",
      metaImage: "http://facultycreative.com/img/icons/facultyicon114.png",
      metaUrl: "http://rs002dev.herokuapp.com/"
    };

    (function setDefaults() {
      _.each(metaDefaults, function(val, key) { $rootScope[key] = val; });
    })();

    var MetaMachine = {
      title: function(pageTitle, baseTitle) {
        baseTitle = typeof baseTitle != 'undefined' ? baseTitle : "Rootstrikers";
        $rootScope.metaTitle = typeof pageTitle != 'undefined' ? pageTitle + " | " + baseTitle : baseTitle;
      },
      description: function(description) {
        $rootScope.metaDescription = description || "We fight the corrupting influence of money in politics";
      },
      image: function(url) {
        $rootScope.metaImage = url || "http://facultycreative.com/img/icons/facultyicon114.png";
      },
      url: function(url) {
        $rootScope.metaUrl = url || "http://rs002dev.herokuapp.com/";
      }
    };
    return MetaMachine;
  });

angular
  .module('app')
  .factory('MetaMachine', function($rootScope) {

    var metaDefaults = {
      metaTitle: "Home | Rootstrikers",
      metaDescription: "We fight the corrupting influence of money in politics",
      metaImage: "/app/images/favicon/apple-touch-icon-144x144-precomposed.png",
      metaUrl: "http://rs002dev.herokuapp.com/"
    };

    (function setDefaults() {
      _.each(metaDefaults, function(val, key) { $rootScope[key] = val; });
    })();

    var MetaMachine = {
      title: function(pageTitle, baseTitle) {
        baseTitle = typeof baseTitle != 'undefined' ? baseTitle : "Rootstrikers";
        $rootScope.metaTitle = typeof pageTitle != 'undefined' ? pageTitle + " | " + baseTitle : baseTitle;
      },
      description: function(description) {
        $rootScope.metaDescription = description || "We fight the corrupting influence of money in politics";
      },
      image: function(url) {
        $rootScope.metaImage = url || "/app/images/favicon/apple-touch-icon-144x144-precomposed.png";
      },
      url: function(url) {
        $rootScope.metaUrl = url || "http://rs002dev.herokuapp.com/";
      }
    };
    return MetaMachine;
  });

Update metadata defaults to Rootstrikers-specific info