/**
  @module ember-flexberry-designer
*/

import FdUmlLink from './fd-uml-link';
import { Link } from './fd-uml-link';

/**
  An object that describes an aggregation link on the UML diagram.

  @class FdUmlAggregation
  @extends FdUmlLink
*/
export default FdUmlLink.extend({

  /**
    See {{#crossLink "FdUmlPrimitive/JointJS:method"}}here{{/crossLink}}.

    @method JointJS
  */
  JointJS() {
    let properties = this.getProperties('id', 'source', 'target', 'vertices', 'labels');
    return new Aggregation(properties);
  },
});

/**
  Defines the JointJS link, which represents a association in the UML diagram.

  @for FdUmlAssociation
  @class Aggregation
  @extends flexberry.uml.Link
  @namespace flexberry.uml
  @constructor
*/
export let Aggregation = Link.define('flexberry.uml.Aggregation', {
  attrs: { '.marker-target': { d: 'M 26 10 L 13 17 L 0 10 L 13 3 z', fill: 'white' } },
});

/**
  @module ember-flexberry-designer
*/

import FdUmlLink from './fd-uml-link';
import { Link } from './fd-uml-link';
import joint from 'npm:jointjs';

/**
  An object that describes an aggregation link on the UML diagram.

  @class FdUmlAggregation
  @extends FdUmlLink
*/
export default FdUmlLink.extend({

  /**
    See {{#crossLink "FdUmlPrimitive/JointJS:method"}}here{{/crossLink}}.

    @method JointJS
  */
  JointJS() {
    let properties = this.getProperties('id', 'source', 'target', 'vertices', 'labels', 'startPoint', 'endPoint');
    return new Aggregation(properties);
  },
});

/**
  Defines the JointJS link, which represents a association in the UML diagram.

  @for FdUmlAssociation
  @class Aggregation
  @extends flexberry.uml.Link
  @namespace flexberry.uml
  @constructor
*/
export let Aggregation = Link.define('flexberry.uml.Aggregation', {
  attrs: {
    '.marker-source': { d: 'M 26 10 L 13 17 L 0 10 L 13 3 z', fill: 'white' },
    text: { visibility: 'hidden' },
    rect: { visibility: 'hidden' }
  }
}, {
  getLabelDistance: function (labelName, isVertical) {
    switch (labelName) {
      case 'startMultiplicity':
      case 'startRole':
        return 30;
      case 'endMultiplicity':
      case 'endRole':
        return isVertical ? -10 : -5;
      case 'description':
        return 0.5;
      default:
        console.log('ERROR - choose correct label name');
    }
  },
});

joint.shapes.flexberry.uml.AggregationView = joint.shapes.flexberry.uml.AssociationView.extend({});

Add text editing for aggregation


import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import postcss from 'rollup-plugin-postcss';
import uglify from 'rollup-plugin-uglify';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import pkg from './package.json';

const transformStyles = postcss({
  extract: 'dist/aos.css',
  plugins: [autoprefixer, cssnano]
});

const input = 'src/js/aos.js';

export default [
  {
    input,
    output: {
      file: pkg.browser,
      name: 'AOS',
      format: 'umd'
    },
    sourceMap: process.env.NODE_ENV === 'dev',
    plugins: [
      transformStyles,
      resolve(),
      commonjs(),
      babel({
        exclude: ['node_modules/**']
      }),
      uglify()
    ]
  },
  {
    input,
    external: Object.keys(pkg.dependencies),
    output: [
      { file: pkg.main, format: 'cjs' },
      { file: pkg.module, format: 'es' }
    ],
    plugins: [
      transformStyles,
      babel({
        exclude: ['node_modules/**']
      })
    ]
  }
];

import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import babel from 'rollup-plugin-babel';
import postcss from 'rollup-plugin-postcss';
import uglify from 'rollup-plugin-uglify';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import pkg from './package.json';

const transformStyles = postcss({
  extract: 'dist/aos.css',
  plugins: [autoprefixer, cssnano]
});

const input = 'src/js/aos.js';

export default [
  {
    input,
    output: {
      file: pkg.browser,
      name: 'AOS',
      format: 'umd',
      sourcemap: process.env.NODE_ENV === 'dev'
    },
    plugins: [
      transformStyles,
      resolve(),
      commonjs(),
      babel({
        exclude: ['node_modules/**']
      }),
      uglify()
    ]
  },
  {
    input,
    external: Object.keys(pkg.dependencies),
    output: [
      { file: pkg.main, format: 'cjs' },
      { file: pkg.module, format: 'es' }
    ],
    plugins: [
      transformStyles,
      babel({
        exclude: ['node_modules/**']
      })
    ]
  }
];

Update sourcemap setting in rollup


/* global define */
(function() {
    'use strict';
    define([], function() {
        function makeFunctions($q, $log) {
            /*
             * Take a 304 Error to Calamari API and convert it back to a success response.
             * 304s can be indicative of a state change on the server that has already
             * been completed and can be ignored.
             */
            function intercept304Error(promise) {
                return promise.then(function(resp) {
                    // request succeeded, pass through
                    return resp;
                }, function(resp) {
                    if (resp.status === 304) {
                        // request failed check if it's a 304
                        $log.debug('intercepting 304 and ignoring');
                        var d = $q.defer();
                        /* jshint camelcase: false */
                        d.resolve({
                            status: 200,
                            data: {
                                request_id: null
                            }
                        });
                        // return a new promise, this command was
                        // a NOP
                        return d.promise;
                    }
                    // pass through error
                    return resp;
                });
            }
            return {
                intercept304Error: intercept304Error
            };
        }
        return {
            makeFunctions: makeFunctions
        };
    });
})();

/* global define */
(function() {
    'use strict';
    define([], function() {
        function makeFunctions($q, $log) {
            /*
             * Take a 304 Error to Calamari API and convert it back to a success response.
             * 304s can be indicative of a state change on the server that has already
             * been completed and can be ignored.
             */
            function intercept304Error(promise) {
                return promise.then(function(resp) {
                    // request succeeded, pass through
                    return resp;
                }, function(resp) {
                    var d = $q.defer();
                    if (resp.status === 304) {
                        // request failed check if it's a 304
                        $log.debug('intercepting 304 and ignoring');
                        /* jshint camelcase: false */
                        d.resolve({
                            status: 200,
                            data: {
                                request_id: null
                            }
                        });
                        // return a new promise, this command was
                        // a NOP
                        return d.promise;
                    }
                    // pass through error
                    d.reject(resp)
                    return d.promise;
                });
            }
            return {
                intercept304Error: intercept304Error
            };
        }
        return {
            makeFunctions: makeFunctions
        };
    });
})();

Fix error callback issue in pool modification


import batch from '../batch';

const batchType = batch.getType();

export function actionTransformer(action) {
  if (action && action.type === batchType) {
    action.payload.type = batchType;
    return action.payload;
  }
  return action;
}

export const logger = {};

for (const level in console) {
  if (typeof console[level] === 'function') {
    logger[level] = function levelFn(...args) {
      const lastArg = args.pop();

      if (Array.isArray(lastArg)) {
        lastArg.forEach(action => {
          console[level].apply(console, [...args, action]);
        });
      } else {
        args.push(lastArg);
        console[level].apply(console, args);
      }
    };
  }
}

import batch from '../batch';

const batchType = batch.getType();

export function actionTransformer(action) {
  if (action && action.type === batchType) {
    action.payload.type = batchType;
    return action.payload;
  }
  return action;
}

export const logger = {};

for (const level in console) {
  if (typeof console[level] === 'function') {
    logger[level] = function levelFn(...args) {
      const lastArg = args.pop();

      if (Array.isArray(lastArg) && lastArg.type === batchType) {
        lastArg.forEach(action => {
          console[level].apply(console, [...args, action]);
        });
      } else {
        args.push(lastArg);
        console[level].apply(console, args);
      }
    };
  }
}

Improve safety on batch logger


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

var assert = require('assert');
var http = require('http');
var bowerBrowser = require('../lib/');

describe('Server', function () {

  this.timeout(10000);

  it('should return HTTP response', function (done) {
    var app = bowerBrowser({
      path: 'test/fixtures',
      open: false,
      silent: true
    });
    app.on('start', function () {
      http.get('http://localhost:3010/', function (res) {
        assert(res.statusCode === 200);
        app.close();
        done();
      });
    });
  });

  it('should listen specified port', function (done) {
    var app = bowerBrowser({
      path: 'test/fixtures',
      open: false,
      silent: true,
      port: 3011
    });
    app.on('start', function () {
      http.get('http://localhost:3011/', function (res) {
        assert(res.statusCode === 200);
        app.close();
        done();
      });
    });
  });

});

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

var assert = require('assert');
var http = require('http');
var _ = require('lodash');

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

var baseOptions = {
  path: 'test/fixtures',
  open: false,
  silent: true
};

describe('Server', function () {

  this.timeout(10000);

  it('returns HTTP response', function (done) {
    var app = bowerBrowser(baseOptions);
    app.on('start', function () {
      http.get('http://localhost:3010/', function (res) {
        assert(res.statusCode === 200);
        app.close();
        done();
      });
    });
  });

  it('isn\'t accessible after `close` event', function (done) {
    var app = bowerBrowser(baseOptions);
    app.on('start', function () {
      http.get('http://localhost:3010/', function (res) {
        assert(res.statusCode === 200);
        app.close();
      });
    });
    app.on('close', function () {
      http.get('http://localhost:3010/')
      .on('error', function (error) {
        assert(error.code = 'ECONNRESET');
        done();
      });
    });
  });

  it('listens specified port', function (done) {
    var app = bowerBrowser(_.merge({}, baseOptions, {
      port: 3011
    }));
    app.on('start', function () {
      http.get('http://localhost:3011/', function (res) {
        assert(res.statusCode === 200);
        app.close();
        done();
      });
    });
  });

});

Add testing of close event


import * as React from 'react';

const HEADERS = ['no', 'text', 'log'];

export const BuilderDataTable = props => {
  return (

{HEADERS.map(header => {header}	)}

        {props.data.map(datapoint =>

            {HEADERS.forEach(header => {datapoint[header]}	)}

        )}

  );
}

import * as React from 'react';

const HEADERS = ['no', 'text', 'log'];

/**
 * Table responsible for storing the data for a builder.
 *
 * @param {Object[]} props.buildSteps - The build steps for a given builder.
 * @param {string} props.buildSteps[].step_number - The relative order of the build step.
 * @param {string} props.buildSteps[].text - Output text related to the build step.
 * @param {string} props.buildSteps[].log - A URL pointing to the log file.
 */
export const BuilderDataTable = props => {
  return (

{HEADERS.map(header => {header}	)}

        {props.buildSteps.map(datapoint =>

            {HEADERS.forEach(header => {datapoint[header]}	)}

        )}

  );
}

Update comments and rename props.data to props.buildStep


// Configure and set up the tests.
require.config({
  baseUrl: "../build/"
})

var specs = [
  'chordmeister/chord_spec.js',
  'chordmeister/song_spec.js',
  'chordmeister/parser_spec.js',
  'chordmeister/classified_line_spec.js',
];

console.log("here");

require(specs, function(require) {
  console.log("in the spec require block");
  mocha.setup('bdd');
  expect = chai.expect;
  // Why? Some async loading condition? Is there a cb I should be hooking into?
  setTimeout(function() {
    console.log("almost there")
    mocha.run();
  }, 1000);
})

// Configure and set up the tests.
require.config({
  baseUrl: "../build/"
})

var specs = [
  'chordmeister/chord_spec.js',
  'chordmeister/song_spec.js',
  'chordmeister/parser_spec.js',
  'chordmeister/classified_line_spec.js',
];

require(specs, function(require) {
  mocha.setup('bdd');
  expect = chai.expect;
  // Why? Some async loading condition? Is there a cb I should be hooking into?
  setTimeout(function() {
    mocha.run();
  }, 100);
})

Tweak test logging and speed.


module.exports = function forfeitRegExp(forfeit){
  if (forfeit.regex) return new RegExp(forfeit.regex,'i');
  else return new RegExp('\\b'+ forfeit.phrase.replace(
    /[-\/\\^$*+?.()|[\]{}]/g, '\\$&') + '\\b','i');
};

module.exports = function forfeitRegExp(forfeit){
  if (forfeit.regex) return new RegExp(forfeit.regex,'i');
  else return new RegExp('\\b' + forfeit.phrase
    .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
    .replace(/\s+/g,'\\W*') + '\\b','i');
};

Allow spaces to substitute for any non-word character in forfeits


(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');

  var ContentHeader = helper.inherits(function(props) {
    ContentHeader.super_.call(this);

    this.element = this.prop(props.element);
  }, jCore.Component);

  if (typeof module !== 'undefined' && module.exports)
    module.exports = ContentHeader;
  else
    app.ContentHeader = ContentHeader;
})(this.app || (this.app = {}));

(function(app) {
  'use strict';

  var jCore = require('jcore');
  var helper = app.helper || require('../helper.js');
  var dom = app.dom || require('../dom.js');

  var ContentHeader = helper.inherits(function(props) {
    ContentHeader.super_.call(this);

    this.element = this.prop(props.element);
  }, jCore.Component);

  ContentHeader.prototype.sidebarToggleButtonElement = function() {
    return dom.child(this.element(), 0);
  };

  if (typeof module !== 'undefined' && module.exports)
    module.exports = ContentHeader;
  else
    app.ContentHeader = ContentHeader;
})(this.app || (this.app = {}));

Add method to access an element of sidebar-toggle-button


pref("extensions.torbirdy.protected", false);
pref("extensions.torbirdy.proxy", 0);
pref("extensions.torbirdy.first_run", true);
pref("extensions.torbirdy.warn", true);
pref("extensions.torbirdy.startup_folder", false);
pref("extensions.torbirdy.enigmail.throwkeyid", true);

Update default preferences to reflect --throw-keyids change


/**
 * Selenium script for running Jasmine unit tests.
 */
module.exports = function(browser, chain, options) {
	chain
		.waitForElementByClassName('alert', options.testReadyTimeout)
		.waitForCondition('!!jasmine.runnerResults', options.testTimeout, options.testInterval)
		.safeEval("jasmine.getJSReport ? jasmine.getJSReport() : null", function(err, obj) {
			if (obj) {
				browser.saucePassed = obj.passed;
				browser.sauceData = { jasmine: obj };
			}
		});
};

/**
 * Selenium script for running Jasmine unit tests.
 */
module.exports = function(browser, chain, options) {
	chain
		.waitForElementByClassName('jasmine_reporter', options.testReadyTimeout)
		.waitForCondition('!!jasmine.runnerResults', options.testTimeout, options.testInterval)
		.safeEval("jasmine.getJSReport ? jasmine.getJSReport() : null", function(err, obj) {
			if (obj) {
				browser.saucePassed = obj.passed;
				browser.sauceData = { jasmine: obj };
			}
		});
};

Fix compatibility issue with Jasmine 1.1.0.


$(document).ready(function(){

    // Instantiate cpliboard button event listeners
    new Clipboard('.copy-button');

    // Iterate over table rows, amending as necessary
    // TODO access table body directly by class name.
    $('.link-table').children().each(function(tableIndex, tablePart) {
        // Access tbody of the link table
        if (tableIndex == 1){
            // Iterate over table rows
            $(tablePart).children().each(function(tableRowIndex, tableRow){
                // Create href attribute with valid URL endpoint for 'a' element
                var linkToken = $(tableRow).attr("id");
                var shortLinkElem = tableRow.getElementsByClassName("link-token")[0].getElementsByTagName("a");
                var shortLink = location.host + "/" + linkToken;
                $(shortLinkElem).attr("href", (location.protocol + "//" + shortLink));
                $(shortLinkElem).text(shortLink);

                // Create target for copy button
                var copyButton = tableRow.getElementsByClassName("copy-button")[0];
                var target = $(shortLinkElem).attr("href");
                $(copyButton).attr("data-clipboard-text", target);

            });    // Close iterate over table rows

        }    // Close if element is table body

    });    // Close iterating over table elements

});    // Close document.ready

$(document).ready(function(){

    // Instantiate clipboard button event listeners
    new Clipboard('.copy-button');

    // Iterate over table rows amending certain cells as necessary
    $('.link-table-body').children().each(function(tableRowIndex, tableRow){
        // Create href attribute with valid URL endpoint for 'a' element
        var linkToken = $(tableRow).attr("id");
        var shortLinkElem = tableRow.getElementsByClassName("link-token")[0].getElementsByTagName("a");
        var shortLink = location.host + "/" + linkToken;
        $(shortLinkElem).attr("href", (location.protocol + "//" + shortLink));
        $(shortLinkElem).text(shortLink);

        // Create target for copy button
        var copyButton = tableRow.getElementsByClassName("copy-button")[0];
        var target = $(shortLinkElem).attr("href");
        $(copyButton).attr("data-clipboard-text", target);

    });    // Close iterate over table rows

});    // Close document.ready

Tidy js: use classes to more cleanly access table.


'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');

module.exports = function (defaults) {
  let app = new EmberAddon(defaults, {
    'ember-froala-editor': {
      plugins: [
        'align',
        'char_counter',
        'colors',
        'emoticons',
        'entities',
        'font_family',
        'font_size',
        'line_breaker',
        'link',
        'lists',
        'paragraph_format',
        'special_characters',
        'table',
        'url',
      ],
    },
  });

  /*
    This build file specifies the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */

  const { maybeEmbroider } = require('@embroider/test-setup');
  return maybeEmbroider(app, {
    skipBabel: [
      {
        package: 'qunit',
      },
    ],
  });
};

'use strict';

const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');

module.exports = function (defaults) {
  let app = new EmberAddon(defaults, {
    'ember-froala-editor': {
      plugins: [
        'align',
        'char_counter',
        'colors',
        'emoticons',
        'entities',
        'font_family',
        'font_size',
        'line_breaker',
        'link',
        'lists',
        'paragraph_format',
        'special_characters',
        'table',
        'url',
      ],
      themes: ['dark', 'gray', 'royal'],
    },
  });

  /*
    This build file specifies the options for the dummy test app of this
    addon, located in `/tests/dummy`
    This build file does *not* influence how the addon or the app using it
    behave. You most likely want to be modifying `./index.js` or app's build file
  */

  const { maybeEmbroider } = require('@embroider/test-setup');
  return maybeEmbroider(app, {
    skipBabel: [
      {
        package: 'qunit',
      },
    ],
  });
};

Add themes back to the build for testing


"use strict";

function ActiveUsersComponent(target, topicId) {
  this.targetElement = target;
  this.topicId = topicId;
}

ActiveUsersComponent.prototype.render = function () {
  getActiveUsers(this.topicId, (data) => {
    let userNameDivs = appendUserNames(...data.userNames);

    appendToSidebar(this.targetElement, userNameDivs);
  });
};

// Create new component
let component = new ActiveUsersComponent(".active-users", 17);

component.render();

Create a new instance of ActiveUsersComponent. Call render method


var CMS = require('../agents/cms');

module.exports = {
  displayCMSPage: function(request, reply) {
    CMS(request.params.slug).then(function(page) {
      reply.view('cms', {
        contentIsFullwidth: true,
        page: page,
        title: page.title
      });
    }, function(err) {
      request.logger.error(err);
      if (err.statusCode == 404) {
        return reply.view('errors/not-found', err).code(404);
      } else {
        return reply.view('errors/internal', err).code(500);
      }
    }).catch(function(err) {
      request.logger.error(err);
    });
  }
}

var CMS = require('../agents/cms');

module.exports = {
  displayCMSPage: function(request, reply) {
    CMS(request.params.slug).then(function(page) {
      reply.view('cms', {
        contentIsFullwidth: true,
        page: page,
        title: page.title
      });
    }).catch(function(err) {
      if (err.statusCode == 404) {
        request.logger.error(err);
        return reply.view('errors/not-found', err).code(404);
      } else {
        return reply(err);
      }
    });
  }
}

Use new simpler error handling interface to handle CMS errors


require("./core");
var types = require("../lib/types");
var def = types.Type.def;
var or = types.Type.or;
var builtin = types.builtInTypes;
var isBoolean = builtin.boolean;
var defaults = require("../lib/shared").defaults;

def("Function")
    .field("async", isBoolean, defaults["false"]);

def("SpreadProperty")
    .bases("Node")
    .build("argument")
    .field("argument", def("Expression"));

def("ObjectExpression")
    .field("properties", [or(def("Property"), def("SpreadProperty"))]);

def("SpreadPropertyPattern")
    .bases("Pattern")
    .build("argument")
    .field("argument", def("Pattern"));

def("ObjectPattern")
    .field("properties", [or(
        def("PropertyPattern"),
        def("SpreadPropertyPattern")
    )]);

def("AwaitExpression")
    .bases("Expression")
    .build("argument", "all")
    .field("argument", or(def("Expression"), null))
    .field("all", isBoolean, false);

require("./core");
var types = require("../lib/types");
var def = types.Type.def;
var or = types.Type.or;
var builtin = types.builtInTypes;
var isBoolean = builtin.boolean;
var defaults = require("../lib/shared").defaults;

def("Function")
    .field("async", isBoolean, defaults["false"]);

def("SpreadProperty")
    .bases("Node")
    .build("argument")
    .field("argument", def("Expression"));

def("ObjectExpression")
    .field("properties", [or(def("Property"), def("SpreadProperty"))]);

def("SpreadPropertyPattern")
    .bases("Pattern")
    .build("argument")
    .field("argument", def("Pattern"));

def("ObjectPattern")
    .field("properties", [or(
        def("PropertyPattern"),
        def("SpreadPropertyPattern")
    )]);

def("AwaitExpression")
    .bases("Expression")
    .build("argument", "all")
    .field("argument", or(def("Expression"), null))
    .field("all", isBoolean, defaults["false"]);

Fix AwaitExpression all field default value


var static = require('node-static');
var http = require('http');

var port = process.argv[2] || 3000;
var file = new static.Server(__dirname + '/static');

http.createServer(function(req, res) {
  req.addListener('end', function() {
    file.serve(req, res);
  }).resume();
}).listen(port);

var static = require('node-static');
var http = require('http');
var path = require('path');

var port = process.argv[2] || 3000;
var file = new static.Server(path.resolve(__dirname, './static'));

http.createServer(function(req, res) {
  req.addListener('end', function() {
    file.serve(req, res);
  }).resume();
}).listen(port);

Use `path.resolve` to create path to `static/`


var mocha = require('mocha')
var chai = require('chai')
var chaiAsPromised = require('chai-as-promised')
chai.use(chaiAsPromised)
var protractor = require('protractor')

mocha.describe('End2end test suite', () => {
  mocha.it('should load completely and have a title', (done) => {
    protractor.browser.ignoreSynchronization = true
    protractor.browser.loadAndWaitForAureliaPage('/')
    chai.expect(protractor.browser.getTitle()).to.eventually.be.equal('Hello World | Hello World')
      .notify(done)
  })
})

var mocha = require('mocha')
var chai = require('chai')
var chaiAsPromised = require('chai-as-promised')
chai.use(chaiAsPromised)
var protractor = require('protractor')

mocha.describe('End2end test suite', () => {
  mocha.it('should load completely and have a title', (done) => {
    protractor.browser.loadAndWaitForAureliaPage('/')
    chai.expect(protractor.browser.getTitle()).to.eventually.be.equal('Hello World | Hello World')
      .notify(done)
  })
})

Remove not needed synchronization statement. We already do that in our configuration file.


var gulp          = require('gulp');
var rename        = require('gulp-rename');
var browserSync   = require('browser-sync');
var webpackStream = require('webpack-stream');
var webpack       = require('webpack');

var config = {
	watch: false,
	module: {
		loaders: [
			{ test: /\.csv?$/, loader: 'dsv-loader' },
			{ test: /\.json$/, loader: 'json-loader' },
			{ test: /\.js$/,   loader: 'babel', exclude: /node_modules/ }
		]
	}
};

gulp.task('js-dev', function() {

	config.plugins = [];

	return gulp.src('src/js/main.js')
		.pipe(webpackStream(config))
		.pipe(rename('bundle.js'))
		.pipe(gulp.dest('dist/dev/js'))
		.pipe(browserSync.reload({stream:true}));
});

gulp.task('js-prod', function() {

	config.plugins = [
		new webpack.optimize.UglifyJsPlugin(),
		new webpack.optimize.DedupePlugin()
	];

	return gulp.src('src/js/main.js')
		.pipe(webpackStream(config))
		.pipe(rename('bundle.js'))
		.pipe(gulp.dest('.tmp/js'));
});

var gulp          = require('gulp');
var rename        = require('gulp-rename');
var browserSync   = require('browser-sync');
var webpackStream = require('webpack-stream');
var webpack       = require('webpack');

var config = {
	module: {
		loaders: [
			{ test: /\.csv?$/, loader: 'dsv-loader' },
			{ test: /\.json$/, loader: 'json-loader' },
			{ test: /\.js$/,   loader: 'babel', exclude: /node_modules/ }
		]
	}
};

gulp.task('js-dev', function() {

	config.plugins = [];

	return gulp.src('src/js/main.js')
		.pipe(webpackStream(config))
		.pipe(rename('bundle.js'))
		.pipe(gulp.dest('dist/dev/js'))
		.pipe(browserSync.reload({stream:true}));
});

gulp.task('js-prod', function() {

	config.plugins = [
		new webpack.optimize.UglifyJsPlugin(),
		new webpack.optimize.DedupePlugin()
	];

	return gulp.src('src/js/main.js')
		.pipe(webpackStream(config))
		.pipe(rename('bundle.js'))
		.pipe(gulp.dest('.tmp/js'));
});

Remove redundant call to disable webpack 'watch' mode


(function ($) {

    $(function() {
        /**
         * Adds links to scripture references on song pages.
         */
        $( "div.group-lectionary-scripture-ref" ).wrap(function() {
            return "";
        });
    });

}(jQuery));

(function ($) {

    $(function() {
        /**
         * Adds links to scripture references on song pages.
         */
        $( "div.field-group.field-group-inline.clearfix.group-lectionary-scripture-ref" ).wrap(function() {
            return "";
        });
    });

}(jQuery));

Fix JS for lectionary scripture links.


'use strict';
var _ = require('lodash');

function testProperties(BBY) {
    expect(BBY.options).not.toBe(undefined);
    expect(BBY.options.key).toBe(process.env.BBY_API_KEY);
    expect(BBY.availability instanceof Function).toBe(true);
    expect(BBY.openBox instanceof Function).toBe(true);
    expect(BBY.categories instanceof Function).toBe(true);
    expect(BBY.products instanceof Function).toBe(true);
    expect(BBY.recommendations instanceof Function).toBe(true);
    expect(BBY.reviews instanceof Function).toBe(true);
    expect(BBY.stores instanceof Function).toBe(true);
}

describe('The BBY API module is correctly initialized', function() {
    describe('When using type one initilization', function() {
        var BBY = require('../bestbuy')(process.env.BBY_API_KEY);
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
    describe('When using type two initilization', function() {
        var BBY = require('../bestbuy')({
            'key': process.env.BBY_API_KEY
        });
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
    describe('When using type three initilization', function() {
        var BBY = require('../bestbuy');
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
    describe('When using type three initilization', function() {
        var BBY = require('../bestbuy')();
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
});

'use strict';
var _ = require('lodash');

function testProperties(BBY) {
    expect(BBY.options).not.toBe(undefined);
    expect(BBY.options.key).toBe(process.env.BBY_API_KEY);
    expect(BBY.availability instanceof Function).toBe(true);
    expect(BBY.openBox instanceof Function).toBe(true);
    expect(BBY.categories instanceof Function).toBe(true);
    expect(BBY.products instanceof Function).toBe(true);
    expect(BBY.recommendations instanceof Function).toBe(true);
    expect(BBY.reviews instanceof Function).toBe(true);
    expect(BBY.stores instanceof Function).toBe(true);
}

describe('The BBY API module is correctly initialized', function() {
    describe('When using type one initilization', function() {
        var BBY = require('../bestbuy')(process.env.BBY_API_KEY);
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
    describe('When using type two initilization', function() {
        var BBY = require('../bestbuy')({
            'key': process.env.BBY_API_KEY
        });
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
    describe('When using type three initilization', function() {
        var BBY = require('../bestbuy')();
        it('Has all properties', function(done) {
            testProperties(BBY);
            done();
        });
    });
});

Remove test covering module creation from alpha version


// 'use strict';

var c = require('../lib/channels.js');
var date = require('../lib/date.js');

var events = [];

events.push({
  when: date('W9D4', 13, 40),
  who: c.juniors,
  message: '<!channel> 5 Minutes until Thesis Presentations!'
});

events.push({
  when: date('W9D4', 13, 44),
  who: c.juniors,
  message: '<!channel> 1 Minute until Thesis Presentations!'
});

module.exports = events;

// 'use strict';

var c = require('../lib/channels.js');
var date = require('../lib/date.js');

var events = [];

events.push({
  when: date('W9D4', 13, 40),
  who: c.seniors,
  message: '<!channel> 5 Minutes until Thesis Presentations!'
});

events.push({
  when: date('W9D4', 13, 44),
  who: c.seniors,
  message: '<!channel> 1 Minute until Thesis Presentations!'
});

module.exports = events;

Switch juniors to seniors for w9d4


import {createStore, combineReducers, applyMiddleware} from 'rx-redux'
import thunkMiddleware from 'redux-thunk'
import * as reducers from './reducers'
import { render, getActionStream } from './view'

const action$ = getActionStream();

const newCreateStore = applyMiddleware(thunkMiddleware)(createStore);
const reducer = combineReducers(reducers);
const store = newCreateStore(reducer);

// set view to initial state
render(store.getState());

// stream states to view
store.state$.subscribe(state => render(state));

// stream actions to dispatcher
action$.subscribe(action => store.dispatcher$.onNext(action));

import {createStore, combineReducers, applyMiddleware} from 'rx-redux'
import thunkMiddleware from 'redux-thunk'
import * as reducers from './reducers'
import { render, getActionStream } from './view'

const action$ = getActionStream();

const newCreateStore = applyMiddleware(thunkMiddleware)(createStore);
const reducer = combineReducers(reducers);
const store = newCreateStore(reducer);

// stream states to view
store.state$.startWith(store.getState()).subscribe(state => render(state));

// stream actions to dispatcher
action$.subscribe(action => store.dispatcher$.onNext(action));

Simplify for an initial state.


#!/usr/bin/env node
var q = require('q');
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var xml2js = require('xml2js');
var del = require('del');

module.exports = function(context) {
  var deferral = q.defer();
  var parser = new xml2js.Parser();

  fs.readFile('config.xml', 'utf8', function (err, xml) {
    if (err) {
      deferral.reject('Unable to load config.xml');

      return;
    }
    parser.parseString(xml, function (err, config) {
      if (err) {
        deferral.reject('Unable to parse config.xml');

        return;
      }
      if (config.widget === undefined || config.widget['ignore-files'] === undefined) {
        return;
      }
      var ignoreFiles = config.widget['ignore-files'];

      for (var i = 0, l = ignoreFiles.length; i < l; ++i) {
        if (ignoreFiles[i].$ === undefined || ignoreFiles[i].$.ignore === undefined) {
          continue;
        }
        glob(ignoreFiles[i].$.ignore, {}, function (er, files) {
          for (var i = 0, l = files.length; i < l; ++i) {
            del.deleteSync(files[i]);

            console.log('ignore-files.js: File `' + files[i] + '` ignored.');
          }
        })
      }
      deferral.resolve();
    });
  });

  return deferral.promise;
};

#!/usr/bin/env node
import q from 'q';
import fs from 'fs';
import path from 'path';
import glob from 'glob';
import xml2js from 'xml2js';
import {deleteSync} from 'del';

module.exports = function(context) {
  var deferral = q.defer();
  var parser = new xml2js.Parser();

  fs.readFile('config.xml', 'utf8', function (err, xml) {
    if (err) {
      deferral.reject('Unable to load config.xml');

      return;
    }
    parser.parseString(xml, function (err, config) {
      if (err) {
        deferral.reject('Unable to parse config.xml');

        return;
      }
      if (config.widget === undefined || config.widget['ignore-files'] === undefined) {
        return;
      }
      var ignoreFiles = config.widget['ignore-files'];

      for (var i = 0, l = ignoreFiles.length; i < l; ++i) {
        if (ignoreFiles[i].$ === undefined || ignoreFiles[i].$.ignore === undefined) {
          continue;
        }
        glob(ignoreFiles[i].$.ignore, {}, function (er, files) {
          for (var i = 0, l = files.length; i < l; ++i) {
            deleteSync(files[i]);

            console.log('ignore-files.js: File `' + files[i] + '` ignored.');
          }
        })
      }
      deferral.resolve();
    });
  });

  return deferral.promise;
};

Use import instead of require


self.addEventListener( 'install', function( e ) {
	// hey
} );

async function networkOrCache(event) {
	try {
		const response = await fetch(event.request);

		if (response.ok) {
			const cache = await caches.open('steamstatus');
			await cache.put(event.request, response.clone());
			return response;
		}

		throw new Error(`Request failed with HTTP ${response.status}`);
	} catch (e) {
		// eslint-disable-next-line no-console
		console.error(e.message, event.request.url);

		const cache = await caches.open('steamstatus');
		const matching = await cache.match(event.request);

		return matching || Promise.reject(new Error('Request not in cache'));
	}
}

self.addEventListener('fetch', (event) => {
	if (event.request.method !== 'GET') {
		return;
	}

	if (!event.request.url.startsWith(self.registration.scope)) {
		return;
	}

	event.respondWith(networkOrCache(event));
});

Update service worker to fallback to cache


'use strict';

var fs      = require('fs');
var path    = require('path');
var jsdom   = require('jsdom').jsdom;
var utility = require('../utility');
var glob    = require('glob');

describe('browser build', function() {
  before(function(done) {
    // Will match both `highlight.pack.js` and `highlight.min.js`
    var hljsPath = glob.sync(utility.buildPath('..', 'build', 'highlight.*.js'));
    var that     = this;

    jsdom.env(
      '
' +
      'var say = "Hello";' +
      'class Car {}' +
      '
',
      [hljsPath[0]],
      function(error, window) {
        that.block = window.document.querySelector('pre code');
        that.hljs  = window.hljs;

        done(error);
      }
    );
  });

  it('should highlight block', function() {
    this.hljs.highlightBlock(this.block);

    var actual = this.block.innerHTML;

    actual.should.equal(
      'var say = "Hello";' +
      'class Car {}'
    );
  });
});

'use strict';

var bluebird = require('bluebird');
var fs       = require('fs');
var path     = require('path');
var jsdom    = require('jsdom');
var utility  = require('../utility');
var glob     = bluebird.promisify(require('glob'));

describe('browser build', function() {
  before(function(done) {
    var that = this;
    var html = '
var say = "Hello";class Car {}
';

    // Will match both `highlight.pack.js` and `highlight.min.js`
    var filepath = utility.buildPath('..', 'build', 'highlight.*.js');

    glob(filepath)
      .then(function(hljsPath) {
        return bluebird.fromNode(function(callback) {
          jsdom.env(html, [hljsPath[0]], callback);
        });
      })
      .then(function(window) {
        that.block = window.document.querySelector('pre code');
        that.hljs  = window.hljs;
      })
      .then(function() { done(); },
            function(error) { done(error); });
  });

  it('should highlight block', function() {
    this.hljs.highlightBlock(this.block);

    var actual = this.block.innerHTML;

    actual.should.equal(
      'var say = "Hello";' +
      'class Car {}'
    );
  });
});

Use promises for both glob and jsdom.env


const { applyFieldDescriptor, createFieldDescriptor } = require("./fields.js");

class EntryFacade {

    constructor(entry) {
        this._entry = entry;
    }

    get entry() {
        return entry;
    }

    get fields() {
        return [
            createFieldDescriptor(
                this.entry,
                "Username",
                "property",
                "username"
            ),
            createFieldDescriptor(
                this.entry,
                "Password",
                "property",
                "password",
                { protected: true }
            )
        ];
    }

    get title() {
        return this.entry.getProperty("title");
    }

    get type() {
        return "";
    }

    consumeInputHarness(harness) {
        if (harness && harness.type) {
            (harness.fields || []).forEach(field => applyFieldDescriptor(field));
        } else {
            throw new Error("Invalid item passed as a harness");
        }
    }

    generateInputHarness() {
        return {
            type: this.type,
            fields: this.fields
        };
    }

}

module.exports = EntryFacade;

const { applyFieldDescriptor, createFieldDescriptor } = require("./fields.js");

class EntryFacade {

    constructor(entry) {
        this._entry = entry;
    }

    get entry() {
        return entry;
    }

    get fields() {
        return [
            createFieldDescriptor(
                this.entry,
                "Username",
                "property",
                "username"
            ),
            createFieldDescriptor(
                this.entry,
                "Password",
                "property",
                "password",
                { protected: true }
            )
        ];
    }

    get title() {
        return this.entry.getProperty("title");
    }

    get type() {
        return "";
    }

    consumeInputHarness(harness) {
        if (harness && harness.type) {
            if (harness.type !== this.type) {
                throw new Error(`Failed consuming entry data: Expected type "${this.type}" but received "${harness.type}"`);
            }
            (harness.fields || []).forEach(field => applyFieldDescriptor(field));
        } else {
            throw new Error("Failed consuming entry data: Invalid item passed as a harness");
        }
    }

    generateInputHarness() {
        return {
            type: this.type,
            fields: this.fields
        };
    }

}

module.exports = EntryFacade;

Add error for invalid harness type


import Paddle from 'props/paddle';
import canvas from 'canvas';

export default class Ai extends Paddle {
  constructor(ball) {
    super(canvas.width - 15, ball.y);
    this.ball = ball;
    this.speed = 3;
  }

  move() {
    const centerBallPoint = this.ball.y - (this.ball.height / 2);
    const distanceToBall = centerBallPoint - this.y;
    const speed = distanceToBall > 0 ? this.speed : -(this.speed);

    return super.move(distanceToBall < speed ? distanceToBall : speed);
  }
}

import Paddle from 'props/paddle';
import canvas from 'canvas';

export default class Ai extends Paddle {
  constructor(ball) {
    super(canvas.width - 15, ball.y);
    this.ball = ball;
    this.speed = 3;
  }

  move() {
    const centerPaddlePoint = this.y + (this.height / 2);
    const centerBallPoint = this.ball.y + (this.ball.height / 2);

    const distanceToBall = centerBallPoint - centerPaddlePoint;
    const speed = distanceToBall > 0 ? this.speed : -(this.speed);

    return super.move(distanceToBall < speed ? distanceToBall : speed);
  }
}

Fix Ai where it wasn't targeting the center of paddle on ball follow


import React from 'react';
import PropTypes from 'prop-types';
import { c } from 'ttag';
import { Modal, ContentModal, FooterModal, ResetButton } from 'react-components';

import AddressesTable from './AddressesTable';

const CatchAllModal = ({ domain, show, onClose }) => {
    return (
        <Modal modalClassName="pm-modal--small" show={show} onClose={onClose} title={c('Title').t`Catch all address`}>
            <ContentModal onReset={onClose}>
                <AddressesTable domain={domain} />
                <FooterModal>
                    <ResetButton>{c('Action').t`Close`}</ResetButton>
                </FooterModal>
            </ContentModal>
        </Modal>
    );
};

CatchAllModal.propTypes = {
    show: PropTypes.bool.isRequired,
    onClose: PropTypes.func.isRequired,
    domain: PropTypes.object.isRequired
};

export default CatchAllModal;

import React from 'react';
import PropTypes from 'prop-types';
import { c } from 'ttag';
import { Modal, ContentModal, FooterModal, ResetButton } from 'react-components';

import AddressesTable from './AddressesTable';

const CatchAllModal = ({ domain, show, onClose }) => {
    return (
        <Modal modalClassName="pm-modal--smaller" show={show} onClose={onClose} title={c('Title').t`Catch all address`}>
            <ContentModal onReset={onClose}>
                <AddressesTable domain={domain} />
                <FooterModal>
                    <ResetButton>{c('Action').t`Close`}</ResetButton>
                </FooterModal>
            </ContentModal>
        </Modal>
    );
};

CatchAllModal.propTypes = {
    show: PropTypes.bool.isRequired,
    onClose: PropTypes.func.isRequired,
    domain: PropTypes.object.isRequired
};

export default CatchAllModal;

Set small modal for catch all


var MONTH_MAPPING = {
  "1": "January",
  "2": "February",
  "3": "March",
  "4": "April",
  "5": "May",
  "6": "June",
  "7": "July",
  "8": "August",
  "9": "September",
  "19": "October",
  "11": "November",
  "12": "December"
};

var util = {};

util.formatDate = function (pubDate) {
  var parts = pubDate.split("-");
  if (pubDate.split("-").length >= 3) {
    var localDate = new Date(pubDate);
    return localDate.toUTCString().slice(0, 16)
  } else {
    var month = parts[1].replace("0", "");
    var year = parts[0];
    return MONTH_MAPPING[month]+" "+year;
  }
}

module.exports = util;

var MONTH_MAPPING = {
  "1": "January",
  "2": "February",
  "3": "March",
  "4": "April",
  "5": "May",
  "6": "June",
  "7": "July",
  "8": "August",
  "9": "September",
  "19": "October",
  "11": "November",
  "12": "December"
};

var util = {};

util.formatDate = function (pubDate) {
  var parts = pubDate.split("-");
  if (pubDate.split("-").length >= 3) {
    // new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
    // Note: months are 0-based
    var localDate = new Date(parts[0], parts[1]-1, parts[2]);
    return localDate.toUTCString().slice(0, 16);
  } else {
    var month = parts[1].replace("0", "");
    var year = parts[0];
    return MONTH_MAPPING[month]+" "+year;
  }
};

module.exports = util;

Fix date parsing: use explicit constructor instead of dash format.


var buster = require('buster')

var forOwn = require('mout/object/forOwn')
var conversion = require('./utility/conversion')

var temperature = require('../api/temperature')
var temperatureDefinition = require('../definition/_temperature')

// Load all definitions
require('../definition/temperature')

var assert = buster.assert
var refute = buster.refute
var testCase = buster.testCase

// augment distance unit constructor
;
(function() {
    forOwn(temperatureDefinition._defs, function(def, name) {
        temperature.augment(name)
    })
})()

testCase('temperature', {
    setUp: function() {},

    'is a function': function() {
        assert.isFunction(temperature)
    },

    'returns an object': function() {
        assert.isObject(temperature())
    },

    'contains definitions': function() {
        var definitions = temperature().definitions

        assert.defined(definitions._defs.kelvin)
        assert.defined(definitions._defs.celsius)
    },

    'convert': {
        setUp: function() {
            this.converter = temperature
        },

        'celsius': conversion(temperatureDefinition, 'celsius'),

        'delisle': conversion(temperatureDefinition, 'delisle'),

        'fahrenheit': conversion(temperatureDefinition, 'fahrenheit'),

        'kelvin': conversion(temperatureDefinition, 'kelvin'),

        'newton': conversion(temperatureDefinition, 'newton'),

        'rankine': conversion(temperatureDefinition, 'rankine'),

        'reaumur': conversion(temperatureDefinition, 'reaumur'),

        'romer': conversion(temperatureDefinition, 'romer')
    }
})

var buster = require('buster')

var forOwn = require('mout/object/forOwn')
var conversion = require('./utility/conversion')

var temperature = require('../temperature')
var temperatureDefinition = require('../definition/_temperature')

var assert = buster.assert
var refute = buster.refute
var testCase = buster.testCase

testCase('temperature', {
    setUp: function() {},

    'is a function': function() {
        assert.isFunction(temperature)
    },

    'returns an object': function() {
        assert.isObject(temperature())
    },

    'contains definitions': function() {
        var definitions = temperature().definitions

        assert.defined(definitions._defs.kelvin)
        assert.defined(definitions._defs.celsius)
    },

    'convert': {
        setUp: function() {
            this.converter = temperature
        },

        'celsius': conversion(temperatureDefinition, 'celsius'),

        'delisle': conversion(temperatureDefinition, 'delisle'),

        'fahrenheit': conversion(temperatureDefinition, 'fahrenheit'),

        'kelvin': conversion(temperatureDefinition, 'kelvin'),

        'newton': conversion(temperatureDefinition, 'newton'),

        'rankine': conversion(temperatureDefinition, 'rankine'),

        'reaumur': conversion(temperatureDefinition, 'reaumur'),

        'romer': conversion(temperatureDefinition, 'romer')
    }
})

Update temperature tests to test api.


// home.js

"use strict";

import { welcome } from "../welcome/welcome";

if (NODE_ENV == DEV_ENV) {
  welcome("home");
  console.log(NODE_ENV);
}

require.ensure(["../loadVendors/loadVendors"], (require) => {
  let vendors = require("../loadVendors/loadVendors");

  vendors.loadVendors();
});

export { welcome };

// home.js

"use strict";

import { welcome } from "../welcome/welcome";
import angular from "angular";

if (NODE_ENV == DEV_ENV) {
  welcome("home");
  console.log(NODE_ENV);
}

require.ensure(["../loadVendors/loadVendors"], (require) => {
  let vendors = require("../loadVendors/loadVendors");

  vendors.loadVendors();
});

export { welcome };

Add import angular from "angular";


import { shim as shimFind } from 'array.prototype.find';
import { enable as enableRejectionTracking } from 'promise/lib/rejection-tracking';
import * as Sentry from '@sentry/browser';

shimFind();

const isProduction = process.env.NODE_ENV === 'production';

if (isProduction) {
  Sentry.init({
    dsn: 'https://cfcb0c4bb8cb4264942f80ca1eb78c49@sentry.io/146907',
    environment: process.env.NODE_ENV,
  });

  // Rejection tracking prevents a common issue where React gets into an
  // inconsistent state due to an error, but it gets swallowed by a Promise,
  // and the user has no idea what causes React's erratic future behavior.
  enableRejectionTracking({
    onUnhandled: (id, error) => {
      if (isProduction) {
        Sentry.captureException(error);
      }
    },
  });
}

/* eslint-disable no-extend-native */
if (!String.prototype.startsWith) {
  String.prototype.startsWith = (search, pos) =>
    this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
}

import { shim as shimFind } from 'array.prototype.find';
import { enable as enableRejectionTracking } from 'promise/lib/rejection-tracking';
import * as Sentry from '@sentry/browser';

shimFind();

const isProduction = process.env.NODE_ENV === 'production';

if (isProduction) {
  Sentry.init({
    dsn: 'https://cfcb0c4bb8cb4264942f80ca1eb78c49@sentry.io/146907',
    environment: process.env.NODE_ENV,
    sampleRate: 1.0,
  });

  // Rejection tracking prevents a common issue where React gets into an
  // inconsistent state due to an error, but it gets swallowed by a Promise,
  // and the user has no idea what causes React's erratic future behavior.
  enableRejectionTracking({
    onUnhandled: (id, error) => {
      if (isProduction) {
        Sentry.captureException(error);
      }
    },
  });
}

/* eslint-disable no-extend-native */
if (!String.prototype.startsWith) {
  String.prototype.startsWith = (search, pos) =>
    this.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
}

Set Sentry sample rate to 1.0


/**
 * @constructor
 */
gecui.MainMenuPanel = function(config) {

	var root = new Ext.tree.TreeNode( {
		text : 'Geoserver'
	});

	var tree = new Ext.tree.TreePanel( {
		root : root,
		rootVisible : false,
		border : false
	});

	var serverNode = new Ext.tree.TreeNode( {
		text : 'Server'
	});

	var servicesNode = new Ext.tree.TreeNode( {
		text : 'Services'
	});

	var workspacesNode = new gecui.tree.WorkspacesNode();

	root.appendChild( [ serverNode, servicesNode, workspacesNode ]);

	var items = [ tree ];

	gecui.MainMenuPanel.superclass.constructor.call(this, Ext.apply( {
		border: false,
		items : items
	}, config));
};

Ext.extend(gecui.MainMenuPanel, Ext.Panel);

Ext.reg('gecui-mainmenu', gecui.MainMenuPanel);

/**
 * @constructor
 */
gecui.MainMenuPanel = function(config) {

	var root = new Ext.tree.TreeNode( {
		text : 'Geoserver'
	});

	var tree = new Ext.tree.TreePanel( {
		root : root,
		rootVisible : false,
		border : false
	});

	var serverNode = new Ext.tree.TreeNode( {
		text : 'Server'
	});

	var servicesNode = new Ext.tree.TreeNode( {
		text : 'Services'
	});

	var workspacesNode = new gecui.tree.WorkspacesNode( {
		expanded : true
	});

	root.appendChild( [ serverNode, servicesNode, workspacesNode ]);

	var items = [ tree ];

	gecui.MainMenuPanel.superclass.constructor.call(this, Ext.apply( {
		border : false,
		items : items
	}, config));
};

Ext.extend(gecui.MainMenuPanel, Ext.Panel);

Ext.reg('gecui-mainmenu', gecui.MainMenuPanel);

Set workspaces node to default as expanded.


/* global exports */
"use strict";

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

// module Docopt.FFI

/**
 * Try and detect the version as indicated in the package.json neighbouring
 * the main module. Uses `require.main` to detect the main module and traverses
 * the parent directories in a search for a `package.json` using
 * `require.main.paths`.
 */

exports.readPkgVersionImpl = function (Just) {
  return function(Nothing) {
    return function() {
      if (!require.main) {
        return Nothing;
      } else {
        for (var i=0; i < require.main.paths.length; i++) {
          var xs = require.main.paths[i].split(path.sep);
          if (xs.pop() === 'node_modules' && xs.length > 1) {
            xs.push('package.json');
            var p = xs.join(path.sep);
            if (fs.existsSync(p)) {
              return Just(JSON.parse(fs.readFileSync(p)).version);
            }
          }
        }
        return Nothing;
      }
    }
  }
};

/* global exports */
"use strict";

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

// module Docopt.FFI

/**
 * Try and detect the version as indicated in the package.json neighbouring
 * the main module. Uses `require.main` to detect the main module and traverses
 * the parent directories in a search for a `package.json` using
 * `require.main.paths`.
 */

exports.readPkgVersionImpl = function (Just) {
  return function(Nothing) {
    return function() {
      if (!require.main) {
        return Nothing;
      } else if (require.main && require.main.paths /* in node? */){
        for (var i=0; i < require.main.paths.length; i++) {
          var xs = require.main.paths[i].split(path.sep);
          if (xs.pop() === 'node_modules' && xs.length > 1) {
            xs.push('package.json');
            var p = xs.join(path.sep);
            if (fs.existsSync(p)) {
              return Just(JSON.parse(fs.readFileSync(p)).version);
            }
          }
        }
        return Nothing;
      }
      return Nothing;
    }
  }
};

Fix version resolve in browser - check if in node


import Item, { MovingDirection, ItemType } from './Item'
import Ball from './Ball'
import ItemLoader from '../Loader/ItemLoader'

export default class Platform extends Item {
  constructor(width, height, color) {
    super(
      [500 - (width / 2), 500 - height - 10],
      [width, height],
      color,
      ItemType.PLATFORM,
    )
  }

  unbindBall() {
    for (let i = 0; i < this.boundItems.length; i += 1) {
      if (this.boundItems[i] instanceof Ball) {
        const prevBoundPosition = this.boundItems[i].getPosition()
        const prevColor = this.boundItems[i].getColor()
        const prevWidth = this.boundItems[i].getWidth()
        this.detachItem(this.boundItems[i])
        const detachedBall = new Ball(prevWidth, prevColor, prevBoundPosition)
        detachedBall.setSpeed([3, 4])
        detachedBall.setDirection([MovingDirection.LEFT, MovingDirection.UP])
        ItemLoader.addItem(detachedBall)
        ItemLoader.addMovingItem(detachedBall)
      }
    }
  }
}

import Item, { MovingDirection, ItemType } from './Item'
import Ball from './Ball'
import ItemLoader from '../Loader/ItemLoader'
import Helper from '../Utility/Utility'

export default class Platform extends Item {
  constructor(width, height, color) {
    super(
      [500 - (width / 2), 500 - height - 10],
      [width, height],
      color,
      ItemType.PLATFORM,
    )
  }

  unbindBall() {
    for (let i = 0; i < this.boundItems.length; i += 1) {
      if (this.boundItems[i] instanceof Ball) {
        const prevBoundPosition = this.boundItems[i].getPosition()
        const prevColor = this.boundItems[i].getColor()
        const prevWidth = this.boundItems[i].getWidth()
        this.detachItem(this.boundItems[i])
        const detachedBall = new Ball(prevWidth, prevColor, prevBoundPosition)
        const xDirections = [MovingDirection.LEFT, MovingDirection.RIGHT]
        const randomXDirection = xDirections[Math.floor(Math.random() * xDirections.length)]
        const randomSpeed = () => Helper.randomIntFromInterval(1, 8)
        detachedBall.setSpeed([0, randomSpeed()])
        detachedBall.setDirection([randomXDirection, MovingDirection.UP])
        ItemLoader.addItem(detachedBall)
        ItemLoader.addMovingItem(detachedBall)
      }
    }
  }
}

Add random ball start angle


angular.module('omniControllers')
	.controller('WalletHistoryController', ["$scope", "$q", "$http", "hashExplorer", "$translate",
		function WalletHistoryController($scope, $q, $http, hashExplorer, $translate) {
		    $scope.setHashExplorer = hashExplorer.setHash.bind(hashExplorer);
  			$scope.showtesteco = $scope.account.getSetting('showtesteco');
  			$scope.history = $scope.wallet.transactions($scope.showtesteco);

		    $scope.changeAddress=function(address){
			  	if(address){
			  		$scope.selectedAddress = address;
			  		$scope.history = address.transactions.filter(function(tx){
				        return ((tx.currency.propertyid < 2147483648 && tx.currency.propertyid != 2) || $scope.showtesteco === 'true');
				    });
			  	} else {
			  		$scope.selectedAddress = undefined;
			  		$scope.history = $scope.wallet.transactions($scope.showtesteco);

			  	}
		    }
		}])

angular.module('omniControllers')
	.controller('WalletHistoryController', ["$scope", "$q", "$http", "hashExplorer", "$translate",
		function WalletHistoryController($scope, $q, $http, hashExplorer, $translate) {
  			$scope.showtesteco = $scope.account.getSetting('showtesteco');
  			$scope.history = $scope.wallet.transactions($scope.showtesteco);

		    $scope.changeAddress=function(address){
			  	if(address){
			  		$scope.selectedAddress = address;
			  		$scope.history = address.transactions.filter(function(tx){
				        return ((tx.currency.propertyid < 2147483648 && tx.currency.propertyid != 2) || $scope.showtesteco === 'true');
				    });
			  	} else {
			  		$scope.selectedAddress = undefined;
			  		$scope.history = $scope.wallet.transactions($scope.showtesteco);

			  	}
		    }

		    $scope.setHashExplorer=function(transaction){
		    	$http.get('/v1/transaction/tx/' + transaction.hash + '.json'). success(function(data) {
			      hashExplorer.setHash(data[0]);
			    });
		    }
		}])

Set the transaction for the hash explorer in history page details


angular.module('ui.knob', [])
  .directive('knob', function () {
    return {
      restrict: 'EACM',
      template: function(elem, attrs){

        return '<input value="{{ knob }}">';

      },
      replace: true,
      scope: true,
      link: function (scope, elem, attrs) {

        scope.knob = scope.$eval(attrs.knobData);

        var renderKnob = function(){

          scope.knob = scope.$eval(attrs.knobData);

          var opts = {};
          if(!angular.isUndefined(attrs.knobOptions)){
            opts = scope.$eval(attrs.knobOptions);
          }

          if(!angular.isUndefined(attrs.knobMax)){
            var max = scope.$eval(attrs.knobMax);
            if(!angular.isUndefined(max)){

              opts.max = max;

            }
          }

          $elem = $(elem);
          $elem.val(scope.knob);
          $elem.change();
          $elem.knob(opts);

        };

        scope.$watch(attrs.knobData, function () {
           renderKnob();
        });

        scope.$watch(attrs.knobOptions, function () {
          renderKnob();
        }, true);

      }
    };
  });

angular.module('ui.knob', [])
  .directive('knob', function () {
    return {
      restrict: 'EACM',
      template: function(elem, attrs){

        return '<input value="{{ knob }}">';

      },
      replace: true,
      scope: true,
      link: function (scope, elem, attrs) {

        scope.knob = scope.$eval(attrs.knobData);

        var renderKnob = function(){

          scope.knob = scope.$eval(attrs.knobData);

          var opts = {};
          if(!angular.isUndefined(attrs.knobOptions)){
            opts = scope.$eval(attrs.knobOptions);
          }

          if(!angular.isUndefined(attrs.knobMax)){
            var max = scope.$eval(attrs.knobMax);
            if(!angular.isUndefined(max)){

              opts.max = max;

            }
          }

          $elem = $(elem);
          $elem.val(scope.knob);
          $elem.change();
          $elem.knob(opts);

        };

        var updateMax = function updateMax() {
          var max = scope.$eval(attrs.knobMax);
          var val = scope.$eval(attrs.knobData);
          $elem = $(elem);
          $elem.trigger('configure', {
            'max': parseInt(max)
          }).trigger('change');
          $elem.val(val);
          $elem.change();
        }

        scope.$watch(attrs.knobData, function () {
           renderKnob();
        });

        scope.$watch(attrs.knobMax, function() {
          updateMax();
        });

        scope.$watch(attrs.knobOptions, function () {
          renderKnob();
        }, true);

      }
    };
  });

Fix for refreshing the max amount of the knob when the max value its bound to is changed


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

class ModuleFulfillmentCollection extends Mongo.Collection {}

const ModuleFulfillments = new ModuleFulfillmentCollection("modfulfillment");

/** Schema for the
  * Object in the module Fulfillments
  * [{acadYear:,
      areaFulfilled:},
  *  {acadYear:,
      areaFulfilled:}]
  */

const fulfillmentSchema = {
  moduleCode: {
    type: String
  },
  moduleMapping: {
    type: [object]
  }
}

ModuleFulfillments.attachSchema(fulfillmentSchema);

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

class ModuleFulfillmentCollection extends Mongo.Collection {}

const ModuleFulfillments = new ModuleFulfillmentCollection("modfulfillment");

/** Schema for the
  * Object in the module Fulfillments
  * [{acadYear:,
      areaFulfilled:},
  *  {acadYear:,
      areaFulfilled:}]
  */
const moduleMappingSchema = {
  acadYear: {
    type: string,
    optional: false
  },
  areaFulfilled: {
    type: string,
    optional: false
  },
  moduleEquivalent: {
    type: [string],
    optional: true
  }
};
const fulfillmentSchema = {
  moduleCode: {
    type: String
  },
  moduleMapping: {
    type: [moduleMappingSchema],
    blackbox: true
  }
};

ModuleFulfillments.attachSchema(fulfillmentSchema);

UPDATE modFulfillment schema with mapping schema


// urlmaker.js
//
// URLs just like Mama used to make
//
// Copyright 2011-2012, E14N https://e14n.com/
//
// 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 url = require("url"),
    querystring = require("querystring");

var URLMaker = {
    hostname: null,
    port: 80,
    makeURL: function(relative, params) {
        var obj = {
            protocol: (this.port === 443) ? "https:" : "http:",
            hostname: this.hostname,
            pathname: relative
        };
        if (!this.hostname) {
            throw new Error("No hostname");
        }
        if (this.port !== 80 && this.port !== 443) {
            obj.port = this.port;
        }
        if (params) {
            obj.search = querystring.stringify(params);
        }
        return url.format(obj);
    }
};

exports.URLMaker = URLMaker;

// urlmaker.js
//
// URLs just like Mama used to make
//
// Copyright 2011-2012, E14N https://e14n.com/
//
// 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 url = require("url"),
    querystring = require("querystring");

var URLMaker = {
    hostname: null,
    port: 80,
    path: null,
    makeURL: function(relative, params) {
        var obj = {
            protocol: (this.port === 443) ? "https:" : "http:",
            hostname: this.hostname,
            pathname: (this.path) ? this.path + "/" + relative : relative
        };
        if (!this.hostname) {
            throw new Error("No hostname");
        }
        if (this.port !== 80 && this.port !== 443) {
            obj.port = this.port;
        }
        if (params) {
            obj.search = querystring.stringify(params);
        }
        return url.format(obj);
    }
};

exports.URLMaker = URLMaker;

Allow a path prefix in URLMaker


'use strict';

const uuid = require('uuid');
const cls = require('cls-hooked');

const store = cls.createNamespace('1d0e0c48-3375-46bc-b9ae-95c63b58938e');

module.exports = {
  withId: configureArgs(withId),
  bindId: configureArgs(bindId),
  getId
};

function withId (id, work) {
  store.run(() => {
    store.set('correlator', id);
    work();
  });
}

function bindId (id, work) {
  return function () {
    store.run(() => {
      store.set('correlator', id);
      work.apply(null, [].slice.call(arguments));
    });
  };
}

function configureArgs (func) {
  return (id, work) => {
    if (!work && isFunction(id)) {
      work = id;
      id = uuid.v4();
    }
    if (!work) throw new Error('Missing work parameter');

    return func(id, work);
  };
}

function isFunction (object) {
  return typeof object === 'function';
}

function getId () {
  return store.get('correlator');
}

'use strict';

const uuid = require('uuid');
const cls = require('cls-hooked');

const store = cls.createNamespace('1d0e0c48-3375-46bc-b9ae-95c63b58938e');

module.exports = {
  withId: configureArgs(withId),
  bindId: configureArgs(bindId),
  getId
};

function withId (id, work) {
  return store.runAndReturn(() => {
    store.set('correlator', id);
    return work();
  });
}

function bindId (id, work) {
  return function () {
    store.run(() => {
      store.set('correlator', id);
      work.apply(null, [].slice.call(arguments));
    });
  };
}

function configureArgs (func) {
  return (id, work) => {
    if (!work && isFunction(id)) {
      work = id;
      id = uuid.v4();
    }
    if (!work) throw new Error('Missing work parameter');

    return func(id, work);
  };
}

function isFunction (object) {
  return typeof object === 'function';
}

function getId () {
  return store.get('correlator');
}

Use runAndReturn to get result of function executed inside withId


var postcss = require('postcss'),
    extend = require('extend');

module.exports = postcss.plugin('postcss-default-unit', function (opts) {
    opts = opts || {};
    opts.unit = opts.unit || 'px';
    opts.ignore = extend({
      'column-count': true,
      'fill-opacity': true,
      'font-weight':  true,
      'line-height':  true,
      'opacity':      true,
      'orphans':      true,
      'widows':       true,
      'z-index':      true,
      'zoom':         true,
      'flex':         true,
      'order':        true,
      'flex-grow':    true,
      'flex-shrink':  true
    }, opts.ignore);

    function transformDecl(decl) {
        if (!opts.ignore[decl.prop] && !/\w\(.*\)/.test(decl.value)) {
            decl.value = decl.value.replace(/\d+(\s|\/|$)/g, function(match){
                return parseInt(match) === 0 ? match : match.replace(/\d+/, '$&' + opts.unit);
            });
        }
    }

    function transformRule(rule) {
        if (rule.name === 'media') {
            rule.params = rule.params.replace(/(height|width|resolution)\s*:\s*\d+\)/g, function(match){
                return match.replace(/\d+/, '$&' + opts.unit);
            });
        }
    }

    function defaultUnit(style) {
        style.eachDecl(transformDecl);
        style.eachAtRule(transformRule);
    }

    return defaultUnit;
});

var postcss = require('postcss'),
    extend = require('extend');

module.exports = postcss.plugin('postcss-default-unit', function (opts) {
    opts = opts || {};
    opts.unit = opts.unit || 'px';
    opts.ignore = extend({
      'columns':      true,
      'column-count': true,
      'fill-opacity': true,
      'font-weight':  true,
      'line-height':  true,
      'opacity':      true,
      'orphans':      true,
      'widows':       true,
      'z-index':      true,
      'zoom':         true,
      'flex':         true,
      'order':        true,
      'flex-grow':    true,
      'flex-shrink':  true
    }, opts.ignore);

    function transformDecl(decl) {
        if (!opts.ignore[decl.prop] && !/\w\(.*\)/.test(decl.value)) {
            decl.value = decl.value.replace(/\d+(\s|\/|$)/g, function(match){
                return parseInt(match) === 0 ? match : match.replace(/\d+/, '$&' + opts.unit);
            });
        }
    }

    function transformRule(rule) {
        if (rule.name === 'media') {
            rule.params = rule.params.replace(/(height|width|resolution)\s*:\s*\d+\)/g, function(match){
                return match.replace(/\d+/, '$&' + opts.unit);
            });
        }
    }

    function defaultUnit(style) {
        style.eachDecl(transformDecl);
        style.eachAtRule(transformRule);
    }

    return defaultUnit;
});

Add `columns` to the ignore list


var Gigasecond = require('./gigasecond');

describe('Gigasecond', function() {

  it('test 1', function() {
    var gs = new Gigasecond(new Date(2011, 3, 25));
    var expectedDate = new Date(2043, 0, 1);
    expect(gs.date()).toEqual(expectedDate);
  });

  xit('test 2', function() {
    var gs = new Gigasecond(new Date(1977, 5, 13));
    var expectedDate = new Date(2009, 1, 19);
    expect(gs.date()).toEqual(expectedDate);
  });

  xit('test 3', function() {
    var gs = new Gigasecond(new Date(1959, 6, 19));
    var expectedDate = new Date(1991, 2, 27);
    expect(gs.date()).toEqual(expectedDate);
  });

});

var Gigasecond = require('./gigasecond');

describe('Gigasecond', function() {

  it('test 1', function() {
    var gs = new Gigasecond(new Date(2011, 3, 25));
    var expectedDate = new Date(2043, 0, 1);
    expect(gs.date()).toEqual(expectedDate);
  });

  xit('test 2', function() {
    var gs = new Gigasecond(new Date(1977, 5, 13));
    var expectedDate = new Date(2009, 1, 19);
    expect(gs.date()).toEqual(expectedDate);
  });

  xit('test 3', function() {
    var gs = new Gigasecond(new Date(1959, 6, 19));
    var expectedDate = new Date(1991, 2, 27);
    expect(gs.date()).toEqual(expectedDate);
  });

  xit('test 4', function() {
    var gs = new Gigasecond(new Date(1959, 6, 19));
    var expectedDate = new Date(1991, 2, 27);
    gs.date();
    expect(gs.date()).toEqual(expectedDate);
  });
});

Test immutability of the gigasecond


import Ember from 'ember';
const {Component, computed} = Ember;
const {alias} = computed;

export default Component.extend({
  tagName: 'option',
  attributeBindings: ['value', 'selected'],

  option: null,
  labelAttribute: 'label',
  valueAttribute: 'value',

  label: computed('option', 'labelAttribute', function(){
    return this.getOptionValue('labelAttribute');
  }),

  value: computed('option', 'valueAttribute', function(){
    return this.getOptionValue('valueAttribute');
  }),

  getOptionValue(attribute){
    const attributeName = 'option.' + this.get(attribute);
    return this.get(attributeName);
  },

  selected: computed('value', 'currentSelection', function(){
    return this.get('value') === this.get('currentSelection');
  })
});

import Ember from 'ember';
const {Component, computed} = Ember;
const {alias} = computed;

export default Component.extend({
  tagName: 'option',
  attributeBindings: ['value', 'selected'],

  option: null,
  labelAttribute: 'label',
  valueAttribute: 'value',

  label: computed('option', 'labelAttribute', function(){
    return this.getOptionValue('labelAttribute');
  }),

  value: computed('option', 'valueAttribute', function(){
    return this.getOptionValue('valueAttribute');
  }),

  getOptionValue(attribute){
    let attributeName = 'option';
    if (typeof(this.get('option')) === 'object'){
      attributeName += '.' + this.get(attribute);
    }
    return this.get(attributeName);
  },

  selected: computed('value', 'currentSelection', function(){
    return this.get('value') === this.get('currentSelection');
  })
});

Add a check for whether the select option is an object


'use strict';

(function() {
  angular.module('ncsaas')
    .service('cloudsService', ['RawCloud', cloudsService]);

  function cloudsService(RawCloud) {
    /*jshint validthis: true */
    var vm = this;

    vm.getCloudList = getCloudList;
    vm.getCloud = getCloud;

    function getCloudList() {
      return RawCloud.query();
    }

    function getCloud(uuid) {
      return RawCloud.get({cloudUUID: uuid});
    }

  }

})();

(function() {
  angular.module('ncsaas')
    .factory('RawCloud', ['ENV', '$resource', RawCloud]);

    function RawCloud(ENV, $resource) {
      return $resource(ENV.apiEndpoint + 'api/clouds/:cloudUUID/', {cloudUUID:'@uuid'});
    }

})();

'use strict';

(function() {
  angular.module('ncsaas')
    .service('cloudsService', ['RawCloud', 'RawTemplate', cloudsService]);

  function cloudsService(RawCloud, RawTemplate) {
    /*jshint validthis: true */
    var vm = this;

    vm.getCloudList = getCloudList;
    vm.getCloud = getCloud;

    function getCloudList() {
      return RawCloud.query();
    }

    function getCloud(uuid) {
      return RawCloud.get({cloudUUID: uuid});
    }

    function getCloudTemplates(cloudUUID) {
      return RawTemplate.query({cloud: cloudUUID});
    }

  }

})();

(function() {
  angular.module('ncsaas')
    .factory('RawCloud', ['ENV', '$resource', RawCloud]);

    function RawCloud(ENV, $resource) {
      return $resource(ENV.apiEndpoint + 'api/clouds/:cloudUUID/', {cloudUUID:'@uuid'});
    }

})();

// This factory has to be moved to template service if this service will be created
(function() {
  angular.module('ncsaas')
    .factory('RawTemplate', ['ENV', '$resource', RawTemplate]);

    function RawTemplate(ENV, $resource) {
      return $resource(ENV.apiEndpoint + 'api/templates/:templateUUID/', {templateUUID:'@uuid'});
    }

})();

Add GetCloudTemplate method to cloud services (saas-128)


const knex = require('../../../knex').web
const orgUnitFinder = require('../helpers/org-unit-finder')
const orgUnitConstants = require('../../constants/organisation-unit')

module.exports = function (id, type) {
  var orgUnit = orgUnitFinder('name', type)
  var table = 'individual_case_overview'
  var whereClause = ''
  var orderBy = 'ldu_name, team_name'

  if (id !== undefined) {
    whereClause = 'WHERE ' + orgUnit.name + '_id = ' + id
  }

  var selectColumns = [
    'ldu_name AS lduCluster',
    'team_name AS teamName',
    'of_name AS offenderManager',
    'total_cases AS totalCases',
    'available_points AS availablePoints',
    'total_points AS totalPoints',
    'contracted_hours AS contractedHours',
    'reduction_hours AS reductionHours',
    'grade_code AS gradeCode'
  ]

  if (orgUnit.name === orgUnitConstants.REGION.name || orgUnit.name === orgUnitConstants.NATIONAL.name) {
    selectColumns.unshift('region_name AS regionName')
    orderBy = 'region_name,' + orderBy
  }

  return knex.raw(
        'SELECT ' + selectColumns.join(', ') +
        ' FROM ' + table + ' WITH (NOEXPAND)' +
        whereClause + ' ORDER BY ' + orderBy)
    .then(function (results) {
      return results
    })
}

const knex = require('../../../knex').web
const orgUnitFinder = require('../helpers/org-unit-finder')
const orgUnitConstants = require('../../constants/organisation-unit')

module.exports = function (id, type) {
  var orgUnit = orgUnitFinder('name', type)
  var table = 'individual_case_overview'
  var whereClause = ''
  var orderBy = 'lduCluster, teamName'

  if (id !== undefined) {
    whereClause = 'WHERE ' + orgUnit.name + '_id = ' + id
  }

  var selectColumns = [
    'ldu_name AS lduCluster',
    'team_name AS teamName',
    'of_name AS offenderManager',
    'total_cases AS totalCases',
    'available_points AS availablePoints',
    'total_points AS totalPoints',
    'contracted_hours AS contractedHours',
    'reduction_hours AS reductionHours',
    'grade_code AS gradeCode'
  ]

  if (orgUnit.name === orgUnitConstants.REGION.name || orgUnit.name === orgUnitConstants.NATIONAL.name) {
    selectColumns.unshift('region_name AS regionName')
    orderBy = 'regionName,' + orderBy
  }

  return knex.raw(
        'SELECT ' + selectColumns.join(', ') +
        ' FROM ' + table + ' WITH (NOEXPAND)' +
        whereClause + ' ORDER BY ' + orderBy)
    .then(function (results) {
      return results
    })
}

Fix error on view using column alias to order by


import { Class } from 'orbit/lib/objects';
import SchemaUtils from 'orbit-firebase/schema-utils';
import { removeItem } from 'orbit-firebase/array-utils';

export default Class.extend({
	init: function(firebaseClient, schema){
		this._firebaseClient = firebaseClient;
		this._schemaUtils = new SchemaUtils(schema);
	},

	handles: function(operation){
		var path = operation.path;
		if(path[2] !== '__rel') return;
		var linkType = this._schemaUtils.lookupLinkDef(path[0], path[3]).type;
		return operation.op === "add" && linkType === 'hasMany';
	},

	transform: function(operation){
		var path = removeItem(operation.path, '__rel');
		return this._firebaseClient.appendToArray(path, operation.value);
	}
});

import { Class } from 'orbit/lib/objects';
import SchemaUtils from 'orbit-firebase/schema-utils';
import { removeItem } from 'orbit-firebase/array-utils';

export default Class.extend({
	init: function(firebaseClient, schema){
		this._firebaseClient = firebaseClient;
		this._schemaUtils = new SchemaUtils(schema);
	},

	handles: function(operation){
		var path = operation.path;
		if(path[2] !== '__rel') return;
		var linkType = this._schemaUtils.lookupLinkDef(path[0], path[3]).type;
		return operation.op === "add" && linkType === 'hasMany';
	},

	transform: function(operation){
		var path = removeItem(operation.path, '__rel');
		return this._firebaseClient.set(path, operation.value);
	}
});

Correct add to has many


import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

FlowRouter.route('/', {
  name: 'App.home',
  action() {
    this.render('canvas');
  },
});

import { FlowRouter } from 'meteor/ostrio:flow-router-extra';

FlowRouter.route('/*', {
  name: 'App.home',
  action() {
    this.render('canvas');
  },
});

Allow existing history framework to work with flow router


import { createElement, Component, createContext, Fragment } from 'ceviche';
const { Provider, Consumer } = createContext();

class ThemeProvider extends Component {
	state = {
		value: this.props.value
	};

	componentDidMount() {
		setTimeout(() => {
			this.setState({
				value: this.props.next
			});
		}, 3000);
	}

	render() {
		console.log(this.state);
		return <Provider value={this.state.value}>
			{this.props.children}
		</Provider>
	}
}

class Child extends Component {
	shouldComponentUpdate() {
		//return false;
	}

	render() {
		return <>

ok this is cool

			{this.props.children}
		</>
	}
}

export default class extends Component {
  render(props, state) {
    return (
      <ThemeProvider value="blue" next="red">
				<Child>
					<Consumer>
						{data =>
current theme: {data}
}
					</Consumer>
      		<ThemeProvider value="black" next="white">
						<Consumer>
							{data =>
current sub theme: {data}
}
						</Consumer>
					</ThemeProvider>
				</Child>
      </ThemeProvider>
    )
  }
}

import { createElement, Component, createContext, Fragment } from 'ceviche';
const { Provider, Consumer } = createContext();

class ThemeProvider extends Component {
	state = {
		value: this.props.value
	};

	componentDidMount() {
		setTimeout(() => {
			this.setState({
				value: this.props.next
			});
		}, 3000);
	}

	render() {
		console.log(this.state);
		return <Provider value={this.state.value}>
			{this.props.children}
		</Provider>
	}
}

class Child extends Component {
	shouldComponentUpdate() {
		//return false;
	}

	render() {
		return <>

ok this is cool

			{this.props.children}
		</>
	}
}

export default class extends Component {
  render(props, state) {
    return (
      <ThemeProvider value="blue" next="red">
				<Child>
					<Consumer>
						{data => (

current theme: {data}

								<ThemeProvider value="black" next="white">
									<Consumer>
										{data =>
current sub theme: {data}
}
									</Consumer>
								</ThemeProvider>

						)}
					</Consumer>
				</Child>
      </ThemeProvider>
    )
  }
}

Put the nested ThemeProvider inside a parent Consumer (still works!)


module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
  extends: 'standard',
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // add your custom rules here
  'rules': {
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
  },
  'globals': {
    '$': true,
    'jQuery': true,
    'window.jQuery': true
  }
}

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
  extends: 'standard',
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // add your custom rules here
  'rules': {
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    // require or disallow a space before function parenthesis
    'space-before-function-paren': ['error', 'never']
  },
  'globals': {
    '$': true,
    'jQuery': true,
    'window.jQuery': true
  }
}

Remove eslint space before function parenthesis


(function () {
    "use strict";

    function CodeEditorController($scope, localizationService) {

        var vm = this;
        vm.submit = submit;
        vm.close = close;

        vm.aceOption = {};
        vm.aceOption = {
            mode: "razor",
            theme: "chrome",
            showPrintMargin: false,
            autoFocus: true,
            advanced: {
                fontSize: "14px",
                enableSnippets: false, //The Razor mode snippets are awful (Need a way to override these)
                enableBasicAutocompletion: true,
                enableLiveAutocompletion: false
            },
            onLoad: function(aceEditor) {
                vm.aceEditor = aceEditor;
            }
        }

        vm.template = {};
        vm.template.content = $scope.model.content;

        //////////

        function onInit() {

            // set default title
            if(!$scope.model.title) {
                // TODO: localize
                $scope.model.title = "Edit source code";
            }
        }

        function submit(model) {

            // refresh the model
            model.content = vm.aceEditor.getValue();

            if($scope.model.submit) {
                $scope.model.submit(model);
            }
        }

        function close() {
            if($scope.model.close) {
                $scope.model.close();
            }
        }

        onInit();
    }

    angular.module("umbraco").controller("Umbraco.PropertyEditors.RTECodeEditorController", CodeEditorController);

})();

(function () {
    "use strict";

    function CodeEditorController($scope, localizationService) {

        var vm = this;
        vm.submit = submit;
        vm.close = close;

        vm.aceOption = {};
        vm.aceOption = {
            mode: "razor",
            theme: "chrome",
            showPrintMargin: false,
            autoFocus: true,
            advanced: {
                fontSize: "14px",
                enableSnippets: false, //The Razor mode snippets are awful (Need a way to override these)
                enableBasicAutocompletion: true,
                enableLiveAutocompletion: false,
                wrap: true
            },
            onLoad: function(aceEditor) {
                vm.aceEditor = aceEditor;
            }
        }

        vm.template = {};
        vm.template.content = $scope.model.content;

        //////////

        function onInit() {

            // set default title
            if(!$scope.model.title) {
                // TODO: localize
                $scope.model.title = "Edit source code";
            }
        }

        function submit(model) {

            // refresh the model
            model.content = vm.aceEditor.getValue();

            if($scope.model.submit) {
                $scope.model.submit(model);
            }
        }

        function close() {
            if($scope.model.close) {
                $scope.model.close();
            }
        }

        onInit();
    }

    angular.module("umbraco").controller("Umbraco.PropertyEditors.RTECodeEditorController", CodeEditorController);

})();

Add line wrap to RTE code editor


const fs = require('fs')
const path = require('path')
const Config = require('../config.json')
const Fetcher = require('./fetcher')

class GitHub extends Fetcher {
  // https://developer.github.com/v3/activity/notifications/#list-your-notifications
  getNotifications() {
    return this.get('notifications')
  }

  static getToken() {
    const tokenPath = path.join(__dirname, '..', '..', '.env')
    return fs.readFileSync(tokenPath).toString()
  }

  get(relativeUrl) {
    const url = `${Config.githubApiUrl}/${relativeUrl}`
    const token = this.getToken()
    const options = {
      headers: {
        Accept: 'application/vnd.github.v3+json',
        Authorization: `token ${token}`,
      },
    }
    console.log('github get', url, options)
    return this.get(url, options)
  }
}

module.exports = GitHub

const fs = require('fs')
const path = require('path')
const Config = require('../config.json')
const Fetcher = require('./fetcher')

class GitHub extends Fetcher {
  // https://developer.github.com/v3/activity/notifications/#list-your-notifications
  getNotifications() {
    return this.get('notifications')
  }

  static getToken() {
    const tokenPath = path.join(__dirname, '..', '..', '.env')
    return fs.readFileSync(tokenPath).toString()
  }

  get(relativeUrl) {
    const url = `${Config.githubApiUrl}/${relativeUrl}`
    const token = GitHub.getToken()
    const options = {
      headers: {
        Accept: 'application/vnd.github.v3+json',
        Authorization: `token ${token}`,
      },
    }
    return super.get(url, options)
  }
}

module.exports = GitHub

Fix super call to get from GitHub model


/**
 * grunt
 * CoffeeScript example
 */
module.exports = function(grunt){

  grunt.initConfig({
    lint: {
      files: ['grunt.js', 'src/*.js']
    },
    coffee: {
      compile: {
        options: {
          bare: true
        },
        files: {
          'src/sidetap_loader.js': 'src/coffee/sidetap_loader.coffee',
          'src/sidetap_standard.js': 'src/coffee/sidetap_standard.coffee',
          'src/sidetap_ios.js': 'src/coffee/sidetap_ios.coffee',
          'src/sidetap.js': ['src/coffee/sidetap_standard.coffee','src/coffee/sidetap_ios.coffee','src/coffee/sidetap_loader.coffee']
        }
      }
    },
    less: {
      compile: {
        files: {
          'src/sidetap.css': 'src/less/sidetap.less'
        }
      }
    },
    watch: {
      dist1: {
        files: 'src/coffee/*',
        tasks: 'coffee'
      },
      dist2: {
        files: 'src/less/*',
        tasks: 'less'
      }
    },
    min: {
      dist: {
        src: ['src/sidetap.js'],
        dest: 'src/sidetap.min.js'
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib');
  grunt.registerTask('build', 'coffee less');
  grunt.registerTask('default', 'coffee less min');

};

/**
 * grunt
 * CoffeeScript example
 */
module.exports = function(grunt){

  grunt.initConfig({
    lint: {
      files: ['grunt.js', 'src/*.js']
    },
    coffee: {
      compile: {
        options: {
          bare: true
        },
        files: {
          'src/sidetap_loader.js': 'src/coffee/sidetap_loader.coffee',
          'src/sidetap_standard.js': 'src/coffee/sidetap_standard.coffee',
          'src/sidetap_ios.js': 'src/coffee/sidetap_ios.coffee',
          'src/sidetap.js': ['src/coffee/sidetap_standard.coffee','src/coffee/sidetap_ios.coffee','src/coffee/sidetap_loader.coffee']
        }
      }
    },
    less: {
      compile: {
        files: {
          'src/sidetap.css': 'src/less/sidetap.less'
        }
      }
    },
    watch: {
      dist1: {
        files: 'src/coffee/*',
        tasks: 'coffee min'
      },
      dist2: {
        files: 'src/less/*',
        tasks: 'less'
      }
    },
    min: {
      dist: {
        src: ['src/sidetap.js'],
        dest: 'src/sidetap.min.js'
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib');
  grunt.registerTask('build', 'coffee less min');
  grunt.registerTask('default', 'coffee less min');

};

Make sure javascript gets minified every time the build runs.


// @flow
import { ROUTES } from '../routes-config';
import walletsIcon from '../assets/images/sidebar/wallet-ic.inline.svg';
import settingsIcon from '../assets/images/sidebar/settings-ic.inline.svg';
import paperWalletCertificateIcon from '../assets/images/sidebar/paper-certificate-ic.inline.svg';
import stakingIcon from '../assets/images/sidebar/delegation-ic.inline.svg';

export const CATEGORIES_BY_NAME = {
  WALLETS: {
    name: 'WALLETS',
    route: ROUTES.WALLETS.ROOT,
    icon: walletsIcon,
  },
  PAPER_WALLET_CREATE_CERTIFICATE: {
    name: 'PAPER_WALLET_CREATE_CERTIFICATE',
    route: ROUTES.PAPER_WALLET_CREATE_CERTIFICATE,
    icon: paperWalletCertificateIcon,
  },
  STAKING: {
    name: 'STAKING',
    route: ROUTES.STAKING.ROOT,
    icon: stakingIcon,
  },
  SETTINGS: {
    name: 'SETTINGS',
    route: ROUTES.SETTINGS.ROOT,
    icon: settingsIcon,
  },
};

export const CATEGORIES = [
  CATEGORIES_BY_NAME.WALLETS,
  CATEGORIES_BY_NAME.PAPER_WALLET_CREATE_CERTIFICATE,
  CATEGORIES_BY_NAME.STAKING,
  CATEGORIES_BY_NAME.SETTINGS,
];

export const sidebarConfig = { CATEGORIES_BY_NAME, CATEGORIES };

// @flow
import { ROUTES } from '../routes-config';
import walletsIcon from '../assets/images/sidebar/wallet-ic.inline.svg';
import settingsIcon from '../assets/images/sidebar/settings-ic.inline.svg';
import paperWalletCertificateIcon from '../assets/images/sidebar/paper-certificate-ic.inline.svg';
import stakingIcon from '../assets/images/sidebar/delegation-ic.inline.svg';

export const CATEGORIES_BY_NAME = {
  WALLETS: {
    name: 'WALLETS',
    route: ROUTES.WALLETS.ROOT,
    icon: walletsIcon,
  },
  PAPER_WALLET_CREATE_CERTIFICATE: {
    name: 'PAPER_WALLET_CREATE_CERTIFICATE',
    route: ROUTES.PAPER_WALLET_CREATE_CERTIFICATE,
    icon: paperWalletCertificateIcon,
  },
  STAKING: {
    name: 'STAKING',
    route: ROUTES.STAKING.ROOT,
    icon: stakingIcon,
  },
  SETTINGS: {
    name: 'SETTINGS',
    route: ROUTES.SETTINGS.ROOT,
    icon: settingsIcon,
  },
};

export const CATEGORIES = [
  CATEGORIES_BY_NAME.WALLETS,
  CATEGORIES_BY_NAME.PAPER_WALLET_CREATE_CERTIFICATE,
  CATEGORIES_BY_NAME.SETTINGS,
];

export const sidebarConfig = { CATEGORIES_BY_NAME, CATEGORIES };

Hide staking from app menu


/*
usage:

asyncMap(myListOfStuff, function (thing, cb) { doSomething(thing, cb) }, cb)
asyncMap(list, function (l, cb) { foo(l, cb) ; bar(l, cb) }, 2, cb)

*/

module.exports = asyncMap

function asyncMap (list, fn, n, cb_) {
  if (typeof n === "function") cb_ = n, n = 1
  if (!list || !list.length) return cb_(null, [])
  var data = []
    , errState = null
    , l = list.length
    , a = l * n
  function cb (er, d) {
    if (errState) return
    if (arguments.length > 1) data = data.concat(d)
    // see if any new things have been added.
    if (list.length > l) {
      var newList = list.slice(l)
      a += (list.length - l) * n
      l = list.length
      process.nextTick(function () {
        newList.forEach(function (ar) { fn(ar, cb) })
      })
    }
    if (er) {
      if (false === cb_(errState = er, data)) errState = null
    } else if (-- a === 0) cb_(errState, data)
  }
  list.forEach(function (ar) { fn(ar, cb) })
}

/*
usage:

asyncMap(myListOfStuff, function (thing, cb) { doSomething(thing, cb) }, cb)
asyncMap(list, function (l, cb) { foo(l, cb) ; bar(l, cb) }, 2, cb)

*/

module.exports = asyncMap

function asyncMap (list, fn, n, cb_) {
  if (typeof n === "function") cb_ = n, n = 1
  if (typeof cb_ !== "function") throw new Error(
    "No callback provided to asyncMap")
  if (!list || !list.length) return cb_(null, [])
  var data = []
    , errState = null
    , l = list.length
    , a = l * n
  function cb (er, d) {
    if (errState) return
    if (arguments.length > 1) data = data.concat(d)
    // see if any new things have been added.
    if (list.length > l) {
      var newList = list.slice(l)
      a += (list.length - l) * n
      l = list.length
      process.nextTick(function () {
        newList.forEach(function (ar) { fn(ar, cb) })
      })
    }
    if (er) {
      if (false === cb_(errState = er, data)) errState = null
    } else if (-- a === 0) cb_(errState, data)
  }
  list.forEach(function (ar) { fn(ar, cb) })
}

Throw if no cb provided, since that's an annoying error to track down.


import React, { Component } from 'react';
import CarouselA from './CarouselA';
import CarouselB from './CarouselB';

import styles from './HeroCarousel.styl'

class HeroCarousel extends Component {

  constructor () {
    super();
    this.state = { count: 0 };
  }

  componentDidMount () {
    this.swapper = setInterval(::this.swap, 7500);
  }

  swap () {
    this.setState({count: this.state.count + 1});
  }

  swapHero () {
    clearInterval(this.swapper);
    this.setState({count: this.state.count + 1});
  }

  render () {
    const showA = this.state.count % 2 === 0;

    if (this.props.username) return ;

    return (

        <CarouselA
          swapHero={::this.swapHero}
          oauthUrl={this.props.oauthUrl}
          style={{
            opacity: showA ? 1 : 0,
            pointerEvents: showA ? 'all' : 'none'
          }} />
        <CarouselB
          swapHero={::this.swapHero}
          oauthUrl={this.props.oauthUrl}
          style={{
            opacity: showA ? 0 : 1,
            pointerEvents: showA ? 'none' : 'all'
          }} />

    )
  }
}

export default HeroCarousel;

import React, { Component } from 'react';
import CarouselA from './CarouselA';
import CarouselB from './CarouselB';

import styles from './HeroCarousel.styl'

class HeroCarousel extends Component {

  constructor () {
    super();
    this.state = { count: 0 };
  }

  componentDidMount () {
    this.swapper = setInterval(::this.swap, 7500);
  }

  componentWillUnmount () {
    clearInterval(this.swapper);
  }

  swap () {
    this.setState({count: this.state.count + 1});
  }

  swapHero () {
    clearInterval(this.swapper);
    this.setState({count: this.state.count + 1});
  }

  render () {
    const showA = this.state.count % 2 === 0;

    if (this.props.username) return ;

    return (

        <CarouselA
          swapHero={::this.swapHero}
          oauthUrl={this.props.oauthUrl}
          style={{
            opacity: showA ? 1 : 0,
            pointerEvents: showA ? 'all' : 'none'
          }} />
        <CarouselB
          swapHero={::this.swapHero}
          oauthUrl={this.props.oauthUrl}
          style={{
            opacity: showA ? 0 : 1,
            pointerEvents: showA ? 'none' : 'all'
          }} />

    )
  }
}

export default HeroCarousel;

Make sure interval gets canceled


import { apiProxyAxios } from '../Task/utils'

export const fetchOutstandingPropositions = ({ adviser }) =>
  apiProxyAxios
    .get('/v4/proposition', {
      params: {
        adviser_id: adviser.id,
        status: 'ongoing',
        sortBy: 'deadline',
        limit: 5,
      },
    })
    .then(({ data }) => data)

import { apiProxyAxios } from '../Task/utils'

export const fetchOutstandingPropositions = ({ adviser }) =>
  apiProxyAxios
    .get('/v4/proposition', {
      params: {
        adviser_id: adviser.id,
        status: 'ongoing',
        sortby: 'deadline',
        limit: 5,
      },
    })
    .then(({ data }) => data)

Fix sort by on reminders api call