/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  ENV.contentSecurityPolicy = {
    'default-src': "'none'",
    'script-src': "'self'",
    'font-src': "'self' fonts.gstatic.com",
    'connect-src': "'self'",
    'img-src': "'self'",
    'media-src': "'self'"
  }

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

/* jshint node: true */

module.exports = function(environment) {
  var ENV = {
    modulePrefix: 'dummy',
    environment: environment,
    baseURL: '/',
    locationType: 'auto',
    EmberENV: {
      FEATURES: {
        // Here you can enable experimental features on an ember canary build
        // e.g. 'with-controller': true
      }
    },

    APP: {
      // Here you can pass flags/options to your application instance
      // when it is created
    }
  };

  if (environment === 'development') {
    // ENV.APP.LOG_RESOLVER = true;
    // ENV.APP.LOG_ACTIVE_GENERATION = true;
    // ENV.APP.LOG_TRANSITIONS = true;
    // ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
    // ENV.APP.LOG_VIEW_LOOKUPS = true;
  }

  if (environment === 'test') {
    // Testem prefers this...
    ENV.baseURL = '/';
    ENV.locationType = 'none';

    // keep test console output quieter
    ENV.APP.LOG_ACTIVE_GENERATION = false;
    ENV.APP.LOG_VIEW_LOOKUPS = false;

    ENV.APP.rootElement = '#ember-testing';
  }

  if (environment === 'production') {

  }

  return ENV;
};

Fix for security policy messages

Fix for security policy messages


'use strict';

angular.module('<%= scriptAppName %>')
  .filter('<%= cameledName %>', function () {
    return function (input) {
      return '<%= cameledName %> filter: ' + input;
    };
  });

'use strict';
(function(){
  var <%= cameledName %> = function(){

    return function (input) {
      return '<%= cameledName %> filter: ' + input;
    };

  };
  angular
    .module('<%= scriptAppName %>')
    .filter('<%= cameledName %>', <%= cameledName %>);

}).call(this);

Update: Refactor Javascript Filter to match best practices


#! /usr/bin/env node

require('../dist')
  .run(process.argv.slice(2))
  .catch(() => {
    process.exit(1);
  });

#! /usr/bin/env node

require('../dist') // eslint-disable-line import/no-unresolved
  .run(process.argv.slice(2))
  .catch(() => {
    process.exit(1);
  });

Add eslint for js files (fix eslint error)


import React, { Component, PropTypes } from "react"
import { baseUrl } from "../../../config"
import joinUri from "join-uri"

export default class Avatar extends Component {
  static propTypes = {
    template: PropTypes.string.isRequired,
    size: PropTypes.number,
  };

  static defaultProps = {
    size: 120,
  }

  render() {
    const { template, size, ...props } = this.props
    const url = baseUrl + joinUri("/", template.replace("{size}", size))
    return (
      <img src={ url } { ...props } />
    )
  }
}

import React, { Component, PropTypes } from "react"
import { baseUrlHttp as baseUrl } from "../../../config"
import joinUri from "join-uri"

export default class Avatar extends Component {
  static propTypes = {
    template: PropTypes.string.isRequired,
    size: PropTypes.number,
  };

  static defaultProps = {
    size: 120,
  }

  render() {
    const { template, size, ...props } = this.props
    const url = baseUrl + joinUri("/", template.replace("{size}", size))
    return (
      <img src={ url } { ...props } />
    )
  }
}

Use http protocol for Avatar

Use http protocol for Avatar


/**
 * Streams with pub/sub principle
 *
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 10.05.18
 */
Imcms.define('imcms-streams', [], function () {

    return {};
});

/**
 * Streams with pub/sub principle
 *
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 10.05.18
 */
Imcms.define('imcms-streams', ['imcms-displacing-array'], function (DisplacingArray) {

    var Subscriber = function (topic) {
        (this.topic = topic).addSubscriber(this);
    };

    Subscriber.prototype = {
        onPublish: function (doOnPublish) {
            this.doOnPublish = doOnPublish;
            return this;
        },
        runFromStart: function () {
            this.topic.forEachPublication(this.reactOnPublication.bind(this))
        },
        getReactionOnPublication: function (content) {
            return function () {
                this.doOnPublish(content);
            }.bind(this);
        },
        reactOnPublication: function (content) {
            setTimeout(this.getReactionOnPublication(content));
        }
    };

    var Topic = function (name) {
        this.name = name;
        this.publications = new DisplacingArray(1024);
        this.subscribers = new DisplacingArray(1024);
    };

    Topic.prototype = {
        forEachPublication: function (doOnPublication) {
            this.publications.forEach(doOnPublication);
        },
        addSubscriber: function (subscriber) {
            this.subscribers.push(subscriber);
        },
        getAllSubscribers: function () {
            return this.subscribers;
        },
        savePublication: function (content) {
            this.publications.push(content);
        },
        publish: function (content) {
            this.savePublication(content);

            this.getAllSubscribers().forEach(function (subscriber) {
                subscriber.reactOnPublication(content);
            });
        }
    };

    var namePerTopic = {};

    function getOrCreateTopic(topicName) {
        return namePerTopic[topicName] || (namePerTopic[topicName] = new Topic(topicName));
    }

    var Publisher = function (topic) {
        this.topic = topic;
    };

    Publisher.prototype = {
        publish: function (content) {
            this.topic.publish(content);
        }
    };

    return {
        createSubscriberOnTopic: function (topicName) {
            return new Subscriber(getOrCreateTopic(topicName));
        },
        subscribeFromStart: function (topicName, doOnPublish) {
            this.createSubscriberOnTopic(topicName)
                .onPublish(doOnPublish)
                .runFromStart();
        },
        createPublisherOnTopic: function (topicName) {
            return new Publisher(getOrCreateTopic(topicName));
        }
    }
});

IMCMS-290: Add a "pin" icon to imCMS's panel:
- Implemented streams module.


beforeEach(function() {
	this.array = [0, 2, 4, 6, 8, 10, 12, 14];
});

it("Should accept a function with three parameters: the value of the element, the index of the element and the object being traversed", function() {
	var array = this.array;

	array.some(function(value, index, object) {
		expect(object).to.be(array);
		expect(object[index]).to.be(value);
		return false;
	});
});

it("Should accept an optional 'this' argument as its second argument which becomes the 'this' value for the function argument", function() {
	var mockThis = { foo: "bar" };
	var array = this.array;

	array.some(function(value) {
		expect(this).to.be(mockThis);
		expect(this.foo).to.be(mockThis.foo);
	}, mockThis);
});

beforeEach(function() {
	this.array = [0, 2, 4, 6, 8, 10, 12, 14];
});

it("Should accept a function with three parameters: the value of the element, the index of the element and the object being traversed", function() {
	var array = this.array;

	array.some(function(value, index, object) {
		expect(object).to.be(array);
		expect(object[index]).to.be(value);
		return false;
	});
});

it("Should accept an optional 'this' argument as its second argument which becomes the 'this' value for the function argument", function() {
	var mockThis = { foo: "bar" };
	var array = this.array;

	array.some(function(value) {
		expect(this).to.be(mockThis);
		expect(this.foo).to.be(mockThis.foo);
		return false;
	}, mockThis);
});

it("Should pass a reference to the array as the third parameter to the function argument", function() {
	var array = [10];

	array.some(function(value, index, object) {
		object[0] = 100;
		return false;
	});

	expect(array[0]).to.be(100);
});

Test that the third parameter to the function is a reference to the array


const { execSync } = require("child_process");
const LoadingStrategy = require("./LoadingStrategy");
const VersionRange = require("./VersionRange");

class Native extends LoadingStrategy {
  load() {
    const versionString = this.validateAndGetSolcVersion();
    const command = "solc --standard-json";

    try {
      return {
        compile: options => String(execSync(command, { input: options })),
        version: () => versionString
      };
    } catch (error) {
      if (error.message === "No matching version found") {
        throw this.errors("noVersion", versionString);
      }
      throw new Error(error);
    }
  }

  validateAndGetSolcVersion() {
    let version;
    try {
      version = execSync("solc --version");
    } catch (error) {
      throw this.errors("noNative", null, error);
    }
    return new VersionRange(this.config).normalizeSolcVersion(version);
  }
}

module.exports = Native;

const { execSync } = require("child_process");
const LoadingStrategy = require("./LoadingStrategy");
const VersionRange = require("./VersionRange");

class Native extends LoadingStrategy {
  load() {
    const versionString = this.validateAndGetSolcVersion();
    const command = "solc --standard-json";
    const maxBuffer = 1024 * 1024 * 10;

    try {
      return {
        compile: options =>
          String(execSync(command, { input: options, maxBuffer })),
        version: () => versionString
      };
    } catch (error) {
      if (error.message === "No matching version found") {
        throw this.errors("noVersion", versionString);
      }
      throw new Error(error);
    }
  }

  validateAndGetSolcVersion() {
    let version;
    try {
      version = execSync("solc --version");
    } catch (error) {
      throw this.errors("noNative", null, error);
    }
    return new VersionRange(this.config).normalizeSolcVersion(version);
  }
}

module.exports = Native;

Increase maxBuffer to 10MB when compiling using native compiler


import { combineReducers, createStore } from 'redux'
import auth from '../modules/Auth/reducer'
import households from '../modules/Households/reducer'
import members from '../modules/Members/reducer'
import meals from '../modules/Meals/reducer'
import error from '../modules/Errors/reducer'
import { reducer as form } from 'redux-form'
import middleware from '../../middleware'
import { loadingBarReducer } from 'react-redux-loading-bar'

const rootReducer = combineReducers({
  auth,
  form,
  households,
  meals,
  members,
  error,
  loadingBar: loadingBarReducer,
})

export default createStore(
  rootReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  middleware
)

import { combineReducers, createStore } from 'redux'
import auth from '../modules/Auth/reducer'
import households from '../modules/Households/reducer'
import members from '../modules/Members/reducer'
import meals from '../modules/Meals/reducer'
import error from '../modules/Errors/reducer'
import { reducer as form } from 'redux-form'
import middleware from '../../middleware'
import { loadingBarReducer: loadingBar } from 'react-redux-loading-bar'

const rootReducer = combineReducers({
  auth,
  form,
  households,
  meals,
  members,
  error,
  loadingBar,
})

export default createStore(
  rootReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
  middleware
)

Update reducer naming in combine reducers


'use strict';

var Subscript = require('./Subscript');
var SubscriptHTMLConverter = require('./SubscriptHTMLConverter');
var SubscriptXMLConverter = require('./SubscriptXMLConverter');
var AnnotationCommand = require('../../ui/AnnotationCommand');
var AnnotationComponent = require('../../ui/AnnotationComponent');
var AnnotationTool = require('../../ui/AnnotationTool');

module.exports = {
  name: 'subscript',
  configure: function(config) {
    config.addNode(Subscript);
    config.addConverter('html', SubscriptHTMLConverter);
    config.addConverter('xml', SubscriptXMLConverter);
    config.addComponent('subscript', AnnotationComponent);
    config.addCommand('Subscript', AnnotationCommand, { nodeType: 'subscript' });
    config.addTool('subscript', AnnotationTool);
    config.addIcon('subscript', { 'fontawesome': 'fa-subscript' });
    config.addStyle(__dirname, '_subscript.scss');
    config.addLabel('subscript', {
      en: 'Subscript',
      de: 'Tiefgestellt'
    });
  }
};

'use strict';

var Subscript = require('./Subscript');
var SubscriptHTMLConverter = require('./SubscriptHTMLConverter');
var SubscriptXMLConverter = require('./SubscriptXMLConverter');
var AnnotationCommand = require('../../ui/AnnotationCommand');
var AnnotationComponent = require('../../ui/AnnotationComponent');
var AnnotationTool = require('../../ui/AnnotationTool');

module.exports = {
  name: 'subscript',
  configure: function(config) {
    config.addNode(Subscript);
    config.addConverter('html', SubscriptHTMLConverter);
    config.addConverter('xml', SubscriptXMLConverter);
    config.addComponent('subscript', AnnotationComponent);
    config.addCommand('subscript', AnnotationCommand, { nodeType: 'subscript' });
    config.addTool('subscript', AnnotationTool);
    config.addIcon('subscript', { 'fontawesome': 'fa-subscript' });
    config.addStyle(__dirname, '_subscript.scss');
    config.addLabel('subscript', {
      en: 'Subscript',
      de: 'Tiefgestellt'
    });
  }
};

Fix case of command name

Fix case of command name


/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

importScripts('console.js');
importScripts('message_handler.js');
importScripts('../pdf.js');
importScripts('../fonts.js');
importScripts('../crypto.js');
importScripts('../glyphlist.js');
importScripts('handler.js');

// Listen for messages from the main thread.
var pdfDoc = null;

var handler = new MessageHandler("worker", this);
WorkerHandler.setup(handler);

/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */

'use strict';

importScripts('console.js');
importScripts('message_handler.js');
importScripts('../pdf.js');
importScripts('../fonts.js');
importScripts('../crypto.js');
importScripts('../glyphlist.js');
importScripts('../metrics.js');
importScripts('handler.js');

// Listen for messages from the main thread.
var pdfDoc = null;

var handler = new MessageHandler("worker", this);
WorkerHandler.setup(handler);

Add missing metrics.js for worker

Add missing metrics.js for worker


var coalesce = require('./coalesce')
var assert = require('assert')
var fs = require('fs')
var path = require('path')
var util = require('util')

var main = require('prolific.main')

var shuttle = {
    main: coalesce(function () {
        return require.main.require('prolific.shuttle')
    }, { filename: null }),
    mine: coalesce(function () {
        return require('prolific.shuttle')
    }, { filename: null })
}

assert(shuttle.main.filename == shuttle.mine.filename,
    util.format(fs.readFileSync(path.join(__dirname, 'error.txt'), 'utf8'),
        shuttle.mine.filename, shuttle.main.filename))

exports.sink = coalesce(shuttle.mine.main, main)

var coalesce = require('./coalesce')
var assert = require('assert')
var fs = require('fs')
var path = require('path')
var util = require('util')

var sink = require('prolific.main')

var shuttle = {
    main: coalesce(function () {
        return require.main.require('prolific.shuttle')
    }, { filename: null }),
    mine: coalesce(function () {
        return require('prolific.shuttle')
    }, { filename: null })
}

assert(shuttle.main.filename == shuttle.mine.filename,
    util.format(fs.readFileSync(path.join(__dirname, 'error.txt'), 'utf8'),
        shuttle.mine.filename, shuttle.main.filename))

exports.sink = coalesce(shuttle.mine.sink, sink)

Fix bug, Shuttle exports Main as `sink`.


"use strict";

function Kablammo() {
  // When hit is to complement of nucleotide sequence (whether for query or
  // subject), we will show the HSPs relative to the coordinates of the
  // original (i.e., input or DB) sequence if this value is false, or relative
  // to the coordinates of its complement if this value is true.
  var use_complement_coords = false;

  this._aln_viewer    = new AlignmentViewer();
  this._aln_exporter  = new AlignmentExporter();
  this._grapher       = new Grapher(this._aln_viewer, this._aln_exporter, use_complement_coords);
  this._parser        = new BlastParser(use_complement_coords);
  this._loader        = new BlastResultsLoader(this._parser);
  this._iface         = new Interface(this._grapher, this._loader);
  this._img_exporter  = new ImageExporter('#results-container', '.export-to-svg', '.export-to-png');

  $('.start-tour').click();
}

function main() {
  new Kablammo();
}

main();

"use strict";

function Kablammo() {
  // When hit is to complement of nucleotide sequence (whether for query or
  // subject), we will show the HSPs relative to the coordinates of the
  // original (i.e., input or DB) sequence if this value is false, or relative
  // to the coordinates of its complement if this value is true.
  var use_complement_coords = false;

  this._aln_viewer    = new AlignmentViewer();
  this._aln_exporter  = new AlignmentExporter();
  this._grapher       = new Grapher(this._aln_viewer, this._aln_exporter, use_complement_coords);
  this._parser        = new BlastParser(use_complement_coords);
  this._loader        = new BlastResultsLoader(this._parser);
  this._iface         = new Interface(this._grapher, this._loader);
  this._img_exporter  = new ImageExporter('#results-container', '.export-to-svg', '.export-to-png');
}

function main() {
  new Kablammo();
}

main();

Remove mistakenly added testing line.

Remove mistakenly added testing line.


function halfBandwidth(scale: Function): number {
    if(scale.bandwidth) {
        return scale.bandwidth() / 2;
    }
    return 0;
}

/**
 * applyScaledValue
 *
 * Because primitive dimensions correlate to an onScreen pixel value the need
 * a slightly different calculation when applying the scale. This is abstracted away
 * to save the headache of knowing to recaclulate.
 *
 *
 * @param      {string}    dimensionName
 * @param      {Function}  scale
 * @param      {any}       value
 * @param      {object}    props     A chart elements inherited props
 * @return     {any}
 */
export default function applyScaledValue(dimensionName: sting, scale: Function, value: *, props: Object): * {
    // console.log(dimensionName, typeof scale, value);
    switch (dimensionName) {
        case 'x':
            return scale(value) + halfBandwidth(scale);

        case 'y':
            return props.height - (scale(value) + halfBandwidth(scale));

        default:
            // the default behavior is to apply current column through current scale
            return scale(value);
    }
}

function halfBandwidth(scale: Function): number {
    if(scale.bandwidth) {
        return scale.bandwidth() / 2;
    }
    return 0;
}

/**
 * applyScaledValue
 *
 * Because primitive dimensions correlate to an onScreen pixel value the need
 * a slightly different calculation when applying the scale. This is abstracted away
 * to save the headache of knowing to recaclulate.
 *
 *
 * @param      {string}    dimensionName
 * @param      {Function}  scale
 * @param      {any}       value
 * @param      {object}    props     A chart elements inherited props
 * @return     {any}
 */
export default function applyScaledValue(dimensionName: string, scale: Function, value: *, props: Object): * {
    if(value === null) {
        return value;
    }

    switch (dimensionName) {
        case 'x':
            return scale(value) + halfBandwidth(scale);

        case 'y':
            return props.height - (scale(value) + halfBandwidth(scale));

        default:
            // the default behavior is to apply current column through current scale
            return scale(value);
    }
}

Make sure not to scale null values

Make sure not to scale null values


module.exports = {

    _interceptor: function (req, res) {
        var _this = this;

        this.options.Vue.http.interceptors.push(function (request, next) {
            if (req) { req.call(_this, request); }

            next(function (response) {
                if (res) { res.call(_this, response); }
            });
        });
    },

    _invalidToken: function (res) {
        if (res.status === 401) {
            this.logout();
        }
    },

    _httpData: function (res) {
        return res.data || {};
    },

    _http: function (data) {
        this.options.Vue.http(data).then(data.success, data.error);
    },

    _getHeaders: function (res) {
        var i,
            data = {},
            headers = res.headers.map;

        for (i in headers) {
            data[i] = headers[i][0];
        }

        return data;
    },

    _setHeaders: function (req, headers) {
        var i;

        for (i in headers) {
            req.headers.set(i, headers[i]);
        }
    }
};

module.exports = {

    _init: function () {
        if ( ! this.options.Vue.http) {
            return 'vue-resource.1.x.js : Vue.http must be set.';
        }
    },

    _interceptor: function (req, res) {
        var _this = this;

        this.options.Vue.http.interceptors.push(function (request, next) {
            if (req) { req.call(_this, request); }

            next(function (response) {
                if (res) { res.call(_this, response); }
            });
        });
    },

    _invalidToken: function (res) {
        if (res.status === 401) {
            this.logout();
        }
    },

    _httpData: function (res) {
        return res.data || {};
    },

    _http: function (data) {
        this.options.Vue.http(data).then(data.success, data.error);
    },

    _getHeaders: function (res) {
        var i,
            data = {},
            headers = res.headers.map;

        for (i in headers) {
            data[i] = headers[i][0];
        }

        return data;
    },

    _setHeaders: function (req, headers) {
        var i;

        for (i in headers) {
            req.headers.set(i, headers[i]);
        }
    }
};

Add _init check for Vue.http being set

Add _init check for Vue.http being set


/* global describe, it */

import {exec} from '../../../src/utils/util';
import assert from 'assert';

describe("Oi CLI", () => {

  it("can be invoked", () => {
    const result = exec('node dist/bin/oi.js -v');
    console.log(result);
    assert(result.stdout.trim().match(/\d+\.\d+\.\d+/), "Invalid version output");
  });

});

/* global describe, it */

import {exec} from '../../../src/utils/util';
import assert from 'assert';
require('chai').should();

describe("Oi CLI", () => {

  it("can be invoked", () => {
    const result = exec('node dist/bin/oi.js -v');
    result.stdout.trim().should.match(/^\d+\.\d+\.\d+$/);
  });

});

Use Chai to assert CLI

Use Chai to assert CLI


import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'

import isPlainObject from './isPlainObject'

export function getDefaultMiddleware() {
  return [thunk]
}

export function configureStore(options = {}) {
  const {
    reducer,
    middleware = getDefaultMiddleware(),
    devTools = true,
    preloadedState,
    enhancers = []
  } = options

  let rootReducer

  if (typeof reducer === 'function') {
    rootReducer = reducer
  } else if (isPlainObject(reducer)) {
    rootReducer = combineReducers(reducer)
  } else {
    throw new Error(
      'Reducer argument must be a function or an object of functions that can be passed to combineReducers'
    )
  }

  const middlewareEnhancer = applyMiddleware(...middleware)

  const storeEnhancers = [middlewareEnhancer, ...enhancers]

  let finalCompose = devTools ? composeWithDevTools : compose

  const composedEnhancer = finalCompose(...storeEnhancers)

  const store = createStore(rootReducer, preloadedState, composedEnhancer)

  return store
}

import { createStore, compose, applyMiddleware, combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import thunk from 'redux-thunk'
import immutableStateInvariant from 'redux-immutable-state-invariant'

import isPlainObject from './isPlainObject'

const IS_PRODUCTION = process.env.NODE_ENV === 'production'

export function getDefaultMiddleware(isProduction = IS_PRODUCTION) {
  const middlewareArray = [thunk]

  if (!isProduction) {
    middlewareArray.unshift(immutableStateInvariant())
  }

  return middlewareArray
}

export function configureStore(options = {}) {
  const {
    reducer,
    middleware = getDefaultMiddleware(),
    devTools = true,
    preloadedState,
    enhancers = []
  } = options

  let rootReducer

  if (typeof reducer === 'function') {
    rootReducer = reducer
  } else if (isPlainObject(reducer)) {
    rootReducer = combineReducers(reducer)
  } else {
    throw new Error(
      'Reducer argument must be a function or an object of functions that can be passed to combineReducers'
    )
  }

  const middlewareEnhancer = applyMiddleware(...middleware)

  const storeEnhancers = [middlewareEnhancer, ...enhancers]

  let finalCompose = devTools ? composeWithDevTools : compose

  const composedEnhancer = finalCompose(...storeEnhancers)

  const store = createStore(rootReducer, preloadedState, composedEnhancer)

  return store
}

Add mutation detection in dev by default


var path = require('path');
var fs = require('fs');
var ExtractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: path.join(__dirname, 'src/frontend/app'),
    cache: true,

    output: {
        path: path.join(__dirname, '/public/'),
        filename: 'bundle.[hash].js'
    },

    module: {
        loaders: [
            { test: /\.css$/,   loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
            { test: /\.jsx?$/,  loader: "babel-loader", exclude: /node_modules/ },
            { test: /\.less$/,  loader: "style-loader!css-loader!less-loader" },
            { test: /\.(ttf|eot|otf|svg|woff|woff2)(\?.+)?$/, loader: "url-loader?limit=10000" },
            { test: /\.scss$/,  loader: "style!css!sass?includePaths[]=" + (path.resolve(__dirname, "./node_modules")) }
        ]
    },

    plugins: [
        new ExtractTextPlugin('bundle.[hash].css'),
        function() {
            this.plugin('done', function(stats) {
                fs.writeFile(path.resolve(__dirname, './public/hash'), stats.hash);
            });
        }
    ],

    devtool: 'source-map'
};

var path = require('path');
var fs = require('fs');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require('webpack');

module.exports = {
    entry: path.join(__dirname, 'src/frontend/app'),
    cache: true,

    output: {
        path: path.join(__dirname, '/public/'),
        filename: 'bundle.[hash].js'
    },

    module: {
        loaders: [
            { test: /\.css$/,   loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
            { test: /\.jsx?$/,  loader: "babel-loader", exclude: /node_modules/ },
            { test: /\.less$/,  loader: "style-loader!css-loader!less-loader" },
            { test: /\.(ttf|eot|otf|svg|woff|woff2)(\?.+)?$/, loader: "url-loader?limit=10000" },
            { test: /\.scss$/,  loader: "style!css!sass?includePaths[]=" + (path.resolve(__dirname, "./node_modules")) }
        ]
    },

    plugins: [
        new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /nb$/),
        new ExtractTextPlugin('bundle.[hash].css'),
        function() {
            this.plugin('done', function(stats) {
                fs.writeFile(path.resolve(__dirname, './public/hash'), stats.hash);
            });
        }
    ],

    devtool: 'source-map'
};

Remove unused moment locales from webpack bundle


'use strict';

const amqplib = require('amqplib');
const amqpUri = require('amqp-uri');

/**
 * Nortstar client service.
 */
module.exports = {
  /**
   * Configure RabbitMQ client.
   */
  getClient() {
    if (!this.client) {
      this.client = amqplib.connect(amqpUri(sails.config.amqp.connection));
    }
    return this.client;
  },
  getChannel() {
    return this.getClient().then(conn => conn.createChannel());
  },
  publishUserPasswordResetTransactional(message) {
    const queueName = 'transactionalQueue';
    const exchangeName = 'transactionalExchange';
    const bindingPattern = '*.*.transactional';
    const routingKey = 'user.password_reset.transactional';
    const msgBuffer = new Buffer(message.toString());

    this.bindQueueToExchange(queueName, exchangeName, bindingPattern)
      .then((channel) => {
        channel.publish(exchangeName, routingKey, msgBuffer)
        .then(result => result);
      });
  },
  bindQueueToExchange(queueName, exchangeName, routingKey) {
    return new Promise((resolve, reject) => {
      this.getChannel()
        .then((channel) => {
          channel.assertExchange(exchangeName, 'topic').then(() => {
            channel.assertQueue(queueName).then(() => {
              channel.bindQueue(queueName, exchangeName, routingKey)
                .then(() => resolve(channel));
            });
          });
        })
        .catch(error => reject(error));
    });
  },
};

'use strict';

const amqplib = require('amqplib');
const amqpUri = require('amqp-uri');

/**
 * Nortstar client service.
 */
module.exports = {
  /**
   * Configure RabbitMQ client.
   */
  getClient() {
    if (!this.client) {
      this.client = amqplib.connect(amqpUri(sails.config.amqp.connection));
    }
    return this.client;
  },
  getChannel() {
    return this.getClient().then(conn => conn.createChannel());
  },
  publishUserPasswordResetTransactional(message) {
    const queueName = 'transactionalQueue';
    const exchangeName = 'transactionalExchange';
    const bindingPattern = '*.*.transactional';
    const routingKey = 'user.password_reset.transactional';
    const msgBuffer = new Buffer(JSON.stringify(message), 'utf-8');

    this.bindQueueToExchange(queueName, exchangeName, bindingPattern)
      .then((channel) => {
        channel.publish(exchangeName, routingKey, msgBuffer)
        .then(result => result);
      });
  },
  bindQueueToExchange(queueName, exchangeName, routingKey) {
    return new Promise((resolve, reject) => {
      this.getChannel()
        .then((channel) => {
          channel.assertExchange(exchangeName, 'topic').then(() => {
            channel.assertQueue(queueName).then(() => {
              channel.bindQueue(queueName, exchangeName, routingKey)
                .then(() => resolve(channel));
            });
          });
        })
        .catch(error => reject(error));
    });
  },
};

Fix payload sent to RabbitMQ.

Fix payload sent to RabbitMQ.


/**
 *
 * Displays a single property of an object.
 *
 * ## Examples
 *
 *     <div
 *          data-hull-widget="property@hull"
 *          data-hull-id="me"
 *          data-hull-property="name"
 *          data-hull-default-text="Not found"
 *     ></div>
 *
 * ## Options
 *
 * - `id`: Required. The id of the object for which we want to display a property.
 * - `property`: Required. The name of the property to be displayed. Can be a path
 *   if the property is nested (_eg_ `stats.likes`)
 * - `default-text`: The text to be displayed if the value does not exist
 *
 * ## Template
 *
 * - `property`: Displays the property with no markup. Markup must be in the parents widget
 *   for easier customization
 *
 */
define({
  type: 'Hull',

  templates: [
    'property'
  ],

  datasources: {
    object: ':id'
  },

  refreshEvents: ['model.hull.me.change'],

  beforeRender: function(data) {
    "use strict";
    var defaultText = this.options.defaultText || 'No value';
    var value = this.findProp(data.object, this.options.property);
    return {
      property: value !== undefined ? value : defaultText
    };
  },

  findProp: function (obj, prop) {
    "use strict";
    prop.split('.').forEach(function (_p) {
      obj = !obj ? undefined : obj[_p];
    });
    return obj;
  }
});

/**
 *
 * Displays a single property of an object.
 *
 * ## Examples
 *
 *     <div
 *          data-hull-widget="property@hull"
 *          data-hull-id="me"
 *          data-hull-property="name"
 *          data-hull-default-text="Not found"
 *     ></div>
 *
 * ## Options
 *
 * - `id`: Required. The id of the object for which we want to display a property.
 * - `property`: Required. The name of the property to be displayed. Can be a path
 *   if the property is nested (_eg_ `stats.likes`)
 * - `default-text`: The text to be displayed if the value does not exist
 *
 * ## Template
 *
 * - `property`: Displays the property with no markup. Markup must be in the parents widget
 *   for easier customization
 *
 */
define({
  type: 'Hull',

  templates: [
    'property'
  ],

  datasources: {
    object: ':id'
  },

  refreshEvents: ['model.hull.me.change'],

  beforeRender: function(data) {
    "use strict";
    var defaultText = this.options.defaultText || 'No value';
    var value = this.findProp(data.object, this.options.property);
    return {
      property: value !== undefined ? value : defaultText
    };
  },

  findProp: function (obj, prop) {
    "use strict";
    var parts = prop.split('.');
    _.each(parts, function(p) {
      obj = !obj ? undefined : obj[p];
    });
    return obj;
  }
});

Use _.each instead of forEach

Use _.each instead of forEach

To be sure that IE8 and other older browers will not complain.


"use strict";
/**
 *  Collection of spines.
 **/
 define([
    "underscore",
    "backbone"
], function(_, Backbone) {

    var SpineCollection = Backbone.Collection.extend({
        filterKey: null,
        /**
         * sortBy comparator: return the title, by which BB will sort the collection.
         **/
        comparator: function(spine) {
            return spine.get("title");
        },

        url: function() {
            var url = "_view/spines";
            if (!_.isNull(this.filterKey)) {
                // Get a subset of the spines, by the given key.
                url = url + '?key="' + this.filterKey + '"';
            }

            return url;
        },
        /**
         * Parse the returned JSON.
         **/
        parse: function(response, options){
            var parsed = [];

            if (_.has(response, "rows") && _.isArray(response.rows)) {
                _.each(response.rows, function(row) {
                    parsed.push({
                        id: row.id,
                        firstLetter: row.value.firstLetter,
                        title: row.value.title
                    });
                });
            }

            return parsed;
        }
    });

    return SpineCollection;
});

"use strict";
/**
 *  Collection of spines.
 **/
 define([
    "underscore",
    "backbone"
], function(_, Backbone) {

    var SpineCollection = Backbone.Collection.extend({
        filterKey: null,
        /**
         * sortBy comparator: return the title, by which BB will sort the collection.
         **/
        comparator: function(spine) {
            return spine.get("title").toLowerCase();
        },

        url: function() {
            var url = "_view/spines";
            if (!_.isNull(this.filterKey)) {
                // Get a subset of the spines, by the given key.
                url = url + '?key="' + this.filterKey + '"';
            }

            return url;
        },
        /**
         * Parse the returned JSON.
         **/
        parse: function(response, options){
            var parsed = [];

            if (_.has(response, "rows") && _.isArray(response.rows)) {
                _.each(response.rows, function(row) {
                    parsed.push({
                        id: row.id,
                        firstLetter: row.value.firstLetter,
                        title: row.value.title
                    });
                });
            }

            return parsed;
        }
    });

    return SpineCollection;
});

Sort titles by lower case

Sort titles by lower case


import { createMachine, interpret } from 'xstate';
import './style.css';

const app = document.querySelector('#app');

app.innerHTML = `

XState JavaScript Template

Open the console!

  <button id="toggle">Toggle</button>
`;

// Edit your machine(s) here
const machine = createMachine({
  id: 'machine',
  initial: 'inactive',
  context: {
    count: 0
  },
  states: {
    inactive: {
      on: { TOGGLE: 'active' }
    },
    active: {
      on: { TOGGLE: 'inactive' }
    }
  }
});

const button = document.querySelector('#toggle');

// Edit your service(s) here
const service = interpret(machine).onTransition((state) => {
  console.log(state.value);
  button.dataset.state = state.value;
});

service.start();

button?.addEventListener('click', () => {
  service.send('TOGGLE');
});

import { interpret } from 'xstate';
import { toggleMachine } from './toggle.machine';
import './style.css';

const app = document.querySelector('#app');

app.innerHTML = `

XState JavaScript Template

Open the console!

  <button id="toggle">Toggle</button>
`;

const button = document.querySelector('#toggle');

// Edit your service(s) here
const service = interpret(toggleMachine).onTransition((state) => {
  console.log(state.value);
  button.dataset.state = state.value;
});

service.start();

button?.addEventListener('click', () => {
  service.send('TOGGLE');
});

Move machines to separate files

Move machines to separate files


import React from 'react'
import PersonCard from '../people/PersonCard'
import PersonGrid from '../people/PersonGrid'
import { parsePost } from '../posts/PostParser'
import { getLinkObject, getLinkArray } from '../../util/json_helper'

export function onboardingCommunities(users) {
  return (

      {users.map((user, i) => {
        return <PersonCard ref={'personCard_' + i} user={user} key={i} />
      })}

  )
}

export function onboardingPeople(users) {
  return (

      {users.map((user, i) => {
        return <PersonGrid ref={'personGrid_' + i} user={user} key={i} />
      })}

  )
}

export function postsAsGrid(posts, json) {
  return (

      {posts.map((post, i) => {
        return (

            {parsePost(post, json)}

        )
      })}

  )
}

export function userDetail(users, json) {
  const posts = getLinkArray(users[0], 'posts', json)
  return postsAsGrid(posts, json)
}

export { getLinkObject, getLinkArray }

Remove export methods as they are in utils now.


// http://www.colourlovers.com/palette/3459622/Flowering_Tiles

var $elements = {
  game_over: document.getElementById('game_over'),
  you_won: document.getElementById('you_won'),
};
var canvas = SVG('canvas').size(window.innerWidth-40, window.innerHeight-document.getElementById('canvas').offsetTop-20);
var board = new Board(canvas);
var stopwatch = new StopWatch({delay: 5, timer: document.getElementById('instructions')});
var level = 4;
var MAX_LEVEL = 9;

board.draw(level);
board.on('start', function() {
  stopwatch.reset();
  stopwatch.start();
});
board.on('done', function() {
  stopwatch.stop();
  document.getElementById("level"+level).classList.add("done");
  if (level == MAX_LEVEL) {
    $elements.you_won.classList.add("active");
  } else {
    level += 1;
    setTimeout(function() {
      board.draw(level);
    }, 500);
  }
});
board.on('fail', function() {
  stopwatch.stop();
  $elements.game_over.classList.add("active");
});

document.getElementById('start_over').addEventListener('click', function() {
  location.reload();
});

document.getElementById('retry').addEventListener('click', function() {
  $elements.game_over.classList.remove("active");
  board.draw(level);
});

document.body.addEventListener('touchmove', function(e){ e.preventDefault(); });

Remove link to unused color palette

Remove link to unused color palette


'use strict';

const Prismic = require('./prismic');
const Predicates = require('prismic.io').Predicates;
const _ = require('lodash');

const getQuotes = (api) => api
    .form('everything')
    .ref(Prismic.getEnvironment(api))
    .query(Predicates.at('document.type', 'quotes'))
    .submit()
    .then((quotes) => {
      return _.map(quotes.results, (result) => {
        return _.map(result.data, (datum) => {
          return datum.value[0].text;
        });
      });
    });

const homeHandler = (request, reply) => {
  Prismic.getAPI().then((api) => {
    const stagingReleaseRef =
      api.ref(process.env.PRISMIC_IO_STAGING_RELEASE_NAME);
    getQuotes(api).then((quotes) => {
      reply.view('quotes', {
        quotes: quotes,
        environment: stagingReleaseRef ? 'Staging' : 'Production'
      });
    });
  });
};

module.exports = {
  method: 'GET',
  path: '/',
  handler: homeHandler
};

'use strict';

const Prismic = require('./prismic');
const Predicates = require('prismic.io').Predicates;
const _ = require('lodash');

const getQuotes = (api) => api
    .form('everything')
    .ref(Prismic.getEnvironment(api))
    .query(Predicates.at('document.type', 'quotes'))
    .submit()
    .then((quotes) => {
      return _.map(quotes.results, (result) => {
        return _.map(result.data, (datum) => {
          return datum.value[0].text;
        });
      });
    });

const homeHandler = (request, reply) => {
  Prismic.getAPI().then((api) => {
    const isProductionEnvironment =
      Prismic.getEnvironment(api) === api.master();

    getQuotes(api).then((quotes) => {
      reply.view('quotes', {
        quotes: quotes,
        environment: isProductionEnvironment ? 'Production' : 'Staging'
      });
    });
  });
};

module.exports = {
  method: 'GET',
  path: '/',
  handler: homeHandler
};

Fix for current environment display

Fix for current environment display


Update js so info box doesn't scroll after window size is < 1000px


import styled from './styled'

import type {
  BaseStylesType,
  ComponentStyleType,
  StyledType,
  StyledElementAttrsType,
  StyledElementType,
  TagNameOrStyledElementType
} from './types'

const getStyledArgs = (
  tagNameOrStyledElement: TagNameOrStyledElementType
): StyledElementAttrsType => {
  if (typeof tagNameOrStyledElement === 'string') {
    return {tagName: tagNameOrStyledElement, style: {}}
  }

  const {tagName, style} = tagNameOrStyledElement
  return {tagName, style}
}

const createStyled = (jss: Function) => (baseStyles: BaseStylesType = {}): StyledType => {
  let sheet

  const mountSheet = () => {
    if (!sheet) {
      sheet = jss.createStyleSheet(baseStyles, {
        link: true,
        meta: 'sheet',
      }).attach()
    }

    return sheet
  }

  return Object.assign((
    tagNameOrStyledElement: TagNameOrStyledElementType
  ) => (
    ownStyle: ComponentStyleType
  ): StyledElementType => {
    const {tagName, style} = getStyledArgs(tagNameOrStyledElement)
    const elementStyle = {...style, ...ownStyle}

    return styled({tagName, baseStyles, elementStyle, mountSheet})
  }, {mountSheet, sheet, styles: baseStyles})
}

export default createStyled

import styled from './styled'

import type {
  BaseStylesType,
  ComponentStyleType,
  StyledType,
  StyledElementAttrsType,
  StyledElementType,
  TagNameOrStyledElementType
} from './types'

const getStyledArgs = (
  tagNameOrStyledElement: TagNameOrStyledElementType
): StyledElementAttrsType => {
  if (typeof tagNameOrStyledElement === 'string') {
    return {tagName: tagNameOrStyledElement, style: {}}
  }

  const {tagName, style} = tagNameOrStyledElement
  return {tagName, style}
}

const createStyled = (jss: Function) => (baseStyles: BaseStylesType = {}): StyledType => {
  let sheet

  const mountSheet = () => {
    if (!sheet) {
      sheet = jss.createStyleSheet(baseStyles, {
        link: true,
        meta: 'styled-jss',
      }).attach()
    }

    return sheet
  }

  return Object.assign((
    tagNameOrStyledElement: TagNameOrStyledElementType
  ) => (
    ownStyle: ComponentStyleType
  ): StyledElementType => {
    const {tagName, style} = getStyledArgs(tagNameOrStyledElement)
    const elementStyle = {...style, ...ownStyle}

    return styled({tagName, baseStyles, elementStyle, mountSheet})
  }, {mountSheet, sheet, styles: baseStyles})
}

export default createStyled

Set meta-name for sheet as "styled-jss"

Set meta-name for sheet as "styled-jss"


import { expect } from 'chai';
import { shallow, mount } from 'enzyme';
import React from 'react';
import { Post } from '../../src/js/components/Post';

describe('<Post/>', () => {
  const post = {
    id: 0,
    title: 'Test Post',
    content: 'empty',
    description: 'empty',
    author: 'bot',
    slug: 'test-post',
    tags: ['test', 'react'],
  };

  it('renders post title', () => {
    const result = mount(<Post post={post} />);
    expect(result.find('.post__title').text()).to.eq('Test Post');
  });

  it('renders post metadata', () => {
    const result = shallow(<Post post={post} />);
    expect(result.find('.post__meta').text()).to.eq('a few seconds ago');
  });
});

import { expect } from 'chai';
import { mount } from 'enzyme';
import React from 'react';
import { Post } from '../../src/js/components/Post';

describe('<Post/>', () => {
  const post = {
    id: 0,
    title: 'Test Post',
    content: 'empty',
    description: 'empty',
    author: 'bot',
    slug: 'test-post',
    tags: ['test', 'react'],
  };

  it('renders post title', () => {
    const result = mount(<Post post={post} />);
    expect(result.find('.post__title').text()).to.eq('Test Post');
  });

  it('renders post metadata', () => {
    const result = mount(<Post post={post} />);
    expect(result.find('.post__meta').text()).to.eq('  a few seconds ago');
  });
});

Update Post tests to match rendered output


'use strict';

/* global Connector */

var trackInfo = null;

function updateTrackInfo() {
	trackInfo = JSON.parse(localStorage.getItem('audio_v10_track'));
}

/**
 * Decodes HTML entities in given text string
 * @param  {String} str String with HTML entities
 * @return {String}     Decoded string
 */
var decodeHtmlEntity = function(str) {
	if (str === null) {
		return null;
	}

	return str.replace(/&#(\d+);/g, function(match, dec) {
		return String.fromCharCode(dec);
	});
};

Connector.artistTrackSelector = '.top_audio_player_title';
Connector.playerSelector = '#top_audio_player';

Connector.getArtist = function () {
			updateTrackInfo();
			return decodeHtmlEntity(trackInfo[4]);
		};
Connector.getTrack = function () {
			updateTrackInfo();
			return decodeHtmlEntity(trackInfo[3]);
		};
Connector.getCurrentTime = function () {
			updateTrackInfo();
			var progress = parseFloat(localStorage.getItem('audio_v10_progress'));
			return Math.round(parseInt(trackInfo[5])*progress);
		};
Connector.getDuration = function () {
			updateTrackInfo();
			return parseInt(trackInfo[5]);
		};
Connector.isPlaying = function() {
	return $(this.playerSelector).hasClass('top_audio_player_playing');
		};

'use strict';

/* global Connector */

var INFO_TRACK = 3;
var INFO_ARTIST = 4;
var INFO_DURATION = 5;

var trackInfo = null;

function updateTrackInfo() {
	trackInfo = JSON.parse(localStorage.getItem('audio_v10_track'));
}

/**
 * Decodes HTML entities in given text string
 * @param  {String} str String with HTML entities
 * @return {String}     Decoded string
 */
var decodeHtmlEntity = function(str) {
	if (str === null) {
		return null;
	}

	return str.replace(/&#(\d+);/g, function(match, dec) {
		return String.fromCharCode(dec);
	});
};

Connector.artistTrackSelector = '.top_audio_player_title';
Connector.playerSelector = '#top_audio_player';

Connector.getArtist = function () {
			updateTrackInfo();
			return decodeHtmlEntity(trackInfo[INFO_ARTIST]);
		};
Connector.getTrack = function () {
			updateTrackInfo();
			return decodeHtmlEntity(trackInfo[INFO_TRACK]);
		};
Connector.getCurrentTime = function () {
			updateTrackInfo();
			var progress = parseFloat(localStorage.getItem('audio_v10_progress'));
			return Math.round(parseInt(trackInfo[INFO_DURATION]) * progress);
		};
Connector.getDuration = function () {
			updateTrackInfo();
			return parseInt(trackInfo[INFO_DURATION]);
		};
Connector.isPlaying = function() {
	return $(this.playerSelector).hasClass('top_audio_player_playing');
		};

Use constants instead of magic numbers

Use constants instead of magic numbers


define([
    './module',
    'jquery',
    'text!./link.html'
], function(directives, $, linkTpl) {
    'use strict';

    directives.directive('zoriLink', ['$interval',
        function($interval) {
            function link(scope, element, attrs) {
                var timeoutId;
                var $link = $(element).find('a');

                function update() {
                    var nbClick = scope.link.nbClick;
                    var height = nbClick * 30 + 30;
                    var hue = nbClick * 10 + 10;

                    var style = {
                        height      : height + 'px',
                        'margin-top': -(height / 2) + 'px',
                        background  : 'linear-gradient(to bottom, hsl(' + hue + ', 99%, 65%) 50%, hsl(' + hue + ', 99%, 30%) 51%)'
                    };

                    $link.css(style);
                }

                scope.$watch(attrs.myCurrentTime, function(value) {
                    update();
                });

                element.on('$destroy', function() {
                    $interval.cancel(timeoutId);
                });

                timeoutId = $interval(function() {
                    update();
                }, 1000);
            }

            return {
                restrict: 'A',
                template: linkTpl,
                link: link
            };
        }
    ]);
});

define([
    './module',
    'jquery',
    'text!./link.html'
], function(directives, $, linkTpl) {
    'use strict';

    directives.directive('zoriLink', ['$interval',
        function($interval) {
            function link(scope, element, attrs) {
                var timeoutId;
                var $link = $(element).find('a');

                function update() {
                    var nbClick = scope.link.nbClick;
                    var height = nbClick * 30 + 30;
                    var hue = Math.min(nbClick * 10, 100);

                    var style = {
                        height      : height + 'px',
                        'margin-top': -(height / 2) + 'px'
                    };

                    if (nbClick > 0) {
                        style.background = 'linear-gradient(to bottom, hsl(' + hue + ', 99%, 65%) 50%, hsl(' + hue + ', 99%, 30%) 51%)';
                    }

                    $link.css(style);
                }

                scope.$watch(attrs.myCurrentTime, function(value) {
                    update();
                });

                element.on('$destroy', function() {
                    $interval.cancel(timeoutId);
                });

                timeoutId = $interval(function() {
                    update();
                }, 1000);
            }

            return {
                restrict: 'A',
                template: linkTpl,
                link: link
            };
        }
    ]);
});

Add a maximum hue for link color

Add a maximum hue for link color


module.exports = function(gatewayd) {
  //  ADD PLUGINS HERE, SUCH AS SETUP WIZARD
  //  const WizardPlugin = require('gatewayd-setup-wizard-plugin');
  //  var wizardPlugin = new WizardPlugin({
  //    gatewayd: gatewayd
  //  });
  //  gatewayd.server.use('/', wizardPlugin.router);
}

module.exports = function(gatewayd) {
  //  ADD PLUGINS HERE, SUCH AS SETUP WIZARD
  const WizardPlugin = require('gatewayd-setup-wizard-plugin');
  var wizardPlugin = new WizardPlugin({
     gatewayd: gatewayd
  });
  gatewayd.server.use('/', wizardPlugin.router);
}

Enable wizard. Access it by going to https://localhost:5000/wizard


/* eslint-env mocha */
const jumpsearch = require('../../../src').algorithms.Searching.jumpsearch;
const assert = require('assert');

describe('Jump Search', () => {
  it('should return -1 for empty array', () => {
    const index = jumpsearch([], 1);

    assert.equal(index, -1);
  });

  it('should return -1 for no element found in array', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 1);

    assert.equal(index, -1);
  });

  it('should return index of mid element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 4);

    assert.equal(index, 2);
  });

  it('should return index of first element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 2);

    assert.equal(index, 0);
  });

  it('should return index of last element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 6);

    assert.equal(index, 4);
  });
});

/* eslint-env mocha */
const jumpsearch = require('../../../src').algorithms.Searching.jumpsearch;
const assert = require('assert');

describe('Jump Search', () => {
  it('should return -1 for empty array', () => {
    const index = jumpsearch([], 1);

    assert.equal(index, -1);
  });

  it('should return -1 for no element found in array', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 1);

    assert.equal(index, -1);
  });

  it('should return index of mid element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 4);

    assert.equal(index, 2);
  });

  it('should return index of first element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 2);

    assert.equal(index, 0);
  });

  it('should return index of last element', () => {
    const index = jumpsearch([2, 3, 4, 5, 6], 6);

    assert.equal(index, 4);
  });

  it('should return index of last element', () => {
    const sortedArray = [];

    for (let i = 0; i <= 100; i += 2) {
      sortedArray.push(i);
    }

    assert.equal(jumpsearch(sortedArray, 6), 3);
    assert.equal(jumpsearch(sortedArray, 103), -1);
    assert.equal(jumpsearch(sortedArray, 79), -1);
  });
});

Test Jump Search: Test coverage improved to 94.12


function maybeLog(log, links) {
  links.forEach((link) => {
    if (link.broken) {
      log(link.description)
    }
  })
}

function maybeThrow(links) {
  const brokenLinks = links.filter(({broken}) => !!broken)
  if (brokenLinks.length) {
    let message = `You have ${brokenLinks.length} broken links:`
    brokenLinks.forEach(({description}) => {
      message += `\n${description}`
    })
    throw new Error(message)
  }
}

module.exports = (options, log = console.log) => {
  return (links) => {
    if (options.warn) {
      maybeLog(log, links)
    } else {
      maybeThrow(links)
    }
  }
}

function maybeLog(log, links) {
  links.forEach((link) => {
    if (link.broken) {
      log(link.description)
    }
  })
}

function maybeThrow(links) {
  const brokenLinks = links.filter(({broken}) => !!broken)

  if (brokenLinks.length) {
    let message = `You have ${brokenLinks.length} broken links:\n`
    brokenLinks.forEach(({filename, description}) => {
      message += `\n${filename} >>> ${description}`
    })
    throw new Error(message)
  }
}

module.exports = (options, log = console.log) => {
  return (links) => {
    if (options.warn) {
      maybeLog(log, links)
    } else {
      maybeThrow(links)
    }
  }
}

Add file name and some (subjective) readability in the log


import React, { Component } from 'react';
import Dispatcher from '../utils/front-end-dispatcher';
import SimpleButton from './simple-button'

var EmptySitesList = React.createClass({
  requestNewSite: function() {
    Dispatcher.send('addSite');
  },
  createNewSite: function() {
    Dispatcher.send('createSite');
  },
  render: function () {
    if(this.props.sitesReceived == true) {
      var childIcon =
;
      return (

Oh dear! This list is empty.

            <SimpleButton onClick={this.createNewSite} className="btn-create">

              Create
            </SimpleButton>
            <SimpleButton href="#" onClick={this.requestNewSite} className="btn-open">

              Open
            </SimpleButton>

      );
    } else {
      return (
 );
    }
  }
})

module.exports = EmptySitesList;

import React, { Component } from 'react';
import Dispatcher from '../utils/front-end-dispatcher';
import SimpleButton from './simple-button'

var EmptySitesList = React.createClass({
  requestNewSite: function() {
    Dispatcher.send('addSite');
  },
  createNewSite: function() {
    Dispatcher.send('createSite');
  },
  render: function () {
    var childIcon =
;
    return (

Oh dear! This list is empty.

          <SimpleButton onClick={this.createNewSite} className="btn-create">

            Create
          </SimpleButton>
          <SimpleButton href="#" onClick={this.requestNewSite} className="btn-open">

            Open
          </SimpleButton>

    );
  }
})

module.exports = EmptySitesList;

Fix empty window on very first open

Fix empty window on very first open


const path = require('path');

module.exports = function makeSettingsPatch(name, dependencyConfig, projectConfig) {
  const relative = path.relative(
    projectConfig.sourceDir,
    dependencyConfig.sourceDir
  );

  /**
   * Replace pattern by patch in the passed content
   * @param  {String} content Content of the Settings.gradle file
   * @return {String}         Patched content of Settings.gradle
   */
  return function applySettingsPatch(content) {
    const pattern = `include ':app'`;
    const patch = `include ':${name}'\n` +
      `project(':${name}').projectDir = ` +
      `new File(rootProject.projectDir, '${relative}')`;

    return content.replace(pattern, `${pattern}\n${patch}`);
  };
};

const path = require('path');

module.exports = function makeSettingsPatch(name, dependencyConfig, projectConfig) {
  const relative = path.relative(
    projectConfig.sourceDir,
    dependencyConfig.settingsGradlePath
  );

  /**
   * Replace pattern by patch in the passed content
   * @param  {String} content Content of the Settings.gradle file
   * @return {String}         Patched content of Settings.gradle
   */
  return function applySettingsPatch(content) {
    const pattern = `include ':app'`;
    const patch = `include ':${name}'\n` +
      `project(':${name}').projectDir = ` +
      `new File(rootProject.projectDir, '${relative}')`;

    return content.replace(pattern, `${pattern}\n${patch}`);
  };
};

Fix wrong settings gradle patch

Fix wrong settings gradle patch

settings.gradle is not always inside sourceDir. Since we already expose explicit path to it, using it is easier and safer. Fixes #23


import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

import ExpPlayerRouteMixin from 'exp-player/mixins/exp-player-route';

export default Ember.Route.extend(AuthenticatedRouteMixin, ExpPlayerRouteMixin, {
    _getExperiment() {
        return new Ember.RSVP.Promise((resolve) => {
            resolve(this.modelFor('experiments.info'));
        });
    },
    _getSession(params, experiment) {
        var session = this.store.createRecord(experiment.get('sessionCollectionId'), {
            experimentId: experiment.id,
            profileId: 'tester0.prof1', // TODO fetch from service
            profileVersion: '',
            completed: false,
            feedback: '',
            hasReadFeedback: '',
            softwareVersion: '',
            expData: {},
            sequence: []
        });

        return experiment.getCurrentVersion().then(versionId => {
            session.set('experimentVersion', versionId);
            return session.save().then(() => session);
        });
        return new Ember.RSVP.Promise((resolve) => {
            resolve(session);
        });
    },
    actions: {
        willTransition: function(transition) {
            // FIXME: This won't prevent back button or manual URL change. See https://guides.emberjs.com/v2.3.0/routing/preventing-and-retrying-transitions/#toc_preventing-transitions-via-code-willtransition-code
            if (this.controller.isDirty() && !confirm('Are you sure you want to exit the experiment?')) {
                transition.abort();
                return false;
            } else {
                // Bubble this action to parent routes
                return true;
            }
        }
    }
});

import Ember from 'ember';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';

import ExpPlayerRouteMixin from 'exp-player/mixins/exp-player-route';

export default Ember.Route.extend(AuthenticatedRouteMixin, ExpPlayerRouteMixin, {
    currentUser: Ember.inject.service(),
    _getExperiment() {
        return new Ember.RSVP.Promise((resolve) => {
            resolve(this.modelFor('experiments.info'));
        });
    },
    _getSession(params, experiment) {
        return this.get('currentUser').getCurrentUser().then(([account, profile]) => {
            return this.store.createRecord(experiment.get('sessionCollectionId'), {
                experimentId: experiment.id,
                profileId: profile.get('id'),
                profileVersion: '', // TODO
                completed: false,
                feedback: '',
                hasReadFeedback: '',
                softwareVersion: '',
                expData: {},
                sequence: []
            });
        });
    },
    actions: {
        willTransition: function(transition) {
            // FIXME: This won't prevent back button or manual URL change. See https://guides.emberjs.com/v2.3.0/routing/preventing-and-retrying-transitions/#toc_preventing-transitions-via-code-willtransition-code
            if (this.controller.isDirty() && !confirm('Are you sure you want to exit the experiment?')) {
                transition.abort();
                return false;
            } else {
                // Bubble this action to parent routes
                return true;
            }
        }
    }
});

Use currentUser service to set session.profileId


var esformatter = require('esformatter');
var stringify = require("json-literal").stringify;
var fs = require("fs");
var path = require("path");

/**
 * Class that writes an object to a file (using the `json-literal` module)
 * @param {*} `data` the javascript object,
 * @constructor
 */
function Writer(data) {
    var prettyPrint = false;

    /**
     * Enable pretty printed output
     */
    this.pretty = function () {
        prettyPrint = true;
        return this;
    };

    /**
     * Write the data to a file (synchronously).
     * @param {string} `targetDir` the directory of the file
     * @param {string} `filename` the name of the file
     */
    this.writeTo = function (targetDir, filename) {
        // Remove wrapping parens which are always created by json-literal
        var node = stringify(data).replace(/^\((.*)\)$/, "$1");
        // Create a valid javascript module
        var string = "module.exports = function() { return " + node + "};";
        // If prettyprint is enabled, use esformatter to format
        // the resulting javascript.
        if (prettyPrint) {
            string = esformatter.format(string, {
                // indent is hard coded to 4 spaces at the moment
                indent: {
                    value: '    '
                }
            });
        }
        // Write the data...
        var targetFile = path.join(targetDir, filename);
        console.log("Writing ", targetFile);
        fs.writeFileSync(targetFile, string, "utf-8");
        console.log("done");
    }
}

module.exports = Writer;

var esformatter = require('esformatter');
var stringify = require("json-literal").stringify;
var fs = require("fs");
var path = require("path");

/**
 * Class that writes an object to a file (using the `json-literal` module)
 * @param {*} `data` the javascript object,
 * @constructor
 */
function Writer(data) {
    var prettyPrint = false;

    /**
     * Enable pretty printed output
     */
    this.pretty = function () {
        prettyPrint = true;
        return this;
    };

    /**
     * Write the data to a file (synchronously).
     * @param {string} `targetDir` the directory of the file
     * @param {string} `filename` the name of the file
     */
    this.writeTo = function (targetDir, filename) {
        // Remove wrapping parens which are always created by json-literal
        var node = stringify(data).replace(/^\((.*)\)$/, "$1");
        // Create a valid javascript module
        var string = "module.exports = " + node + ";";
        // If prettyprint is enabled, use esformatter to format
        // the resulting javascript.
        if (prettyPrint) {
            string = esformatter.format(string, {
                // indent is hard coded to 4 spaces at the moment
                indent: {
                    value: '    '
                }
            });
        }
        // Write the data...
        var targetFile = path.join(targetDir, filename);
        console.log("Writing ", targetFile);
        fs.writeFileSync(targetFile, string, "utf-8");
        console.log("done");
    }
}

module.exports = Writer;

Remove "function()" from database-files. Why was it inserted in the first place?


module.exports = (function(){

    function parseCommandOption( args ){

        var options = {}, token;

        while( token = args.shift() ){

            if( !token.startsWith("--") ){
                 options.extra = [token].concat(args);
                 break;
            }

            let optionType = token.replace(/^--/, "");
            let i, len;

            for( i = 0, len = args.length; i < len; ++i ){
                if( args[i].startsWith("--"))
                    break;
            }

            options[optionType] = args.splice(0, i);
        }

        return options;
    }

    var handlers = {};

    handlers.echo = ( ...args )=>{
        return {
            msg: args.join(" ")
        };
    }

    return handlers;
})();

module.exports = (function(){

    function parseCommandOption( args ){

        var options = {}, token;

        while( token = args.shift() ){

            if( !token.startsWith("--") ){
                 options.extra = [token].concat(args);
                 break;
            }

            let optionType = token.replace(/^--/, "");
            let i, len;

            for( i = 0, len = args.length; i < len; ++i ){
                if( args[i].startsWith("--"))
                    break;
            }

            options[optionType] = args.splice(0, i);
        }

        return options;
    }

    var handlers = {};

    handlers.echo = ( args )=>{

        var options = {
            msg: args.join(" ")
        }

        return [ "echo", options ];
        };
    }

    return handlers;
})();

 Fix bug and update the return value ( port ).

 Changes to be committed:
    modified:   src/lib/edge/telegram/commandHandler.js


export const ALERT_BANNER_ACTIVE = true

// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  url:
    'https://www.hashicorp.com/webinars/nomad-0-12-multi-cluster-federations-cni-advanced-scheduling-and-more/',
  tag: 'WEBINAR',
  text:
    'Join us for a webinar to learn about Nomad 0.12. This release included 15+ new features and our breakthrough Multi-Cluster Deployment. Register here!',
}

export const ALERT_BANNER_ACTIVE = true

// https://github.com/hashicorp/web-components/tree/master/packages/alert-banner
export default {
  url:
    'https://www.hashicorp.com/blog/announcing-general-availability-of-hashicorp-nomad-0-12',
  tag: 'ANNOUNCING',
  text:
    'Nomad 0.12 is now generally available, which includes 15+ new features and our breakthrough Multi-Cluster Deployment. Learn more!',
}

Revert "updating banner for webinar"

Revert "updating banner for webinar"

This reverts commit 2c4a801b7de8857a1cd58c40f1d7ff8be951102c.


// @flow
import _ from 'lodash'
import ProxySet from './_proxy-set'

import type Project from './project'
import type Composition from './composition'
import Layer from './layer'

export default class TimeLane
{
    static deserialize(timelaneJson: Object, comp: Composition)
    {
        const timelane = new TimeLane
        const config = _.pick(timelaneJson.config, ['name'])
        const layers = timelaneJson.layers.map(layerJson => Layer.deserialize(layerJson))

        Object.defineProperty(timelane, 'id', timelaneJson.id)
        timelane.layers = new Set(layers)
        Object.assign(timelane.config, config)

        return timelane
    }

    id: ?string = null
    layers: Set<Layer> = new Set()

    config: {
        name: ?string,
    } = {
        name: null
    }

    get name(): string { return this.config.name }
    set name(name: string) { this.config.name = name }

    constructor()
    {
        Object.seal(this)
    }

    toPreBSON(): Object
    {
        return {
            id: this.id,
            config: Object.assign({}, this.config),
            layers: Array.from(this.layers.values()).map(layer => layer.toPreBSON()),
        }
    }

    toJSON(): Object
    {
        return {
            id: this.id,
            config: Object.assign({}, this.config),
            layers: Array.from(this.layers.values()).map(layer => layer.toJSON()),
        }
    }
}

// @flow
import _ from 'lodash'
import ProxySet from './_proxy-set'

import type Project from './project'
import type Composition from './composition'
import Layer from './layer'

export default class TimeLane
{
    static deserialize(timelaneJson: Object, comp: Composition)
    {
        const timelane = new TimeLane
        const config = _.pick(timelaneJson.config, ['name'])
        const layers = timelaneJson.layers.map(layerJson => Layer.deserialize(layerJson))

        Object.defineProperty(timelane, 'id', {value: timelaneJson.id})
        timelane.layers = new Set(layers)
        Object.assign(timelane.config, config)

        return timelane
    }

    id: ?string = null
    layers: Set<Layer> = new Set()

    config: {
        name: ?string,
    } = {
        name: null
    }

    get name(): string { return this.config.name }
    set name(name: string) { this.config.name = name }

    constructor()
    {
        Object.seal(this)
    }

    toPreBSON(): Object
    {
        return {
            id: this.id,
            config: Object.assign({}, this.config),
            layers: Array.from(this.layers.values()).map(layer => layer.toPreBSON()),
        }
    }

    toJSON(): Object
    {
        return {
            id: this.id,
            config: Object.assign({}, this.config),
            layers: Array.from(this.layers.values()).map(layer => layer.toJSON()),
        }
    }
}

Fix incorrect id assign in Timelane

Fix incorrect id assign in Timelane


var sizeOf = require('image-size');
var sass = require('node-sass');
var project = require('../../package.json');
var config = require('../config.js');

var customFunctions = {
    'image-width($url: "")': function(url) {
        var image = url.getValue();
        var dimensions = sizeOf(config.src + 'img/' + image);
        return sass.types.String(dimensions.width.toString() + 'px');
    },
    'image-height($url: "")': function(url) {
        var image = url.getValue();
        var dimensions = sizeOf(config.src + 'img/' + image);
        return sass.types.String(dimensions.height.toString() + 'px');
    }
}

module.exports = customFunctions;

var sizeOf = require('image-size');
var sass = require('node-sass');
var project = require('../../package.json');
var config = require('../config.js');

var customFunctions = {
    'image-width($url: "")': function(url) {
        var image = url.getValue();
        var dimensions = sizeOf(config.src + 'img/' + image);
        return sass.types.Number(dimensions.width, 'px');
    },
    'image-height($url: "")': function(url) {
        var image = url.getValue();
        var dimensions = sizeOf(config.src + 'img/' + image);
        return sass.types.Number(dimensions.height, 'px');
    }
}

module.exports = customFunctions;

Change image-width and image-height sass function return type to number


(function (angular, undefined) {

    angular.module('expression-builder')
        .provider('expressionBuilder', ExpressionBuilderProvider);

    ExpressionBuilderProvider.$inject = [];

	function ExpressionBuilderProvider () {
		var templates = [];

		return {
			register: function (type, property, template) {
				Builder.prototype[property] = function () {

                    Object.create(type, {

                    });
                }
			},
			$get: function () {
				return Builder;
			}
		}
	}

    function Builder () {
        this.plan = [];
    }

    Builder.prototype.apply = function (node) {
        this.plan.forEach(function (p) {
             p(node);
        });
    };

})(angular);

(function (angular, undefined) {

    angular.module('expression-builder')
        .factory('expressionBuilder', Factory);

    Factory.$inject = [];

    function Factory () {
        return ExpressionBuilder;
    }

    function ExpressionBuilder (expressions) {
        function Builder () {
            this.plan = [];
        };

        Builder.prototype.apply = function (node) {
            plan.forEach(function (p) {
                p(node);
            });
        };

        expressions.forEach(function (expression) {
            Builder.prototype[expression.property] = function (id, parameters) {
                var build = function (node, context) {
                    var expression = Object.create(expression.prototype);
                    angular.extend(model, parameters);
                    node.add(model);
                };

                this.plan.push(build);

                return this;
            };
        });

        return new Builder();
    }

})(angular);

Use factory instead of provider

Use factory instead of provider


'use strict';

function ArgumentReadNode(argIndex) {
    assert(argIndex >= 0);

    this.execute = function (frame) {
        return frame.getArg(argIndex);
    };

    this.doPreEvaluated = function (frame, args) {
        return args[argIndex];
    };
}

'use strict';

function ArgumentReadNode(contextLevel, arg, source) {
    ContextualNode.call(this, contextLevel, source);
    var _this = this;

    assert(arg.getIndex() >= 0);

    this.execute = function (frame) {
        var ctx = _this.determineContext(frame);
        return ctx.getArgument(arg.getIndex());
    };
}
ArgumentReadNode.prototype = Object.create(ContextualNode.prototype);

Fix argument read node to be context node

Signed-off-by: Stefan Marr <46f1a0bd5592a2f9244ca321b129902a06b53e03@stefan-marr.de>


import { withStyles } from '@material-ui/core/styles'
import { Link } from 'client/routes'

const styles = theme => ({
  photo: {
    position: 'absolute',
    textAlign: 'center',
    color: theme.palette.text.secondary,
    whiteSpace: 'nowrap',
  },
})

const PhotoGridItem = ({ albumSlug, item, classes }) => {
  const { versions } = item.photo

  return (
    <Link
      route='photo'
      params={{slug: albumSlug, filename: item.photo.filename}}>
      <a>
        <img
          style={{
            top: item.top,
            left: item.left,
            height: item.height,
            width: item.width,
          }}
          className={classes.photo}
          srcSet={Object.keys(versions).map(
            key => `${versions[key].url} ${versions[key].width}w`
          ).join(', ')}
          sizes={`${item.width}px`}
          src={item.photo.urls.mobile_sm}
          alt={item.photo.alt} />
      </a>
    </Link>
  )
}

export default withStyles(styles)(PhotoGridItem)

import { withStyles } from '@material-ui/core/styles'
import { Link } from 'client/routes'

const styles = theme => ({
  photo: {
    backgroundColor: theme.palette.primary.light,
    position: 'absolute',
    textAlign: 'center',
    whiteSpace: 'nowrap',
  },
})

const PhotoGridItem = ({ albumSlug, item, classes }) => {
  const { versions } = item.photo

  return (
    <Link
      route='photo'
      params={{slug: albumSlug, filename: item.photo.filename}}>
      <a>
        <img
          style={{
            top: item.top,
            left: item.left,
            height: item.height,
            width: item.width,
          }}
          className={classes.photo}
          srcSet={Object.keys(versions).map(
            key => `${versions[key].url} ${versions[key].width}w`
          ).join(', ')}
          sizes={`${item.width}px`}
          src={item.photo.urls.mobile_sm}
          alt={item.photo.alt} />
      </a>
    </Link>
  )
}

export default withStyles(styles)(PhotoGridItem)

Add background color for loading photos

Add background color for loading photos


import { IS_DEBUG } from './debug';

const obj = {};

if(IS_DEBUG) {
    Object.freeze(obj);
}

export default obj;

import { IS_DEBUG } from './debug';

const obj = Object.create(null);

if(IS_DEBUG) {
    Object.freeze(obj);
}

export default obj;

Use object without prototype as empty object


// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require bootstrap.min

$("form[data-remote='true']").on('submit', function() {
    $this = $(this)
    $btn  = $this.find("input[name='commit'][type='submit'], button[type='submit']")
                 .attr('data-loading-text', 'loading...')
                 .button('loading')

    $this.on('ajax:complete', function() {
        $btn.button('reset')
        $this.off('ajax:complete')
    })
});

$('.nav.nav-tabs.nav-js a').click(function (e) {
    e.preventDefault()
    $(this).tab('show')
})

// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require bootstrap.min

//
// Optimize remote forms
//
$("form[data-remote='true']").on('submit', function() {
    $this = $(this)
    $btn  = $this.find("input[name='commit'][type='submit'], button[type='submit']")
                 .attr('data-loading-text', 'loading...')
                 .button('loading')

    $this.on('ajax:complete', function() {
        $btn.button('reset')
        $this.off('ajax:complete')
    })
});

//
// Optimize Nav-Tabs
//
$('.nav.nav-tabs.nav-js a').click(function (e) {
    e.preventDefault()
    // var scr = document.body.scrollTop;
    window.location.hash = $(this).attr('href')
    // document.body.scrollTop = scr;
    $(this).tab('show')
})

if(window.location.hash) {
    $('.nav-js a[href="'+window.location.hash+'"]').tab('show')
}

Optimize twitter bootstrap nav-tabs javascript


const createFixer = ({range, left, right, operator}, source) => fixer => {
  const {start: leftStart, end: leftEnd} = left;
  const {start: rightStart} = right;
  const operatorRange = [leftEnd, rightStart];
  const operatorText = source.slice(...operatorRange);

  if (operator === '||') {
    const leftText = source.slice(leftStart, leftEnd);
    return [
      fixer.replaceTextRange(operatorRange, operatorText.replace(operator, `? ${leftText} :`))
    ];
  }

  return [
    fixer.replaceTextRange(operatorRange, operatorText.replace(operator, '?')),
    fixer.insertTextAfterRange(range, ' : null')
  ];
};

const create = context => ({
  LogicalExpression: node => {
    if (node.right.type === 'JSXElement') {
      context.report({
        node,
        message: 'JSX should not use logical expression',
        fix: createFixer(node, context.getSourceCode().getText())
      });
    }
  }
});

module.exports = {
  create,
  createFixer,
  meta: {
    docs: {
      description: 'Prevent falsy values to be printed'
    },
    fixable: 'code'
  }
};

const createFixer = ({range, left, right, operator}, source) => fixer => {
  const [leftStart, leftEnd] = left.range;
  const [rightStart] = right.range;
  const operatorRange = [leftEnd, rightStart];
  const operatorText = source.slice(...operatorRange);

  if (operator === '||') {
    const leftText = source.slice(leftStart, leftEnd);
    return [
      fixer.replaceTextRange(operatorRange, operatorText.replace(operator, `? ${leftText} :`))
    ];
  }

  return [
    fixer.replaceTextRange(operatorRange, operatorText.replace(operator, '?')),
    fixer.insertTextAfterRange(range, ' : null')
  ];
};

const create = context => ({
  LogicalExpression: node => {
    if (node.right.type === 'JSXElement') {
      context.report({
        node,
        message: 'JSX should not use logical expression',
        fix: createFixer(node, context.getSourceCode().getText())
      });
    }
  }
});

module.exports = {
  create,
  createFixer,
  meta: {
    docs: {
      description: 'Prevent falsy values to be printed'
    },
    fixable: 'code'
  }
};

Fix usage of start, end properties now prohibited :wrench:


(function () {
    function CreateNotifyController(
        $scope,
        contentResource,
        navigationService,
        angularHelper) {
        var vm = this;
        var currentForm;
        vm.notifyOptions = [];
        vm.save = save;
        vm.cancel = cancel;
        vm.message = {
            name: $scope.currentNode.name
        };;
        function onInit() {
            vm.loading = true;
            contentResource.getNotifySettingsById($scope.currentNode.id).then(function (options) {
                currentForm = angularHelper.getCurrentForm($scope);
                vm.loading = false;
                vm.notifyOptions = options;
            });
        }
        function cancel() {
            navigationService.hideMenu();
        };
        function save(notifyOptions) {
            vm.saveState = "busy";
            vm.saveError = false;
            vm.saveSuccces = false;
            var selectedSting = "";
            angular.forEach(notifyOptions, function (option) {
                if (option.checked === true && option.notifyCode) {
                    selectedSting += option.notifyCode;
                }
            })
            contentResource.setNotifySettingsById($scope.currentNode.id, selectedSting).then(function () {
                vm.saveState = "success";
                vm.saveSuccces = true;
            }, function (error) {
                vm.saveState = "error";
                vm.saveError = error;
            });
        }
        onInit();
    }
    angular.module("umbraco").controller("Umbraco.Editors.Content.CreateNotifyController", CreateNotifyController);
}());

(function () {
    function CreateNotifyController(
        $scope,
        contentResource,
        navigationService,
        angularHelper) {
        var vm = this;
        var currentForm;
        vm.notifyOptions = [];
        vm.save = save;
        vm.cancel = cancel;
        vm.message = {
            name: $scope.currentNode.name
        };;
        function onInit() {
            vm.loading = true;
            contentResource.getNotifySettingsById($scope.currentNode.id).then(function (options) {
                currentForm = angularHelper.getCurrentForm($scope);
                vm.loading = false;
                vm.notifyOptions = options;
            });
        }
        function cancel() {
            navigationService.hideMenu();
        };
        function save(notifyOptions) {
            vm.saveState = "busy";
            vm.saveError = false;
            vm.saveSuccces = false;
            var selectedString = "";
            angular.forEach(notifyOptions, function (option) {
                if (option.checked === true && option.notifyCode) {
                    selectedString += option.notifyCode;
                }
            })
            contentResource.setNotifySettingsById($scope.currentNode.id, selectedString).then(function () {
                vm.saveState = "success";
                vm.saveSuccces = true;
            }, function (error) {
                vm.saveState = "error";
                vm.saveError = error;
            });
        }
        onInit();
    }
    angular.module("umbraco").controller("Umbraco.Editors.Content.CreateNotifyController", CreateNotifyController);
}());

Fix typo selectedSting to selectedString


import Injector from 'lib/Injector';
import { fileInterface, file, folder } from 'lib/fileFragments';
import { buildQueryConfig as buildCreateFolderConfig } from 'state/files/createFolderMutation';

const registerQueries = () => {
  Injector.query.registerFragment('FileInterfaceFields', fileInterface);
  Injector.query.registerFragment('FileFields', file);
  Injector.query.registerFragment('FolderFields', folder);

  // @todo delete these examples/POCs, CreateFolder is not used in favour of form submit
  // and `FolderCreateInputType` does not exist
  Injector.query.register('CreateFolder', buildCreateFolderConfig());
  Injector.transform('folder-bob', (updater) => {
    updater.query('CreateFolder', (manager) => {
      manager.transformApolloConfig('props', ({ mutate }) => (prevProps) => {
        const createFolder = (parentId) => mutate({
          variables: {
            folder: {
              parentId,
              // this transform forces all folders to be called "another-bob" for no reason
              name: 'another-bob',
            },
          },
        });

        return {
          ...prevProps,
          actions: {
            ...prevProps.actions,
            files: {
              ...prevProps.actions.files,
              createFolder,
            },
          },
        };
      });
    });
  });
};

export default registerQueries;

import Injector from 'lib/Injector';
import { fileInterface, file, folder } from 'lib/fileFragments';
import { buildQueryConfig as buildCreateFolderConfig } from 'state/files/createFolderMutation';

const forceAllFoldersToBob = (manager) => {
  manager.transformApolloConfig('props', ({ mutate }) => (prevProps) => {
    const createFolder = (parentId) => mutate({
      variables: {
        folder: {
          parentId,
          // this transform forces all folders to be called "another-bob" for no reason at all
          name: 'another-bob',
        },
      },
    });

    return {
      ...prevProps,
      actions: {
        ...prevProps.actions,
        files: {
          ...prevProps.actions.files,
          createFolder,
        },
      },
    };
  });
};

const registerQueries = () => {
  Injector.query.registerFragment('FileInterfaceFields', fileInterface);
  Injector.query.registerFragment('FileFields', file);
  Injector.query.registerFragment('FolderFields', folder);

  // @todo delete these examples/POCs, CreateFolder is not used in favour of form submit
  // and `FolderCreateInputType` does not exist
  Injector.query.register('CreateFolder', buildCreateFolderConfig());

  Injector.transform('folder-bob', (updater) => {
    updater.query('CreateFolder', forceAllFoldersToBob);
  });
};

export default registerQueries;

Move the transform to a separate function


var qs = require('querystring');
var defaults = require('cog/defaults');
var quickconnect = require('rtc-quickconnect');
var getUserMedia = require('getusermedia');

var params = defaults(qs.parse(location.search.slice(1)), {
  signaller: 'http://switchboard.rtc.io/'
});

var qc;

function connect(stream) {
  // create a quickconnect instance
  qc = require('rtc-quickconnect')(params.signaller, {
    room: params.room
  });

  (params.channels || []).forEach(function(channel) {
    qc.createDataChannel(channel);
  });

  if (stream) {
    qc.addStream(stream);
  }

  console.log('connecting to signaller');
  qc.on('call:started', function(id, pc) {
    console.log('call started with peer: ' + id);
    console.log('remote stream count: ' + pc.getRemoteStreams().length);
  });

  qc.on('call:ended', function(id) {
    console.log('call ended with peer: ' + id);
  });
}

if (params.video) {
  getUserMedia({ audio: true, video: true }, function(err, stream) {
    if (err) {
      // TODO: report error
      return;
    }

    connect(stream);
  });
}
else {
  connect();
}

var qs = require('querystring');
var defaults = require('cog/defaults');
var quickconnect = require('rtc-quickconnect');
var getUserMedia = require('getusermedia');

var params = defaults(qs.parse(location.search.slice(1)), {
  signaller: 'http://switchboard.rtc.io/',
  iceServers: []
});

var qc;

function connect(stream) {
  // create a quickconnect instance
  qc = require('rtc-quickconnect')(params.signaller, {
    room: params.room,
    iceServers: params.iceServers
  });

  (params.channels || []).forEach(function(channel) {
    qc.createDataChannel(channel);
  });

  if (stream) {
    qc.addStream(stream);
  }

  console.log('connecting to signaller');
  qc.on('call:started', function(id, pc) {
    console.log('call started with peer: ' + id);
    console.log('remote stream count: ' + pc.getRemoteStreams().length);
  });

  qc.on('call:ended', function(id) {
    console.log('call ended with peer: ' + id);
  });
}

if (params.video) {
  getUserMedia({ audio: true, video: true }, function(err, stream) {
    if (err) {
      // TODO: report error
      return;
    }

    connect(stream);
  });
}
else {
  connect();
}

Read iceServers from the querystring

Read iceServers from the querystring


import {observable, computed, reaction} from 'mobx';

export default class PlayerStore {
	@observable player = {
	    name: 'Willy'
    };
	@observable level = 1;

	@computed get completedCount() {
		return this.todos.length - this.activeTodoCount;
	}

	@computed get levelCount() {
	    return this.level;
    }

	subscribeServerToStore() {
		reaction(
			() => this.toJS(),
			todos => fetch('/api/todos', {
				method: 'post',
				body: JSON.stringify({ todos }),
				headers: new Headers({ 'Content-Type': 'application/json' })
			})
		);
	}

	subscribeLocalstorageToStore() {
		reaction(
			() => this.toJS(),
			todos => localStorage.setItem('mobx-react-todomvc-todos', JSON.stringify({ todos }))
		);
	}

	addTodo (title) {
		this.todos.push(new TodoModel(this, Utils.uuid(), title, false));
	}

	changeName(name) {
	    player.name = name;
    }

    changeLevel(level) {
	    this.level = level;
    }
}

import {observable} from 'mobx';

import * as storage from 'services/localStorage';
import * as playerService from 'services/player';

class PlayerStore {
    @observable player = {};

    constructor() {
        this.player = storage.get('player');
    }

    resetTimer() {
        this.timer = 0;
    }

    changeName(name) {
        this.player.name = name;
    }
}

export default PlayerStore;

Prepare player store for refactoring

Prepare player store for refactoring


// stamper.js
//
// Make and invert standard timestamps
//
// Copyright 2012, StatusNet Inc.
//
// 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.

var dateFormat = require('dateformat');

var Stamper = {
    stamp: function(date) {
        if (!date) {
            date = new Date();
        }
        return dateFormat(date, "isoDateTime", true);
    },
    unstamp: function(ts) {
        return Date.parse(ts);
    }
};

exports.Stamper = Stamper;

// stamper.js
//
// Make and invert standard timestamps
//
// Copyright 2012, StatusNet Inc.
//
// 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.

var dateFormat = require('dateformat');

var Stamper = {
    stamp: function(date) {
        if (!date) {
            date = new Date();
        }
        return dateFormat(date, "isoDateTime", true);
    },
    unstamp: function(ts) {
        return new Date(ts);
    }
};

exports.Stamper = Stamper;

Return a date object from unstamp()

Return a date object from unstamp()


import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { get } from '@ember/object';
import { hash } from 'rsvp';

export default Route.extend({
  globalStore: service(),

  model() {
    const store = get(this, 'globalStore');

    var role = store.createRecord({
      type: `roleTemplate`,
      name: '',
      rules: [],
    });

    return hash({
      roles: store.find('roleTemplate'),
      policies: store.find('podSecurityPolicyTemplate'),
    }).then((res) => {
      res.role = role;
      return res;
    });
  },
});

import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { get } from '@ember/object';
import { hash } from 'rsvp';

export default Route.extend({
  globalStore: service(),

  model() {
    const store = get(this, 'globalStore');

    var role = store.createRecord({
      type: `roleTemplate`,
      name: '',
      rules: [],
      hidden: false,
    });

    return hash({
      roles: store.find('roleTemplate'),
      policies: store.find('podSecurityPolicyTemplate'),
    }).then((res) => {
      res.role = role;
      return res;
    });
  },
});

Add hidden false for the role created via UI

https://github.com/rancher/rancher/issues/10952


'use strict';

const { validatePayload } = require('./validate');

// Use JSON-RPC-specific logic to parse the request into an
// rpc-agnostic `rpcDef`
const handler = function ({ payload }) {
  validatePayload({ payload });

  const { method, params } = payload;
  const args = getArgs({ params });
  const rpcDef = { commandName: method, args };
  return { rpcDef };
};

// Can either be [{ ... }], [], {...} or nothing
const getArgs = function ({ params = {} }) {
  if (!Array.isArray(params)) { return params; }

  if (params.length === 0) { return {}; }

  return params[0];
};

module.exports = {
  handler,
};

'use strict';

const { validatePayload } = require('./validate');

// Use JSON-RPC-specific logic to parse the request into an
// rpc-agnostic `rpcDef`
const handler = function ({ payload }) {
  validatePayload({ payload });

  const { method, params, id } = payload;

  const args = getArgs({ params });
  const argsA = addSilent({ args, id });

  const rpcDef = { commandName: method, args: argsA };
  return { rpcDef };
};

// Can either be [{ ... }], [], {...} or nothing
const getArgs = function ({ params = {} }) {
  if (!Array.isArray(params)) { return params; }

  if (params.length === 0) { return {}; }

  return params[0];
};

// If request `id` is absent, there should be no response according to
// JSON-RPC spec. We achieve this by settings `args.silent` `true`
const addSilent = function ({ args, id }) {
  if (id != null) { return args; }

  return { ...args, silent: true };
};

module.exports = {
  handler,
};

Add support for JSON-RPC notifications

Add support for JSON-RPC notifications