import { createStore, applyMiddleware, compose } from 'redux'
import createLogger from 'redux-logger'
import saga from 'redux-saga'
import DevTools from '../containers/DevTools'
import rootReducer from '../reducers'
import rootSaga from '../sagas'

const finalCreateStore = compose(
  applyMiddleware(saga(rootSaga), createLogger()),
  DevTools.instrument()
)(createStore)

export default function configureStore(initialState) {
  const store = finalCreateStore(rootReducer, initialState)

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers')
      store.replaceReducer(nextRootReducer)
    })
  }

  return store
}

import { createStore, applyMiddleware, compose } from 'redux'
import createLogger from 'redux-logger'
import saga from 'redux-saga'
import DevTools from '../containers/DevTools'
import rootReducer from '../reducers'
import rootSaga from '../sagas'

const finalCreateStore = compose(
  applyMiddleware(saga(rootSaga), createLogger()),
  DevTools.instrument()
)(createStore)

export default function configureStore(initialState) {
  const store = finalCreateStore(rootReducer, initialState)

  if (module.hot) {
    // Enable Webpack hot module replacement for reducers
    module.hot.accept('../reducers', () => {
      const nextRootReducer = require('../reducers').default
      store.replaceReducer(nextRootReducer)
    })
  }

  return store
}

Fix hot reducer loading in examples/real-world


module.exports = function() {
  var dataBuffer = Array.prototype.slice.call(arguments),
      data,
      self = this;

  data = dataBuffer.map(function(d) {
    return d.toString();
  });

  // update timer for last message recieved
  this.lastMsg = new Date();

  switch(data[0]) {
    case this.constants.HEARTBEAT:
      console.log("I: HEARTBEAT");
      var heartbeat = [
        this.constants.PROTOCOL_WORKER, this.constants.HEARTBEAT
      ];
      self.socket.send(heartbeat);
      break;
    case this.constants.REQUEST:
      var req = {};

      data.forEach(function(d, i) {
        var attr = self.constants.MSG_ATTRS[i];

        req[attr] = d.toString();
      });

      try {
        if(req.params) {
          req.params = JSON.parse(req.params);
        }
      } catch(err) {
        console.log('Connot parse message', req.correlationId,  err);
      }

      console.log("I: REQUEST", req);
      this.events.emit('request', req);
      break;
    case this.constants.DISCONNECT:
      console.log("E: DISCONNECTED", data[1]);

      this.events.emit('disconnect', data[2]);
      break;
    default:
      console.log("?: Unknown request type", data[0]);
  }
}

module.exports = function() {
  var dataBuffer = Array.prototype.slice.call(arguments),
      data,
      self = this;

  data = dataBuffer.map(function(d) {
    return d.toString();
  });

  // update timer for last message recieved
  this.lastMsg = new Date();

  switch(data[0]) {
    case this.constants.HEARTBEAT:
      console.log("I: HEARTBEAT");
      var heartbeat = [
        this.constants.PROTOCOL_WORKER, this.constants.HEARTBEAT
      ];
      self.socket.send(heartbeat);
      break;
    case this.constants.REQUEST:
      var req = {};

      data.forEach(function(d, i) {
        var attr = self.constants.MSG_ATTRS[i];

        req[attr] = d.toString();
      });

      try {
        if(req.params) {
          req.params = JSON.parse(req.params);
        }
      } catch(err) {
        console.log('Connot parse message', req.correlationId,  err);
      }

      console.log("I: REQUEST", req);
      this.events.emit('request', req);
      break;
    case this.constants.DISCONNECT:
      console.log("E: DISCONNECTED", data[1]);

      this.liveness = 0;
      this.events.emit('disconnect', data[2]);
      break;
    default:
      console.log("?: Unknown request type", data[0]);
  }
}

Set liveness to 0 when broker tells us we are disconnected


'use strict';

module.exports = function compress(grunt) {
    // Load task
    grunt.loadNpmTasks('grunt-contrib-compress');

    return {
        'hmda-edit-check-api': {
            options: {
                archive: './dist/hmda-edit-check-api.zip',
                mode: 'zip',  //zip | gzip | deflate | tgz
                pretty: true
            },
            files: [
                {
                    expand: true,
                    cwd: './',

                    //zip all files except coverage, test dirs and the grunt/test modules
                    src: [ '**',
                        '!coverage/**',
                        '!test/**',
                        '!node_modules/**'
                    ]
                }
            ]
        },
        'codedeploy': {
          options: {
            archive: './dist/hmda-edit-check-api-codedeploy.zip',
            mode: 'zip',  //zip | gzip | deflate | tgz
            pretty: true
          },
          files: [
            {
              expand: true,
              dot: true,
              cwd: './',

              //zip dist directory
              src: ['dist/hmda-edit-check-api.zip', 'scripts/*', 'appspec.yml']
            }
          ]
        }
    };
};

'use strict';

module.exports = function compress(grunt) {
    // Load task
    grunt.loadNpmTasks('grunt-contrib-compress');

    return {
        'hmda-edit-check-api': {
            options: {
                archive: './dist/hmda-edit-check-api.zip',
                mode: 'zip',  //zip | gzip | deflate | tgz
                pretty: true
            },
            files: [
                {
                    expand: true,
                    cwd: './',

                    //zip all files except coverage, test dirs and the grunt/test modules
                    src: [ '**',
                        '!data/**',
                        '!coverage/**',
                        '!test/**',
                        '!node_modules/**'
                    ]
                }
            ]
        },
        'codedeploy': {
          options: {
            archive: './dist/hmda-edit-check-api-codedeploy.zip',
            mode: 'zip',  //zip | gzip | deflate | tgz
            pretty: true
          },
          files: [
            {
              expand: true,
              dot: true,
              cwd: './',

              //zip dist directory
              src: ['dist/hmda-edit-check-api.zip', 'scripts/*', 'appspec.yml']
            }
          ]
        }
    };
};

Exclude data from the deploy for now


// ==UserScript==
// @name         GMail Oldest First
// @namespace    https://blog.jverkamp.com/
// @version      0.2
// @description  Display emails in Gmail oldest first (per page)
// @author       JP Verkamp
// @match        https://mail.google.com/*
// @grant        none
// ==/UserScript==

// Warning, this will break if (when) GMail changes their class names

/* jshint -W097 */
'use strict';

(function() {
    let head = document.getElementsByTagName('head')[0];
    let style = document.createElement('style');
    style.type = 'text/css';
    style.innerHTML = `
table.F.cf.zt tbody {
    display: flex;
    flex-direction: column-reverse;
}
    `;
    head.appendChild(style);
    console.log('GMail Oldest First applied style');
})();

// ==UserScript==
// @name         GMail Oldest First
// @namespace    https://blog.jverkamp.com/
// @version      0.2
// @description  Display emails in Gmail oldest first (per page)
// @author       JP Verkamp
// @match        https://mail.google.com/*
// @grant        none
// ==/UserScript==

// Warning, this will break if (when) GMail changes their class names

/* jshint -W097 */
'use strict';

(function() {
    const CLASS_NAME = 'gmail-oldest-first';
    const MESSAGE_LIST_QUERY = 'table.F.cf.zt tbody';

    function toggle() {
        console.log('Gmail Oldest First: Toggle');
        document.querySelectorAll(MESSAGE_LIST_QUERY).forEach((el) => {
            el.classList.toggle(CLASS_NAME);
        });
    }

    let head = document.getElementsByTagName('head')[0];
    let style = document.createElement('style');
    style.id = 'gmail-oldest-first';
    style.type = 'text/css';
    style.innerHTML = `
.${CLASS_NAME} {
    display: flex !important;
    flex-direction: column-reverse;
}
    `;
    head.appendChild(style);
    console.log('GMail Oldest First: Applied style');

    // Run once to reverse by default
    toggle();

    // Bind to Ctrl-R to reverse
    document.addEventListener('keyup', (event) => {
        if (event.ctrlKey && event.key == 'r') {
            toggle();
        }
    });
})();

Add a keyboard shortcut (Ctrl-R) to reverse


minispade.register('controllers', function() {

  RiakCsControl.ApplicationController = Ember.Controller.extend();

  RiakCsControl.CreateUserController = Ember.ObjectController.extend({
    enter: function() {
      this.transaction = this.get('store').transaction();
      this.set('content',
        this.transaction.createRecord(RiakCsControl.User, {}));
    },

    createUser: function() {
      this.transaction.commit();
      this.transaction = null;
    },

    exit: function() {
      this.transaction.rollback();
      this.transaction = null;
    }
  });

  RiakCsControl.UsersController = Ember.ArrayController.extend({
    persistedUsers: function() {
      return this.get('content').filterProperty('isNew', false);
    }.property('content.@each.isNew'),

    enableUser: function(user) {
      this.performUserUpdate(user, function() { user.enable(); });
    },

    disableUser: function(user) {
      this.performUserUpdate(user, function() { user.disable(); });
    },

    revokeCredentials: function(user) {
      this.performUserUpdate(user, function() { user.revoke(); });
    },

    performUserUpdate: function(user, update) {
      var transaction = RiakCsControl.get('store').transaction();

      transaction.add(user);
      update.call(user);
      transaction.commit();
    }
  });

});

minispade.register('controllers', function() {

  RiakCsControl.ApplicationController = Ember.Controller.extend();

  RiakCsControl.CreateUserController = Ember.ObjectController.extend({
    enter: function() {
      this.transaction = this.get('store').transaction();
      this.set('content',
        this.transaction.createRecord(RiakCsControl.User, {}));
    },

    createUser: function() {
      this.transaction.commit();
      this.transaction = null;

      this.get('content').addObserver('id', this, 'showUsers');
    },

    exit: function() {
      this.transaction.rollback();
      this.transaction = null;
    },

    viewUsers: function() {
      RiakCsControl.router.send('viewUsers');
    }
  });

  RiakCsControl.UsersController = Ember.ArrayController.extend({
    persistedUsers: function() {
      return this.get('content').filterProperty('isNew', false);
    }.property('content.@each.isNew'),

    enableUser: function(user) {
      this.performUserUpdate(user, function() { user.enable(); });
    },

    disableUser: function(user) {
      this.performUserUpdate(user, function() { user.disable(); });
    },

    revokeCredentials: function(user) {
      this.performUserUpdate(user, function() { user.revoke(); });
    },

    performUserUpdate: function(user, update) {
      var transaction = RiakCsControl.get('store').transaction();

      transaction.add(user);
      update.call(user);
      transaction.commit();
    }
  });

});

Return to user list once user is created.


render("contacts");
render("projects");

function render(template) {
    var source = document.getElementById(template + "-template").innerHTML;
    var destination = document.querySelector("." + template);
    destination.innerHTML = Handlebars.compile(source)(data[template]);
}

var action = document.getElementById("action");
var actions = ["collaborate", "create", "share", "build", "learn", "code", "teach", "dream"];

var i = 0;

setInterval(function() {
    action.innerHTML = actions[i];
    i = (i + 1) % actions.length;
}, 1500);

var bLazy = new Blazy({
        selector: 'img'
    }
);

render("contacts");
render("projects");

function render(template) {
    var source = document.getElementById(template + "-template").innerHTML;
    var destination = document.querySelector("." + template);
    destination.innerHTML = Handlebars.compile(source)(data[template]);
}

var action = document.getElementById("action");
var actions = ["collaborate", "create", "share", "build", "learn", "code", "teach", "dream"];

var i = 0;

setInterval(function() {
    action.innerHTML = actions[i];
    i = (i + 1) % actions.length;
}, 1500);

var bLazy = new Blazy({
        selector: 'img',
        offset: 500
    }
);

Set the bLazy offset to 500px


import commonjs from 'rollup-plugin-commonjs';
import nodeResolve from 'rollup-plugin-node-resolve';

export default {
  output: {name: 'perfetto'},
  plugins: [
    nodeResolve({mainFields: ['browser', 'main']}),

    // emscripten conditionally executes require('fs') (likewise for others),
    // when running under node. Rollup can't find those libraries so expects
    // these to be present in the global scope, which then fails at runtime.
    // To avoid this we ignore require('fs') and the like.
    commonjs({
      ignore: [
        'fs',
        'path',
        'crypto',
      ]
    }),
  ]
}

import commonjs from 'rollup-plugin-commonjs';
import nodeResolve from 'rollup-plugin-node-resolve';

export default {
  output: {name: 'perfetto'},
  plugins: [
    nodeResolve({module: false, browser: true}),

    // emscripten conditionally executes require('fs') (likewise for others),
    // when running under node. Rollup can't find those libraries so expects
    // these to be present in the global scope, which then fails at runtime.
    // To avoid this we ignore require('fs') and the like.
    commonjs({
      ignore: [
        'fs',
        'path',
        'crypto',
      ]
    }),
  ]
}

Revert "perfetto-ui: Fix deprecated warning"


/* eslint-disable no-native-reassign */
/* global addToPage, setTitle, showLoadingIndicator, useTheme, useFontFamily */

// Makes regular text have the regular text size
document.body.style.fontSize = "1.33333333em";

document.body.className = "light sans-serif";

const oldSetTitle = setTitle;
setTitle = (...args) => {
	window.top.postMessage({action: "setTitle", title: args[0]}, "*");
	oldSetTitle.apply(window, args);
}

const result = JSON.parse(localStorage["result_" + location.hash.substr(1)]);
addToPage(result[2][1]);
setTitle(result[1]);
showLoadingIndicator(true);

chrome.storage.sync.get({theme: "light", font: "sans-serif"}, ({theme, font}) => {
	useTheme(theme);
	useFontFamily(font);
});

/* eslint-disable no-native-reassign */
/* global addToPage, setTitle, showLoadingIndicator, useTheme, useFontFamily */

// Makes regular text have the regular text size
document.body.style.fontSize = "1.33333333em";

document.body.className = "light sans-serif";

const oldSetTitle = setTitle;
setTitle = (...args) => {
	window.top.postMessage({action: "setTitle", title: args[0]}, "*");
	oldSetTitle.apply(window, args);
}

const storageKey = "result_" + location.hash.substr(1);
const result = JSON.parse(localStorage[storageKey]);
localStorage.removeItem(storageKey);
addToPage(result[2][1]);
setTitle(result[1]);
showLoadingIndicator(true);

chrome.storage.sync.get({theme: "light", font: "sans-serif"}, ({theme, font}) => {
	useTheme(theme);
	useFontFamily(font);
});

Delete localStorage data after use


import React from 'react'
import ReactDOM from 'react-dom'

class App extends React.Component {
  render() {
    return (

Sample App

    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app'));

import React from 'react';
import ReactDOM from 'react-dom';

class App extends React.Component {
  render() {
    return (

Sample App

    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
);

Add missing semicolons and a new line


const {getNativeInteger} = require("./helpers");

class Route {
  constructor(attributes) {
    this.attributes = attributes;
  }

  route() {
    var route;
    switch ((route = this.routeId())) {
      case "Brn":
        return "Brown";
      case "G":
        return "Green";
      case "Org":
        return "Orange";
      case "P":
        return "Purple";
      case "Y":
        return "Yellow";
      default:
        return route;
    }
  }

  directionId() {
    return getNativeInteger(this.attributes.trDr);
  }

  runNumber() {
    return getNativeInteger(this.attributes.rn);
  }

  routeClass() {
    return this.route().toLowerCase();
  }

  routeId() {
    return this.attributes.rt;
  }

  toJSON() {
    return {
      class: this.routeClass(),
      directionId: this.directionId(),
      id: this.routeId(),
      name: this.route(),
      run: this.runNumber(),
    };
  }
}

module.exports = Route;

const {getNativeInteger} = require("./helpers");

const ABBREVIATED_ROUTE_NAMES = {
  Brn: "Brown",
  G: "Green",
  Org: "Orange",
  P: "Purple",
  Y: "Yellow",
};

class Route {
  constructor(attributes) {
    this.attributes = attributes;
  }

  route() {
    return ABBREVIATED_ROUTE_NAMES[this.attributes.rt] || this.attributes.rt;
  }

  directionId() {
    return getNativeInteger(this.attributes.trDr);
  }

  runNumber() {
    return getNativeInteger(this.attributes.rn);
  }

  routeClass() {
    return this.route().toLowerCase();
  }

  routeId() {
    return this.attributes.rt;
  }

  toJSON() {
    return {
      class: this.routeClass(),
      directionId: this.directionId(),
      id: this.routeId(),
      name: this.route(),
      run: this.runNumber(),
    };
  }
}

module.exports = Route;

Move short line names to object


// Module dependencies.
var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var error = require('./util/error');

/**
 * Show a contextual help.
 * @param  {String} [command] Command you want to know more about.
 * @return {String}
 */
var help =  function (command) {
  var file = 'help';
  if (!_.isNull(command)) {
    file += '-' + command;
  }
  file += '.txt';
  file = path.resolve(__dirname + '../../../doc/cli/' + file);
  fs.readFile(file, 'utf8', function (err, data) {
    if (err) {
      error.handle(new Error('Can\'t read file'));
    };
    console.log(data);
  });
};

module.exports = help;

// Module dependencies.
var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var error = require('./util/error');

/**
 * Show a contextual help.
 * @param  {String} [context] Command you want to know more about.
 * @return {String}
 */
var help =  function (context) {
  var file = 'help';
  if (context === 'global') {
    file += '-' + context;
  }
  file += '.txt';
  file = path.resolve(__dirname + '../../../doc/cli/' + file);
  fs.readFile(file, 'utf8', function (err, data) {
    if (err) {
      error.handle(new Error('Can\'t read file'));
    };
    console.log(data);
  });
};

module.exports = help;

Change command paramater to context


import React, { Component } from 'react';
import {
  View,
  ScrollView,
} from 'react-native';
import _ from 'lodash'
import { observer } from 'mobx-react/native'

import { BarMapView } from './BarMap.js'
import { BarCard } from './BarCard.js'
import { DownloadResultView } from './HTTP.js'
import { T } from './AppText.js'
import { store } from './Store.js'
import { config } from './Config.js'

@observer export class DiscoverPage extends DownloadResultView {
    constructor(props) {
        super(props, "Error downloading list of bars:")
    }

    refreshPage = store.initialize
    getDownloadResult = () => store.barList
    renderNotStarted  = () => <View />

    renderFinished = (barList) => {
        return <ScrollView style={{flex: 1}}>
            <BarMapView />
            <View style={{flex: 1}}>
                {/*
                <T style={
                        { marginLeft: 10
                        , fontSize: 20
                        , color: config.theme.primary.medium
                        }}>
                    Nearby Bars
                </T>
                */}
                {barList.slice(0, 3).map((bar, i) => <BarCard key={i} bar={bar} />)}
            </View>
        </ScrollView>
    }
}

import React, { Component } from 'react';
import {
  View,
  ScrollView,
} from 'react-native';
import _ from 'lodash'
import { observer } from 'mobx-react/native'

import { BarMapView } from './BarMap.js'
import { BarCard } from './BarCard.js'
import { DownloadResultView } from './HTTP.js'
import { T } from './AppText.js'
import { store } from './Store.js'
import { config } from './Config.js'

@observer export class DiscoverPage extends DownloadResultView {
    constructor(props) {
        super(props, "Error downloading list of bars:")
    }

    refreshPage = store.initialize
    getDownloadResult = () => store.barList
    renderNotStarted  = () => <View />

    saveScrollView = (scrollview) => {
        store.discoverScrollView = scrollview
    }

    renderFinished = (barList) => {
        return (
            <ScrollView style={{flex: 1}} ref={this.saveScrollView}>
                <BarMapView />
                <View style={{flex: 1}}>
                    {/*
                    <T style={
                            { marginLeft: 10
                            , fontSize: 20
                            , color: config.theme.primary.medium
                            }}>
                        Nearby Bars
                    </T>
                    */}
                    {barList.slice(0, 3).map((bar, i) => <BarCard key={i} bar={bar} />)}
                </View>
            </ScrollView>
        )
    }
}

Change discover page layout a little


describe("Core Bliss", function () {
  "use strict";

  beforeEach(function () {
    fixture.setBase('tests/fixtures')
    this.fixture = fixture.load('core.html');
    document.body.innerHTML += this.fixture[0]
  });

  // testing setup
  it("has the fixture on the dom", function () {
    expect($('#fixture-container')).to.not.be.null;
  });

});

describe("Core Bliss", function () {
  "use strict";

  beforeEach(function () {
    fixture.setBase('tests/fixtures');
    this.fixture = fixture.load('core.html');
    document.body.innerHTML += this.fixture[0];
  });

  // testing setup
  it("has the fixture on the dom", function () {
    expect($('#fixture-container')).to.not.be.null;
  });

  it("has global methods and aliases", function() {
    expect(Bliss).to.be.defined;
    expect($).to.be.defined;
    expect($$).to.be.defined;

    expect($).to.equal(Bliss);
    expect($$).to.equal($.$);
  });
});

Add some core smoke tests


#!/usr/bin/env node
'use strict';

/** Load modules. */
var fs = require('fs'),
    path = require('path');

/** Resolve program params. */
var args = process.argv.slice(process.argv[0] === process.execPath ? 2 : 0),
    filePath = path.resolve(args[1]);

var pattern = (function() {
  var result = args[0],
      delimiter = result.charAt(0),
      lastIndex = result.lastIndexOf(delimiter);

  return RegExp(result.slice(1, lastIndex), result.slice(lastIndex + 1));
}());

/** Used to match lines of code. */
var reLine = /.*/gm;

/*----------------------------------------------------------------------------*/

fs.writeFileSync(filePath, fs.readFileSync(filePath, 'utf-8').replace(pattern, function(match) {
  return match.replace(reLine, '');
}));

#!/usr/bin/env node
'use strict';

/** Load modules. */
var fs = require('fs'),
    path = require('path');

/** Resolve program params. */
var args = process.argv.slice(process.argv[0] === process.execPath ? 2 : 0),
    filePath = path.resolve(args[1]);

var pattern = (function() {
  var result = args[0],
      delimiter = result.charAt(0),
      lastIndex = result.lastIndexOf(delimiter);

  return RegExp(result.slice(1, lastIndex), result.slice(lastIndex + 1));
}());

/** Used to match lines of code. */
var reLine = /.*/gm;

/*----------------------------------------------------------------------------*/

fs.writeFileSync(filePath, fs.readFileSync(filePath, 'utf8').replace(pattern, function(match) {
  return match.replace(reLine, '');
}));

Use 'utf8', which Node uses, instead of 'utf-8'.


const { JSDOM } = require('jsdom');

const jsdom = new JSDOM('<!DOCTYPE html>');
const { window } = jsdom;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
        .filter(prop => typeof target[prop] === 'undefined')
        .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
global.navigator = {
    userAgent: 'node.js',
};
copyProps(window, global);

const { JSDOM } = require('jsdom');

const jsdom = new JSDOM('<!DOCTYPE html>');
const { window } = jsdom;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
        .filter(prop => typeof target[prop] === 'undefined')
        .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
}

global.window = window;
global.document = window.document;
global.HTMLElement = window.HTMLElement;
global.navigator = {
    userAgent: 'node.js',
};
copyProps(window, global);

Fix test errors caused by upgrade in Chai dependency


QUnit.module( "FrequencyMap tests" );
QUnit.test( "constructor test", function( assert ) {
    var fm = new FrequencyMap();
    assert.ok( fm instanceof FrequencyMap, "Default constructor works");
});
QUnit.test("getFrequency tests", function(assert) {
    var fm = new FrequencyMap();
    assert.strictEqual(fm.getFrequency(0, 9), 110, "A110 is returned correctly");
    assert.strictEqual(fm.getFrequency(1, 9), 220, "A220 is returned correctly");
    assert.strictEqual(fm.getFrequency(2, 9), 440, "A440 is returned correctly");
    assert.strictEqual(fm.getFrequency(3, 9), 880, "A880 is returned correctly");
    assert.strictEqual(fm.getFrequency(4, 9), 1760, "A1760 is returned correctly");
});

QUnit.assert.close = function(number, expected, error, message ) {
    if (error === void 0 || error === null ) {
        error = 0.00001;
    }
    var result = number === expected || (number<expected + error && number > expected - error) || false;
    this.push(result, number, expected, message);
}
QUnit.module( "FrequencyMap tests" );
QUnit.test( "constructor test", function( assert ) {
    var fm = new FrequencyMap();
    assert.ok( fm instanceof FrequencyMap, "Default constructor works");
});
QUnit.test("getFrequency tests", function(assert) {
    var fm = new FrequencyMap();
    assert.close(fm.getFrequency(0, 9), 110, null, "A110 is returned correctly");
    assert.close(fm.getFrequency(1, 9), 220, null,  "A220 is returned correctly");
    assert.close(fm.getFrequency(2, 9), 440, null,  "A440 is returned correctly");
    assert.close(fm.getFrequency(3, 9), 880, null,  "A880 is returned correctly");
    assert.close(fm.getFrequency(4, 9), 1760, null,  "A1760 is returned correctly");
});

Use our own assert method to test for float values.


/**
 * Grunt-Contrib-RequireJS
 * @description Optimize RequireJS projects using r.js.
 * @docs https://github.com/gruntjs/grunt-contrib-requirejs
*/

var config = require("../Config");

module.exports = {
	deploy: {
		options: {
			mainConfigFile: config.JavaScripts.paths.devDir + "/" + config.JavaScripts.requireJS.config + ".js",
			include: [config.JavaScripts.requireJS.libSourceFile, config.JavaScripts.requireJS.config],
			out: config.JavaScripts.requireJS.compileDistFile,

			// Wrap in an IIFE
			wrap: true,

			// Generate source maps for the build.
			generateSourceMaps: true,

			// Do not preserve license comments when working with source maps, incompatible.
			preserveLicenseComments: false,

			// Uglify the build with 'uglify2'.
			optimize: "uglify2",

			// Remove 'console.log(...)' statements if set to true in the grunt config.
			onBuildRead: function (moduleName, path, contents) {
				"use strict";
				if(config.JavaScripts.requireJS.removeLoggingStatements) {
					return contents.replace(/console.log(.*);/g, '');
				} else {
					return contents;
				}
			}
		}
	}
};

/**
 * Grunt-Contrib-RequireJS
 * @description Optimize RequireJS projects using r.js.
 * @docs https://github.com/gruntjs/grunt-contrib-requirejs
*/

var config = require("../Config");

module.exports = {
	deploy: {
		options: {
			mainConfigFile: config.JavaScripts.paths.devDir + "/" + config.JavaScripts.requireJS.config + ".js",
			include: [config.JavaScripts.requireJS.libSourceFile, config.JavaScripts.requireJS.config],
			out: config.JavaScripts.requireJS.compileDistFile,

      // Include all require files in nested files.
      findNestedDependencies: true,

			// Wrap in an IIFE
			wrap: true,

			// Generate source maps for the build.
			generateSourceMaps: true,

			// Do not preserve license comments when working with source maps, incompatible.
			preserveLicenseComments: false,

			// Uglify the build with 'uglify2'.
			optimize: "uglify2",

			// Remove 'console.log(...)' statements if set to true in the grunt config.
			onBuildRead: function (moduleName, path, contents) {
				"use strict";
				if(config.JavaScripts.requireJS.removeLoggingStatements) {
					return contents.replace(/console.log(.*);/g, '');
				} else {
					return contents;
				}
			}
		}
	}
};

Set the 'findNestedDependencies' flag for the r.js optimizer to true


import _Any from "./any"
import _Core from "./core"
import _Union from "./union"
/**
 * An map of strings to some types.
 */
export default class _AssociativeArray extends _Any {
    /**
     *
     * @param {_Union} member_type
     */
    constructor(member_type = null) {
        super()
        this.memberType = member_type
    }
    /**
     * @type {string} A string representation of the type, as meaningful for type
     * checking.
     */
    get typeSignature() {
        return "array"
    }

    /**
     * Returns true if this type does not violate the expectations of another
     * associative array type.
     *
     * Please note that associative arrays DO violate the expectations of
     * indexed arrays.
     *
     * @param {_Any} expected_type The other array type
     * @returns {boolean}
     */
    compliesWith(expected_type) {
        if(expected_type instanceof _AssociativeArray) {
            return this.memberType.compliesWith(expected_type.memberType)
        } else {
            return super.compliesWith(expected_type)
        }
    }

    /**
     * @type {string} Represents best expression of the object, rather than
     * simply its type signature.
     */
    toString() {
        return this.typeSignature
    }
}

import _Any from "./any"
import _Core from "./core"
import _Union from "./union"
/**
 * An map of strings to some types.
 */
export default class _AssociativeArray extends _Any {
    /**
     *
     * @param {_Union} member_type
     */
    constructor(member_type = null) {
        super()
        this.memberType = member_type
    }
    /**
     * @type {string} A string representation of the type, as meaningful for type
     * checking.
     */
    get typeSignature() {
        return "array"
    }

    /**
     * Returns true if this type does not violate the expectations of another
     * associative array type.
     *
     * Please note that associative arrays DO violate the expectations of
     * indexed arrays.
     *
     * @param {_Any} expected_type The other array type
     * @returns {boolean}
     */
    compliesWith(expected_type) {
        if(expected_type instanceof _AssociativeArray) {
            if(!expected_type.memberType) {
                return true
            } else if(!this.memberType) {
                return false
            } else {
                return this.memberType.compliesWith(expected_type.memberType)
            }
        } else {
            return super.compliesWith(expected_type)
        }
    }

    /**
     * @type {string} Represents best expression of the object, rather than
     * simply its type signature.
     */
    toString() {
        return this.typeSignature
    }
}

Fix compliance test where the member type is unset


import { Observable } from 'rx';
import { handleError, setUser, fetchUser } from './types';

export default ({ services }) => ({ dispatch }) => next => {
  return function getUserSaga(action) {
    if (action.type !== fetchUser) {
      return next(action);
    }

    return services.readService$({ service: 'user' })
      .map(({
        username,
        picture,
        progressTimestamps = [],
        isFrontEndCert,
        isBackEndCert,
        isFullStackCert
      }) => {
        return {
          type: setUser,
          payload: {
            username,
            picture,
            points: progressTimestamps.length,
            isFrontEndCert,
            isBackEndCert,
            isFullStackCert,
            isSignedIn: true
          }
        };
      })
      .catch(error => Observable.just({
        type: handleError,
        error
      }))
      .doOnNext(dispatch);
  };
};

import { Observable } from 'rx';
import { handleError, setUser, fetchUser } from './types';

export default ({ services }) => ({ dispatch }) => next => {
  return function getUserSaga(action) {
    if (action.type !== fetchUser) {
      return next(action);
    }

    return services.readService$({ service: 'user' })
      .map(({
        username,
        picture,
        points,
        isFrontEndCert,
        isBackEndCert,
        isFullStackCert
      }) => {
        return {
          type: setUser,
          payload: {
            username,
            picture,
            points,
            isFrontEndCert,
            isBackEndCert,
            isFullStackCert,
            isSignedIn: true
          }
        };
      })
      .catch(error => Observable.just({
        type: handleError,
        error
      }))
      .doOnNext(dispatch);
  };
};

Fix brownie points not showing on react pages


// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:

Parse.Cloud.define("hello", function(request, response) {
  response.success("Hello world!");
});

Parse.Cloud.define("reviewTeammate", function(request, response) {
  Parse.Cloud.useMasterKey();
  var userId = request.params.userId;
  var reviewKey = request.params.reviewKey;
  var thinkerReview = request.params.review.thinkerReview;
  var enablerReview = request.params.review.enablerReview;
  var connectorReview = request.params.review.connectorReview;
  var query = new Parse.Query("User");

  query.get(userId).then(function(user) {
    user.increment("thinker", thinkerReview);
    user.increment("enabler", enablerReview);
    user.increment("connector", connectorReview);
    return user.save();
  }).then(function(user) {
    response.success({
      message: "Updated score for " + user.get('name')
    });
  }, function(error) {
    console.log("Failed: " +error.message);
    response.error(error);
  });
});

// Use Parse.Cloud.define to define as many cloud functions as you want.
// For example:

Parse.Cloud.define("hello", function(request, response) {
  response.success("Hello world!");
});

Parse.Cloud.define("reviewTeammate", function(request, response) {
  Parse.Cloud.useMasterKey();
  var userId = request.params.userId;
  var reviewKey = request.params.reviewKey;
  var thinkerReview = request.params.review.thinkerReview;
  var enablerReview = request.params.review.enablerReview;
  var connectorReview = request.params.review.connectorReview;
  var query = new Parse.Query("User");

  query.get(userId).then(function(user) {
    user.increment("thinker", thinkerReview);
    user.increment("enabler", enablerReview);
    user.increment("connector", connectorReview);
    user.add("reviewKeys", reviewKey);
    return user.save();
  }).then(function(user) {
    response.success({
      message: "Updated score for " + user.get('name')
    });
  }, function(error) {
    console.log("Failed: " +error.message);
    response.error(error);
  });
});

Add reviewKey to reviewKeys array on Parse for user that is reviewed on Parse


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

define(['../../helpers'], function(Helpers) {
    'use strict';
    function WelcomePage(remote) {
        this.remote = remote;
    }

    WelcomePage.prototype = {
        constructor: WelcomePage,
        skip: function(strictCheck) {
            return this.remote
                .getCurrentUrl()
                .then(function(url) {
                    if (url == Helpers.serverUrl + '/#welcome') {
                        return this.parent
                            .clickByCssSelector('.welcome-button-box button')
                            .waitForDeletedByCssSelector('.welcome-button-box button', 2000)
                            .then(
                                function() {return true},
                                function() {return !strictCheck}
                            );
                    } else {
                        return true;
                    }
                });
        }
    };
    return WelcomePage;
});

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

define(['../../helpers'], function() {
    'use strict';
    function WelcomePage(remote) {
        this.remote = remote;
    }

    WelcomePage.prototype = {
        constructor: WelcomePage,
        skip: function(strictCheck) {
            return this.remote
                .waitForCssSelector('.welcome-page', 3000)
                .then(function() {
                    return this.parent
                        .clickByCssSelector('.welcome-button-box button')
                        .waitForDeletedByCssSelector('.welcome-button-box button', 2000)
                        .then(
                            function() {return true},
                            function() {return !strictCheck}
                        );
                    },
                    function() {return !strictCheck}
                );
        }
    };
    return WelcomePage;
});

Fix for randomly failing Welcome page tests


$(document).ready(function(){
  $('#navLogInRegisterButton').on("click",function(event){
    event.preventDefault();
    $.ajax({
      method:"get",
      url:"/sessions/new"
    }).done(function(result){
      $("#newModalForm").html(result);
    }).fail(function(error){
      console.log(error);
    });
  });

  $("#home_create_button").on("click",function(event){
    event.preventDefault();
    $.ajax({
      method:"get",
      url:"/surveys/new"
    }).done(function(result){
      $("#newModalForm").html(result);
      formCreation();
    }).fail(function(error){
      console.log(error);
    });
  });
});

$(document).ready(function(){
  $('#navLogInRegisterButton').on("click",function(event){
    event.preventDefault();
    $.ajax({
      method:"get",
      url:"/sessions/new"
    }).done(function(result){
      $("#newModalForm").html(result);
    }).fail(function(error){
      console.log(error);
    });
  });

  $("#home_create_button").on("click",function(event){
    event.preventDefault();
    $.ajax({
      method:"get",
      url:"/surveys/new"
    }).done(function(result){
      if ($(".modal-body").children().length == 0){
        $("#newModalForm").html(result);
        formCreation();
      }
    }).fail(function(error){
      console.log(error);
    });
  });
});

Add create form reserve with ajax modal window


const register = require('postcss-variables/lib/register');
let v = require('wee-core/styles/variables');
let { colors, font, heading, icon } = require('wee-core/styles/variables');
let color = require('tinycolor2');

// Add and overwrite variables here
// Example - v.colors.primary = '#58a324';

colors.primary = '#111';
colors.blue = '#5789ff';
colors.lightBlue = color(colors.blue).setAlpha(.8);
colors.offWhite = '#fafafa';
colors.lightGray = '#e7eaeb';

font.family = 'Heebo, Helvetica, Arial, sans-serf';
font.color = colors.primary;
heading.family = font.family;
heading.weight = 500;

icon.checkmark = 'ea10';
icon.cart = 'e93a';

module.exports = register(v);

const register = require('postcss-variables/lib/register');
let v = require('wee-core/styles/variables');
let { colors, font, heading, icon } = require('wee-core/styles/variables');
let color = require('tinycolor2');

// Add and overwrite variables here
// Example - v.colors.primary = '#58a324';

colors.primary = '#111';
colors.blue = '#5789ff';
colors.lightBlue = color(colors.blue).setAlpha(.8);
colors.offWhite = '#fafafa';
colors.lightGray = '#e7eaeb';

font.family = 'Heebo, Helvetica, Arial, sans-serf';
font.color = colors.primary;
heading.family = font.family;
heading.weight = 500;

icon.checkmark = 'ea10';
icon.cart = 'e93a';

icon.family = 'icomoon';

module.exports = register(v);

Update icon font name to ‘icomoon’


angular.module('snap')
  .directive('snapToggle', function() {
      'use strict';
      return function (scope, element, attrs) {
        element.bind('click', function() {
            if (scope.snapper !== undefined) {
              if (attrs.snapToggle) {
                scope.snapper.toggle(attrs.snapToggle);
              } else {
                scope.snapper.toggle('left');
              }
            }
        });
      };
  });

angular.module('snap')
  .directive('snapToggle', function() {
      'use strict';
      return {
        restrict: 'A',
        link: function (scope, element, attrs) {
          element.bind('click', function() {
              if (scope.snapper !== undefined) {
                if (attrs.snapToggle) {
                  scope.snapper.toggle(attrs.snapToggle);
                } else {
                  scope.snapper.toggle('left');
                }
              }
          });
        }
      };
  });

Make required attribute status explicit


import frames from '../../../sprite-frames';
import { centerOfObject } from '../../../utils';

import Tree from '../../../sprites/Tree';
import Generator from '../../../sprites/Generator';

export default function addObjects() {
  this.objects = {
    trees: [],
    generators: [],
  };

  trees.call(this);
  generators.call(this);
}

function trees() {
  const treesArr = this.map.objects.trees;
  for (let i = 0, len = treesArr.length; i < len; i++) {
    const treeStart = centerOfObject(treesArr[i], this.map);

    const tree = new Tree({
      game: this.game,
      x: treeStart.x,
      y: treeStart.y,
    });

    this.objects.trees.push(tree);

    this.game.add.existing(tree);
  }
}
function generators() {
  const genArr = this.map.objects.generators;
  for (let i = 0, len = genArr.length; i < len; i++) {
    const genStart = centerOfObject(genArr[i], this.map);

    const generator = new Generator({
      game: this.game,
      x: genStart.x,
      y: genStart.y,
    });

    this.objects.generators.push(generator);

    this.game.add.existing(generator);
  }
}

import frames from '../../../sprite-frames';
import { centerOfObject } from '../../../utils';

import Tree from '../../../sprites/Tree';
import Generator from '../../../sprites/Generator';

export default function addObjects() {
  this.objects = {
    trees: [],
    generators: [],
  };

  objects = objects.bind(this);

  objects('trees', Tree);
  objects('generators', Generator);
}

function objects(name, objectClass) {
  const arr = this.map.objects[name];
  for (let i = 0, len = arr.length; i < len; i++) {
    const start = centerOfObject(arr[i], this.map);

    const object = new objectClass({
      game: this.game,
      x: start.x,
      y: start.y,
    });

    this.objects[name].push(object);

    this.game.add.existing(object);
  }
}

Make generic function to add object to world


define([
	'modules/MainMenu/src/MainMenuModel',
	'modules/MainMenu/src/MainMenuController',
	'modules/MainMenu/src/MainMenuView',
	'modules/Harmonizer/src/HarmonizerController',
	'modules/Harmonizer/src/HarmonizerView',
], function(MainMenuModel, MainMenuController, MainMenuView, HarmonizerController, HarmonizerView) {
	return {
		run: function() {
			test("MainMenuController", function(assert) {
				var menu = new MainMenuModel();

				var menuView = new MainMenuView(menu, document.getElementsByTagName('body')[0]);

				var mmc = new MainMenuController(menu, menuView);
				assert.ok(mmc instanceof MainMenuController);

				$.subscribe('MainMenuView-ready', function(el) {
					var hv = new HarmonizerView($('#main_menu_second_level')[0]);
					var hc = new HarmonizerController(undefined,hv);
					menu.addMenu({title:'Harmonizer', view: hv});
				});

			});
		}
	};
});

define([
	'modules/MainMenu/src/MainMenuModel',
	'modules/MainMenu/src/MainMenuController',
	'modules/MainMenu/src/MainMenuView',
	'modules/Harmonizer/src/HarmonizerController',
	'modules/Harmonizer/src/HarmonizerView',
], function(MainMenuModel, MainMenuController, MainMenuView, HarmonizerController, HarmonizerView) {
	return {
		run: function() {
			test("MainMenuController", function(assert) {
				var menu = new MainMenuModel();

				var menuView = new MainMenuView(menu, document.getElementsByTagName('body')[0]);

				var mmc = new MainMenuController(menu, menuView);
				assert.ok(mmc instanceof MainMenuController);

				/*$.subscribe('MainMenuView-ready', function(el) {
					var hv = new HarmonizerView($('#main_menu_second_level')[0]);
					var hc = new HarmonizerController(undefined,hv);
					menu.addMenu({title:'Harmonizer', view: hv});
				});*/

			});
		}
	};
});

Remove menu test that display menu


/**
 * Consider:
 *
 *    .a {
 *      margin: 0 5px 0 0;
 *    }
 *
 *    .a {
 *      margin: 0;
 *    }
 *
 * Would be converted to:
 *
 *    html[dir='ltr'] .a {
 *      margin: 0 5px 0 0;
 *    }
 *
 *    html[dir='rtl'] .a {
 *      margin: 0 0 0 5px;
 *    }
 *
 *    .a {
 *       margin: 0;
 *    }
 *
 * As the "html[dir] .a" will have more specificity,
 * "margin: 0" will be ignored. That's why we must
 * convert the following properties *always*, regardless
 * of the value.
 *
 *
 */
module.exports = [
    'background',
    'background-position',
    'background-position-x',
    'border',
    'border-color',
    'border-radius',
    'border-style',
    'border-width',
    'border-top',
    'border-right',
    'border-bottom',
    'border-left',
    'box-shadow',
    'margin',
    'padding',
    'text-shadow',
    'text-align',
    'transform',
    'transform-origin'
].join('|');

/**
 * Consider:
 *
 *    .a {
 *      margin: 0 5px 0 0;
 *    }
 *
 *    .a {
 *      margin: 0;
 *    }
 *
 * Would be converted to:
 *
 *    html[dir='ltr'] .a {
 *      margin: 0 5px 0 0;
 *    }
 *
 *    html[dir='rtl'] .a {
 *      margin: 0 0 0 5px;
 *    }
 *
 *    .a {
 *       margin: 0;
 *    }
 *
 * As the "html[dir] .a" will have more specificity,
 * "margin: 0" will be ignored. That's why we must
 * convert the following properties *always*, regardless
 * of the value.
 *
 *
 */
module.exports = [
    'background',
    'background-position',
    'background-position-x',
    'border',
    'border-color',
    'border-radius',
    'border-style',
    'border-width',
    'border-top',
    'border-right',
    'border-bottom',
    'border-left',
    'box-shadow',
    'float',
    'margin',
    'padding',
    'text-shadow',
    'text-align',
    'transform',
    'transform-origin'
].join('|');

Add `float` to always convert list


import { fromJS, Record, List } from 'immutable';
import { createReducer } from 'reduxsauce';

import { teamsActionsTypes } from './teams.actions';

const StateRecord = new Record({
  list: List(),
  rangeValues: fromJS({
    min: 0,
    max: 600,
  }),
});

const INITIAL_STATE = new StateRecord();

const getSuccessHandler = (state = INITIAL_STATE, action) => state.set('list', fromJS(action.payload.teams));
const setRangeValues = (state = INITIAL_STATE, action) => state.set('rangeValues', fromJS(action.values));

const HANDLERS = {
  [teamsActionsTypes.GET_TEAMS_SUCCESS]: getSuccessHandler,
  [teamsActionsTypes.SET_RANGE_VALUES]: setRangeValues,
};

export default createReducer(INITIAL_STATE, HANDLERS);

import { fromJS, Record, List } from 'immutable';
import { createReducer } from 'reduxsauce';

import { teamsActionsTypes } from './teams.actions';

const StateRecord = new Record({
  list: List(),
  rangeValues: fromJS({
    min: 0,
    max: 600,
  }),
  error: null,
});

const INITIAL_STATE = new StateRecord();

const teamsSuccess = (state = INITIAL_STATE, action) => state.set('list', fromJS(action.payload.teams));
const teamsError = (state = INITIAL_STATE, action) => state.set('error', action.payload.error);
const rangeValuesSuccess = (state = INITIAL_STATE, action) => state.set('rangeValues', fromJS(action.values));

const HANDLERS = {
  [teamsActionsTypes.GET_TEAMS_SUCCESS]: teamsSuccess,
  [teamsActionsTypes.SET_RANGE_VALUES]: rangeValuesSuccess,
  [teamsActionsTypes.GET_TEAMS_ERORR]: teamsError,
};

export default createReducer(INITIAL_STATE, HANDLERS);

Add team fetching error handling


const webpack = require('webpack')

const plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    __DEV__: process.env.NODE_ENV === 'development',
    __TEST__: process.env.NODE_ENV === 'test'
  })
]

if (process.env.NODE_ENV === 'production') {
  plugins.push(new webpack.optimize.UglifyJsPlugin())
}

module.exports = {
  output: {
    library: 'cssVendor',
    libraryTarget: 'umd'
  },
  plugins: plugins,
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        test: /\.js$/,
        exclude: /node_modules/
      }, {
        loader: 'json-loader',
        test: /\.json$/
      }
    ]
  },
  node: {
    fs: "empty",
  }
}

const webpack = require('webpack')

const plugins = [
  new webpack.DefinePlugin({
    'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    __DEV__: process.env.NODE_ENV === 'development',
    __TEST__: process.env.NODE_ENV === 'test'
  })
]

if (process.env.NODE_ENV === 'production') {
  plugins.push(new webpack.optimize.UglifyJsPlugin())
}

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'dist/bundle.js',
    library: 'cssVendor',
    libraryTarget: 'umd'
  },
  plugins,
  module: {
    loaders: [
      {
        loader: 'babel-loader',
        test: /\.js$/,
        exclude: /node_modules/
      }, {
        loader: 'json-loader',
        test: /\.json$/
      }
    ]
  },
  node: {
    fs: 'empty',
  }
}

Update webpack to 3rd version


var webpack = require( 'webpack' );

module.exports = {
    entry: [
      'webpack-dev-server/client?http://localhost:8080',
      'webpack/hot/only-dev-server',
      './src/index.jsx'
    ],
    module: {
        loaders: [ {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            loader: 'react-hot!babel'
    } ]
    },
    resolve: {
        extensions: [ '', '.js', '.jsx' ]
    },
    output: {
        path: __dirname + '/dest',
        publicPath: '/',
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: './dest',
        hot: true
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
  ]
};

var webpack = require( 'webpack' );

module.exports = {
    entry: [
      'webpack-dev-server/client?http://localhost:8080',
      'webpack/hot/only-dev-server',
      './src/index'
    ],
    module: {
        loaders: [ {
            test: /\.jsx?$/,
            exclude: /node_modules/,
            loaders: [ 'react-hot', 'babel' ]
    } ]
    },
    resolve: {
        extensions: [ '', '.js', '.jsx' ]
    },
    output: {
        path: __dirname + '/dest',
        publicPath: '/',
        filename: 'bundle.js'
    },
    devServer: {
        contentBase: './dest',
        hot: true
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin()
  ]
};

Use lists, not delimited strings


// @flow

declare type Selector = string | Component

declare interface WrapperInterface { // eslint-disable-line no-undef
        computed(): Object;
        contains(selector: Selector): boolean;
        data(): Object;
        destroy(): void;
        dispatch(event: string): void;
        hasAttribute(attribute: string, value: string): boolean;
        hasClass(className: string): boolean;
        hasStyle(style: string, value: string): boolean;
        find(selector: Selector): WrapperType;
        html(): string;
        instance(): Component;
        is(selector: Selector): boolean;
        isEmpty(): boolean;
        methods(): Object;
        name(): string;
    propsData(): Object,
        text(): string;
        setData(data: Object): void;
        setProps(data: Object): void;
        simulate(event: string): void;
        style(): Object;
        trigger(type: string, options: Object): void;
        update(): void;
}

Fix formatting in WrapperInterface declaration


module.exports = {
    entry: {
        app: './src/init.js'
    },
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: { presets: [ 'es2015', 'react' ] }
        },
        {
            test: /\.css$/,
            loader: 'style-loader!css-loader'
        }]
    },
    devtool: 'source-map'
};

module.exports = {
    entry: {
        app: __dirname + '/src/init.js'
    },
    output: {
        path: __dirname + '/dist',
        filename: 'bundle.js'
    },
    module: {
        loaders: [{
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel',
            query: { presets: [ 'es2015', 'react' ] }
        },
        {
            test: /\.css$/,
            loader: 'style-loader!css-loader'
        }]
    },
    devtool: 'source-map'
};

Use __dirname for source dir


define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(resource) {
    var dataDV = new DataView(resource.data.buffer, resource.data.byteOffset, resource.data.byteLength);
    var textPos = dataDV.getUint32(0, false);
    var textLen = dataDV.getUint32(4, false);
    var num3 = dataDV.getUint32(8, false); // TODO: what is this
    resource.text = macintoshRoman(resource.data, textPos, textLen);
  };

});

define(['mac/roman'], function(macintoshRoman) {

  'use strict';

  return function(item) {
    return item.getBytes().then(function(bytes) {
      var dataDV = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
      var textPos = dataDV.getUint32(0, false);
      var textLen = dataDV.getUint32(4, false);
      var num3 = dataDV.getUint32(8, false); // TODO: what is this
      item.text = macintoshRoman(bytes, textPos, textLen);
    });
  };

});

Update STXT to new loader format


import Component from '@ember/component';

function createEvent(name) {
  let event = document.createEvent('Event');
  event.initEvent(name, true, true);
  return event;
}

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

  didInsertElement() {
    loadJsApi()
      .then(api => loadCoreChart(api))
      .then(() => {
        window.googleChartsLoaded = true;
        document.dispatchEvent(createEvent('googleChartsLoaded'));
      });
  },
});

async function loadScript(src) {
  await new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.onload = resolve;
    script.onerror = reject;
    document.body.appendChild(script);
  });
}

async function loadJsApi() {
  await loadScript('https://www.google.com/jsapi');
  return window.google;
}

async function loadCoreChart(api) {
  await new Promise(resolve => {
    api.load('visualization', '1.0', {
      packages: ['corechart'],
      callback: resolve,
    });
  });
}

import Component from '@ember/component';

function createEvent(name) {
  let event = document.createEvent('Event');
  event.initEvent(name, true, true);
  return event;
}

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

  didInsertElement() {
    loadJsApi()
      .then(api => loadCoreChart(api))
      .then(() => {
        window.googleChartsLoaded = true;
        document.dispatchEvent(createEvent('googleChartsLoaded'));
      });
  },
});

async function loadScript(src) {
  await new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.onload = resolve;
    script.onerror = reject;
    document.body.appendChild(script);
  });
}

async function loadJsApi() {
  if (!window.google) {
    await loadScript('https://www.google.com/jsapi');
  }
  return window.google;
}

async function loadCoreChart(api) {
  await new Promise(resolve => {
    api.load('visualization', '1.0', {
      packages: ['corechart'],
      callback: resolve,
    });
  });
}

Load Google JS API only if not already present on the page


var CKEDITOR_BASEPATH = '/assets/ckeditor/';
CKEDITOR.config.ignoreEmptyParagraph = false;
CKEDITOR.config.allowedContent = true;
CKEDITOR.config.baseHref = '/assets/ckeditor/';
CKEDITOR.config.height = 400;
CKEDITOR.config.width = '95.5%';
CKEDITOR.config.toolbarStartupExpanded = false;
CKEDITOR.config.toolbarGroups = [
  { name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
  { name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
  { name: 'editing', groups: [ 'find', 'selection', 'spellchecker' ] },
  '/',
  { name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
  { name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align' ] },
  { name: 'links' },
  { name: 'insert' },
  '/',
  { name: 'styles' },
  { name: 'colors' },
  { name: 'tools' },
  { name: 'others' }
];

Fix for ckeditor in dev


import sanitizeHtml from 'sanitize-html';
import { Utils } from '../modules';
import { throwError } from './errors.js';

Utils.sanitize = function(s) {
  return sanitizeHtml(s, {
    allowedTags: [
      'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul',
      'ol', 'nl', 'li', 'b', 'i', 'strong', 'em', 'strike',
      'code', 'hr', 'br', 'div', 'table', 'thead', 'caption',
      'tbody', 'tr', 'th', 'td', 'pre', 'img'
    ]
  });
};

Utils.performCheck = (operation, user, checkedObject, context, documentId, operationName, collectionName) => {

  if (!operation) {
    throwError({ id: 'app.no_permissions_defined', data: { documentId, operationName } });
  }

  if (!checkedObject) {
    throwError({ id: 'app.document_not_found', data: { documentId, operationName } });
  }

  if (!operation(user, checkedObject, context)) {
    throwError({ id: 'app.operation_not_allowed', data: { documentId, operationName } });
  }

};

export { Utils };

import sanitizeHtml from 'sanitize-html';
import { Utils } from '../modules';
import { throwError } from './errors.js';

Utils.sanitize = function(s) {
  return sanitizeHtml(s, {
    allowedTags: [
      'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul',
      'ol', 'nl', 'li', 'b', 'i', 'strong', 'em', 's', 'del', 'ins',
      'code', 'hr', 'br', 'div', 'table', 'thead', 'caption',
      'tbody', 'tr', 'th', 'td', 'pre', 'img'
    ]
  });
};

Utils.performCheck = (operation, user, checkedObject, context, documentId, operationName, collectionName) => {

  if (!operation) {
    throwError({ id: 'app.no_permissions_defined', data: { documentId, operationName } });
  }

  if (!checkedObject) {
    throwError({ id: 'app.document_not_found', data: { documentId, operationName } });
  }

  if (!operation(user, checkedObject, context)) {
    throwError({ id: 'app.operation_not_allowed', data: { documentId, operationName } });
  }

};

export { Utils };

Update to current valid strikethrough tags


import { remote } from 'electron';

const window = remote.getCurrentWindow();

window.on('app-command', (e, cmd) => {
  if (cmd === 'browser-backward') {
    remote.getCurrentWebContents().goBack();
  } else if (cmd === 'browser-forward') {
    remote.getCurrentWebContents().goForward();
  }
});

import { remote } from 'electron';

const bWindow = remote.getCurrentWindow();

window.addEventListener('beforeunload', bWindow.removeAllListeners());
bWindow.on('app-command', (e, cmd) => {
  if (cmd === 'browser-backward') {
    remote.getCurrentWebContents().goBack();
  } else if (cmd === 'browser-forward') {
    remote.getCurrentWebContents().goForward();
  }
});

Fix silly garbage handling issues


'use strict';
/**
 * angular-select-text directive
 */
angular.module('angular-select-text', []).
  directive('selectText', function ($window) {
    var selectElement;

    if ($window.document.selection) {
      selectElement = function(element) {
        var range = $window.document.body.createTextRange();
        range.moveToElementText(element[0]);
        range.select();
      };
    } else if ($window.getSelection) {
      selectElement = function(element) {
        var range = $window.document.createRange();
        range.selectNode(element[0]);
        $window.getSelection().addRange(range);
      };
    }

    return {
      restrict: 'A',
      link: function(scope, element, attrs){
        element.bind('click', function(){
          selectElement(element);
        });
      }
    };
  });

'use strict';
/**
 * angular-select-text directive
 */
angular.module('angular-select-text', []).
  directive('selectText', ['$window', function ($window) {
    var selectElement;

    if ($window.document.selection) {
      selectElement = function(element) {
        var range = $window.document.body.createTextRange();
        range.moveToElementText(element[0]);
        range.select();
      };
    } else if ($window.getSelection) {
      selectElement = function(element) {
        var range = $window.document.createRange();
        range.selectNode(element[0]);
        $window.getSelection().addRange(range);
      };
    }

    return {
      restrict: 'A',
      link: function(scope, element, attrs){
        element.bind('click', function(){
          selectElement(element);
        });
      }
    };
  }]);

Revert "Revert "use strict dependency injection""


"use strict";

var use = require("alamid-plugin/use.js");

var path = require("path"),
    argv = require("minimist")(process.argv.slice(2));

function dynamicConfig(basePath, fileName) {

    var env = dynamicConfig.getEnv(),
        filePath = dynamicConfig.getFilePath(basePath, env, fileName),
        config;

    if (dynamicConfig.options.log) {
        console.log("Loading configuration '" + fileName + "'  from path '" + filePath + "'");
    }

    config = dynamicConfig.loadConfig(filePath);

    dynamicConfig.resolvedConfigPath = filePath;

    return config;
}

dynamicConfig.getEnv = function() {
    return argv.env || argv.ENV || process.env.env || dynamicConfig.options.defaultEnv;
};

dynamicConfig.getFilePath = function(basePath, env, fileName) {
    return path.join(basePath, env, fileName);
};

dynamicConfig.loadConfig = function(filePath) {
    var config;

    try {
        config = require(filePath);
    }
    catch (err) {

        //handle only not found errors, throw the rest
        if (err.code === "MODULE_NOT_FOUND") {
            throw new Error("Config not found at '" + filePath + "'");
        }

        throw err;
    }

    return config;
};

dynamicConfig.options = {
    defaultEnv: "develop",
    log: false
};

dynamicConfig.use = use;

module.exports = dynamicConfig;

"use strict";

var use = require("alamid-plugin/use.js");

var path = require("path"),
    argv = require("minimist")(process.argv.slice(2));

function dynamicConfig(basePath, fileName) {

    var env = dynamicConfig.getEnv(),
        filePath = dynamicConfig.getFilePath(basePath, env, fileName),
        config;

    if (dynamicConfig.options.log) {
        console.log("Loading configuration '" + fileName + "'  from path '" + filePath + "'");
    }

    config = dynamicConfig.loadConfig(filePath);

    dynamicConfig.resolvedConfigPath = filePath;

    return config;
}

dynamicConfig.getEnv = function() {
    return argv.env || argv.ENV || process.env.env || process.env.ENV || dynamicConfig.options.defaultEnv;
};

dynamicConfig.getFilePath = function(basePath, env, fileName) {
    return path.join(basePath, env, fileName);
};

dynamicConfig.loadConfig = function(filePath) {
    var config;

    try {
        config = require(filePath);
    }
    catch (err) {

        //handle only not found errors, throw the rest
        if (err.code === "MODULE_NOT_FOUND") {
            throw new Error("Config not found at '" + filePath + "'");
        }

        throw err;
    }

    return config;
};

dynamicConfig.options = {
    defaultEnv: "develop",
    log: false
};

dynamicConfig.use = use;

module.exports = dynamicConfig;

Add process.env.ENV to getEnv() method


// Based on http://www.html5rocks.com/en/tutorials/workers/basics/
define(function() {
    var URL = window.URL || window.webkitURL
    // BlobBuilder is deprecated but Chrome for Android fails with an "Illegal constructor"
    // instantiating the Blob directly
    var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder
    if (URL && Worker && Blob && BlobBuilder) {
        var blobBuilder = new BlobBuilder
        blobBuilder.append('self.onmessage = function(event) { setInterval(function() { self.postMessage({}) }, event.data.interval) }')
        var blob = blobBuilder.getBlob('text/javascript')
        var blobUrl = URL.createObjectURL(blob)
        return function(callback, interval) {
            var worker = new Worker(blobUrl)
            worker.addEventListener('message', callback)
            worker.postMessage({interval: interval})
        }
    }

    console.warn("Worker or Blob not available, falling back to setInterval()")
    return setInterval
})

// Based on http://www.html5rocks.com/en/tutorials/workers/basics/
define(function() {
    var URL = window.URL || window.webkitURL
    if (URL && Worker && Blob) {
        var blobUrl = URL.createObjectURL(new Blob(
            ['self.onmessage = function(event) { setInterval(function() { self.postMessage({}) }, event.data.interval) }'],
            {type: 'text/javascript'}
        ))
        return function(callback, interval) {
            var worker = new Worker(blobUrl)
            worker.addEventListener('message', callback)
            worker.postMessage({interval: interval})
        }
    }

    console.warn("Worker or Blob not available, falling back to setInterval()")
    return setInterval
})

Revert "Use BlobBuilder (supported by Chrome for Android)"


define([
  'jquery',
  'underscore',
  'backbone',
  'models/project/ProjectModel'
], function($, _, Backbone, ProjectModel){
  var ProjectsCollection = Backbone.Collection.extend({
    model: ProjectModel,
    url: 'api/projects',
    models: [],

    initialize: function(){
    },

    fetchSuccess: function(collection, response) {
      this.models = collection.models;
    },

    fetchError: function(collection, response) {
      throw new Error("Projects fetch error");
    },

    parse: function(response) {
      return response ? response.data : [];
    }

  });

  return ProjectsCollection;
});

define([
  'jquery',
  'underscore',
  'backbone',
  'models/project/ProjectModel'
], function($, _, Backbone, ProjectModel){
  var ProjectsCollection = Backbone.Collection.extend({
    model: ProjectModel,
    url: 'api/projects',
    models: [],

    initialize: function(){
    },

    fetchSuccess: function(collection, response) {
      this.models = collection.models;
    },

    fetchError: function(collection, response) {
      throw new Error("Projects fetch error");
    },

    parse: function(response) {
        console.log(response);
        return response ? response.data : [];
    }

  });

  return ProjectsCollection;
});

Mark where to add pagination in projects


/* Popup initialization */
import { createUIStore } from 'redux-webext';
import addEventListeners from './event-listeners';
import { populateTabList } from './dom-utils';

// Add a key containing adding the current windowId to the popup.
const windowIdPromise = browser.windows.getCurrent()
  .then(({ id }) => ({ windowId: id }));
// Adds a key 'windowId' to the store object.
// Store object is now -> { dispatch, getState, subscribe, windowId }
const mergeStoreWithWindowId = promiseArray =>
  promiseArray.reduce((acc, obj) => Object.assign({}, acc, obj));

Promise.all([createUIStore(), windowIdPromise])
  .then(mergeStoreWithWindowId)
  .then(populateTabList)
  .then(addEventListeners)
  .catch((e) => {
    console.error(e);
    throw new Error('Ran into a problem initializing popup window.');
  });

/* Popup initialization */
import { createUIStore } from 'redux-webext';
import addEventListeners from './event-listeners';
import { populateTabList } from './dom-utils';

// Add a key containing adding the current windowId to the popup.
const windowIdPromise = browser.windows.getCurrent()
  .then(({ id }) => ({ currentWindowId: id }));
// Adds a key 'windowId' to the store object.
// Store object is now -> { dispatch, getState, subscribe, currentWindowId }
const mergeObjects = arr => arr.reduce((acc, obj) => Object.assign({}, acc, obj));

Promise.all([createUIStore(), windowIdPromise]).then(mergeObjects)
  .then(populateTabList)
  .then(addEventListeners)
  .catch((e) => {
    console.error(e);
    throw new Error('Ran into a problem initializing popup window.');
  });

Add currentWindowId to store object


/**
 * Secret View
 *
 * @copyright (c) 2018 Passbolt SARL
 * @licence AGPL-3.0 http://www.gnu.org/licenses/agpl-3.0.en.html
 */

"use strict";
var AppView = require('../appView.js');

class UserGetView extends AppView {

  constructor (data) {
    super();
    this.data = [];
    var u;

    u = data.body;

    this.data[0] = {
      'first name': u.Profile.first_name,
      'last name': u.Profile.last_name,
      'username': u.User.username,
      'fingerprint': u.Gpgkey.fingerprint,
      'UUID': u.User.id
    };
  }

  render() {
    console.log(this.columnify(this.data, {
      minWidth: 20,
      columns: ['first name', 'last name', 'username', 'fingerprint', 'UUID'],
      config: {
        'username' : {maxWidth: 64}
      }
    }));
  }
}
module.exports = UserGetView;

/**
 * Secret View
 *
 * @copyright (c) 2018 Passbolt SARL
 * @licence AGPL-3.0 http://www.gnu.org/licenses/agpl-3.0.en.html
 */

"use strict";
var AppView = require('../appView.js');

class UserGetView extends AppView {

  constructor (data) {
    super();
    this.data = [];

    this.user = data.body;

    this.data[0] = {
      'first name': this.user.Profile.first_name,
      'last name': this.user.Profile.last_name,
      'username': this.user.User.username,
      'fingerprint': this.user.Gpgkey.fingerprint,
      'UUID': this.user.User.id
    };
  }

  render() {
    console.log(this.columnify(this.data, {
      minWidth: 20,
      columns: ['first name', 'last name', 'username', 'fingerprint', 'UUID'],
      config: {
        'username' : {maxWidth: 64}
      }
    }));
    console.log('');
    console.log(this.user.Gpgkey.armored_key);
  }
}
module.exports = UserGetView;

Add display user public key


import { runAndGetResult, expectResultTypes, parts } from '../tools';

describe('After Purchase Blocks', () => {
    let result;

    beforeAll(done => {
        runAndGetResult(
            undefined,
            `
      ${parts.waitToPurchase}
      ${parts.waitToSell}
      result.isWin = Bot.isResult('win');
      result.detail = Bot.readDetails(1);
    `
        ).then(v => {
            result = v;
            done();
        });
    });

    it('After purchase api', () => {
        expectResultTypes(result, [
            'boolean', // is result win
            'string', // statement
        ]);
    });
});

import { runAndGetResult, expectResultTypes, parts } from '../tools';

describe('After Purchase Blocks', () => {
    let result;

    beforeAll(done => {
        runAndGetResult(
            undefined,
            `
      ${parts.waitToPurchase}
      ${parts.waitToSell}
      result.isWin = Bot.isResult('win');
      result.detail = Bot.readDetails(1);
    `
        ).then(v => {
            result = v;
            done();
        });
    });

    it('After purchase api', () => {
        expectResultTypes(result, [
            'boolean', // is result win
            'number', // statement
        ]);
    });
});

Change contract detail data type from string to number


import React, {Component} from 'react'
import {IndexLink, Link} from 'react-router'
import styles from '../sass/Navbar'

class Navbar extends Component {
    constructor() {
        super()
    }

    render() {
        return (
            <nav className={styles.navbar}>
                <IndexLink className={styles.link} activeClassName={styles.active} to="">home</IndexLink>
                <Link className={styles.link} activeClassName={styles.active} to="explore">explore</Link>
                <Link className={styles.link} activeClassName={styles.active} to="about">about</Link>
            </nav>
        )
    }
}

export default Navbar

import React, {Component} from 'react'
import {IndexLink, Link} from 'react-router'
import styles from '../sass/Navbar'

class Navbar extends Component {
    constructor() {
        super()
    }

    render() {
        return (
            <nav className={styles.navbar}>
                <IndexLink className={styles.link} activeClassName={styles.active} to="/">home</IndexLink>
                <Link className={styles.link} activeClassName={styles.active} to="explore">explore</Link>
                <Link className={styles.link} activeClassName={styles.active} to="about">about</Link>
            </nav>
        )
    }
}

export default Navbar

Fix IndexLink component without href value can't be a link


import createStoreShape from '../utils/createStoreShape';

export default function createProvider(React) {
  const { Component, PropTypes } = React;
  const storeShape = createStoreShape(PropTypes);

  return class Provider extends Component {
    static childContextTypes = {
      store: storeShape.isRequired
    };

    static propTypes = {
      children: PropTypes.func.isRequired
    };

    getChildContext() {
      return { store: this.state.store };
    }

    constructor(props, context) {
      super(props, context);
      this.state = { store: props.store };
    }

    componentWillReceiveProps(nextProps) {
      const { store } = this.state;
      const { store: nextStore } = nextProps;

      if (store !== nextStore) {
        const nextReducer = nextStore.getReducer();
        store.replaceReducer(nextReducer);
      }
    }

    render() {
      const { children } = this.props;
      return children();
    }
  };
}

import createStoreShape from '../utils/createStoreShape';

export default function createProvider(React) {
  const { Component, PropTypes } = React;
  const storeShape = createStoreShape(PropTypes);

  return class Provider extends Component {
    static childContextTypes = {
      store: storeShape.isRequired
    };

    static propTypes = {
      children: PropTypes.func.isRequired,
      store: storeShape.isRequired
    };

    getChildContext() {
      return { store: this.state.store };
    }

    constructor(props, context) {
      super(props, context);
      this.state = { store: props.store };
    }

    componentWillReceiveProps(nextProps) {
      const { store } = this.state;
      const { store: nextStore } = nextProps;

      if (store !== nextStore) {
        const nextReducer = nextStore.getReducer();
        store.replaceReducer(nextReducer);
      }
    }

    render() {
      const { children } = this.props;
      return children();
    }
  };
}

Enforce shape of store property


function resetName() {
  if (Cookies.get('name') != null) {
    var time = new Date();
    time.setTime( time.getTime() + ( 60 * 1000 ));
    Cookies.set('name', Cookies.get('name'), { expires: time });
  }
  setInterval('resetName()', 50 * 1000);
}

$(document).ready(function() {
  resetName();
});

function updateNameExpires() {
  if (Cookies.get('name') != null) {
    var time = new Date();
    time.setTime( time.getTime() + ( 60 * 1000 ));
    Cookies.set('name', Cookies.get('name'), { expires: time });
  }
}

$(document).ready(function() {
  setInterval('updateNameExpires()', 50 * 1000);
});

Fix keep random guest name


window.c.AdminUserDetail = (function(m, _, c){
    return {
        controller: function(){
            return {
                actions: {
                    reset: {
                        property: 'user_password',
                        updateKey: 'password',
                        callToAction: 'Redefinir',
                        innerLabel: 'Nova senha de Usuário:',
                        outerLabel: 'Redefinir senha',
                        placeholder: 'ex: 123mud@r',
                        model: c.models.userDetail
                    },
                    reactivate: {
                        property: 'state',
                        updateKey: 'id',
                        callToAction: 'Reativar',
                        innerLabel: 'Tem certeza que deseja reativar esse usuário?',
                        outerLabel: 'Reativar usuário',
                        forceValue: 'deleted',
                        model: c.models.userDetail
                    }
                }
            };
        },

        view: function(ctrl, args){
            var actions = ctrl.actions,
                item = args.item,
                details = args.details;
            return m('#admin-contribution-detail-box', [
                m('.divider.u-margintop-20.u-marginbottom-20'),
                m('.w-row.u-marginbottom-30', [
                    m.component(c.AdminInputAction, {data: actions.reset, item: item}),
                    (item.deactivated_at) ?
                    m.component(c.AdminInputAction, {data: actions.reactivate, item: item}) : ''
                ]),
            ]);
        }
    };
}(window.m, window._, window.c));

window.c.AdminUserDetail = (function(m, _, c){
    return {
        controller: function(){
            return {
                actions: {
                    reset: {
                        property: 'user_password',
                        updateKey: 'password',
                        callToAction: 'Redefinir',
                        innerLabel: 'Nova senha de Usuário:',
                        outerLabel: 'Redefinir senha',
                        placeholder: 'ex: 123mud@r',
                        model: c.models.userDetail
                    },
                    reactivate: {
                        property: 'deactivated_at',
                        updateKey: 'id',
                        callToAction: 'Reativar',
                        innerLabel: 'Tem certeza que deseja reativar esse usuário?',
                        outerLabel: 'Reativar usuário',
                        forceValue: null,
                        model: c.models.userDetail
                    }
                }
            };
        },

        view: function(ctrl, args){
            var actions = ctrl.actions,
                item = args.item,
                details = args.details;
            return m('#admin-contribution-detail-box', [
                m('.divider.u-margintop-20.u-marginbottom-20'),
                m('.w-row.u-marginbottom-30', [
                    m.component(c.AdminInputAction, {data: actions.reset, item: item}),
                    (item.deactivated_at) ?
                    m.component(c.AdminInputAction, {data: actions.reactivate, item: item}) : ''
                ]),
            ]);
        }
    };
}(window.m, window._, window.c));

Set columns to reactivate component


function doEval(e) {
  $.post("/eval", { evalInput: $("#evalInput").val() } ,
                    function(response) {
    $("#display").html(response);
  })
    .done(function() {
      $("#evalInput").val("");
    });
}
$("#todoSubmitButton").click(function(e) {
  e.preventDefault();
  doEval(e);
});
$("#evalInput").keydown(function(e) {
  if (e.keyCode == 13) {
    doEval(e);
    return false;
  }
});
$(document).ready(function () {
  i = 0;
  $.each($(".taskIndex"), function(index, content) {
    $(content).text(index);
    i++;
  })
});

function drawIndices() {
  i = 0;
  $.each($(".taskIndex"), function(index, content) {
    $(content).text(index);
    i++;
  })
}
function doEval(e) {
  $.post("/eval", { evalInput: $("#evalInput").val() } ,
                    function(response) {
    $("#display").html(response);
  })
    .done(function() {
      $("#evalInput").val("");
      drawIndices();
    });
}
$("#todoSubmitButton").click(function(e) {
  e.preventDefault();
  doEval(e);
});
$("#evalInput").keydown(function(e) {
  if (e.keyCode == 13) {
    doEval(e);
    return false;
  }
});
$(document).ready(function () {
  drawIndices();
});

Fix task indices being drawn when adding new task.


import { ACTIVE_IN_INPUT } from '../../application/keyboardShortcuts.js';
import { Class } from '../../core/Core.js';
import { ButtonView } from './ButtonView.js';
import { formatKeyForPlatform } from '../../application/formatKeyForPlatform.js';
import { loc } from '../../localisation/i18n.js';

const ClearSearchButtonView = Class({
    Name: 'ClearSearchButtonView',

    Extends: ButtonView,

    positioning: 'absolute',

    baseClassName: 'v-ClearSearchButton',

    tooltip: loc('Shortcut: {value1}', formatKeyForPlatform('Ctrl-/')),

    // Alternatives are for AZERTY keyboard
    shortcut: 'Ctrl-/ Ctrl-Shift-/ Ctrl-Shift-:',
    shortcutWhenInputFocused: ACTIVE_IN_INPUT,
});

export { ClearSearchButtonView };

import { ACTIVE_IN_INPUT } from '../../application/keyboardShortcuts.js';
import { Class } from '../../core/Core.js';
import { ButtonView } from './ButtonView.js';
import { formatKeyForPlatform } from '../../application/formatKeyForPlatform.js';
import { loc } from '../../localisation/i18n.js';

const ClearSearchButtonView = Class({
    Name: 'ClearSearchButtonView',

    Extends: ButtonView,

    positioning: 'absolute',

    baseClassName: 'v-ClearSearchButton',

    tooltip: function () {
        return loc('Shortcut: {value1}', formatKeyForPlatform('Ctrl-/'));
    }.property(),

    // Alternatives are for AZERTY keyboard
    shortcut: 'Ctrl-/ Ctrl-Shift-/ Ctrl-Shift-:',
    shortcutWhenInputFocused: ACTIVE_IN_INPUT,
});

export { ClearSearchButtonView };

Move `loc` call into a computed property


{
  angular.module('meganote.signUp')
    .directive('signUp', [

      'UsersService',
      (UsersService) => {

        class SignUpController{
          constructor (){
            this.user = {};
          }
          submit(){
            UsersService.create(this.user);
          }
        }

        return {
          scope: {},
          controller: SignUpController,
          controllerAs: 'vm',
          bindToController: true,
          templateUrl:'/sign-up/sign-up.html',
        };
      }
    ]);
}

{
  angular.module('meganote.signUp')
    .directive('signUp', [

      '$state',
      'UsersService',
      ($state, UsersService) => {

        class SignUpController{
          constructor (){
            this.user = {};
          }
          submit(){
            UsersService.create(this.user)
              .then(
                () => $state.go('notes.form', { noteId: undefined })
              );
          }
        }

        return {
          scope: {},
          controller: SignUpController,
          controllerAs: 'vm',
          bindToController: true,
          templateUrl:'/sign-up/sign-up.html',
        };
      }
    ]);
}

Add state to notes when registering


angular.module("tampereCoaches", [])
	.controller("home", function($scope, $http) {
		$http.get("/resources").success(function(model) {
			$scope.greeting = model;
		});
	});

var moduleName = "tampereCoaches";
var dependencies = [
	"ngRoute";
]

angular.module(moduleName, dependencies)
	.config(function($routeProvider, $httpProvider) {
		$routeProvider.when("/", {
			templateUrl: "greetings.html",
			controller: "home"
		})
		.when("/login", {
			templateUrl: "login.html",
			controller: "nagivation"
		})
		.otherwise("/");
	})
	.controller("home", function($scope, $http) {
		$http.get("/resources").success(function(model) {
			$scope.greeting = model;
		});
	})
	.controller("navigation", function() {

	});

Update controller to match the SPA ngRoute use.


(function(){
  "use strict"
  $(document).ready(init);

  function init(){
    $(".sort").on('click', sortActivities);
    $(".user-activities").on('click', ".card", showDescription);
  }

  function sortActivities() {
    var type = $(this).text().toLowerCase(),
        $activities = $(".dashboard__activity"),
        orderedByDateActivities

    if (type == "name") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return $(a).find(".activity__name").text() > $(b).find(".activity__name").text();
      });
      $(".user-activities").empty().html(orderedByDateActivities);
    }

    else if (type == "date") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return (new Date($(a).find(".activity__date").text())) > (new Date($(b).find(".activity__date").text()));
      });
      $(".user-activities").empty().html(orderedByDateActivities);
    }

    else if (type == "venue") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return $(a).find(".activity__venue-name").text() > $(b).find(".activity__venue-name").text();
      });
      $(".user-activities").empty().html(orderedByDateActivities);
    }
  }

  function showDescription() {
    var selectedActvity = $(this).closest('.user-activity');
    var description = selectedActvity.find('.activity__description').toggleClass("hidden");
  }

})();

(function(){
  "use strict"
  $(document).ready(init);

  function init(){
    $(".sort").on('click', sortActivities);
    $(".user-activities").on('click', ".card", showDescription);
  }

  function sortActivities() {
    var type = $(this).text().toLowerCase(),
        $activities = $(".user-activity"),
        orderedByDateActivities = [];

    if (type == "name") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return $(a).find(".activity__name").text() > $(b).find(".activity__name").text();
      });
      $(".user-activities").empty().append(orderedByDateActivities);
    }

    else if (type == "date") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return (new Date($(a).find(".activity__date").text())) > (new Date($(b).find(".activity__date").text()));
      });
      $(".user-activities").empty().append(orderedByDateActivities);
    }

    else if (type == "venue") {
      orderedByDateActivities = $activities.sort(function(a,b){
        return $(a).find(".activity__venue-name").text() > $(b).find(".activity__venue-name").text();
      });
      $(".user-activities").empty().append(orderedByDateActivities);
    }
  }

  function showDescription() {
    var selectedActvity = $(this).closest('.user-activity');
    var description = selectedActvity.find('.activity__description').toggleClass("hidden");
  }

})();

Update naming convention to fix bug


import Ember from 'ember';

export default Ember.Component.extend({
  pageNumber: null,
  width: Ember.computed('pageNumber', function() {
    var width = (this.pageNumber / 11) * 100;
    return new Ember.Handlebars.SafeString('width: ' + width + '%;');
  })
});

import Ember from 'ember';

export default Ember.Component.extend({
  pageNumber: null,
  width: Ember.computed('pageNumber', function() {
    var width = (this.pageNumber / 11) * 100;
    return new Ember.String.htmlSafe('width: ' + width + '%;');
  })
});

Resolve deprecation warning for SafeString


/**
  Utility Functions
  @description a collection of utility functions, aka junk drawer
  @exports {function} isRemoteResourceAction
  @exports {function} isCacheableRequest
  @exports {function} isPromise
**/

import RemoteResource from '../lib/RemoteResource';

/**
  @name isRemoteResourceAction
  @desc determines if an action should be processed by this middleware or not
    by checking that the action contains the RemoteResource Symbol
  @param {object} action
  @returns {boolean} isValid
**/
export function isRemoteResourceAction(action) {
  return (
    action && action.hasOwnProperty
    && (action.hasOwnProperty(RemoteResource) || !!action[RemoteResource])
  );
}

/**
  @name isCacheableRequest
  @desc determines if the request is cacheable based on HTTP verb used,
    will return false for actionable HTTP verbs like POST or DELETE
  @param {string} httpMethod
  @returns {boolean} result
**/
const uncacheableMethods = [ 'POST', 'PUT', 'DELETE' ];
export function isCacheableRequest(httpMethod) {
  return !~uncacheableMethods.indexOf(httpMethod.toUpperCase());
}

/**
  @name isPromise
  @desc determines if a given value is a promise
  @param {any} potentialPromise
  @returns {boolean} result
**/
export function isPromise(potentialPromise) {
  return potentialPromise && typeof potentialPromise.then === 'function' &&
    typeof potentialPromise['catch'] === 'function'; // eslint-disable-line
}

/**
  Utility Functions
  @description a collection of utility functions, aka junk drawer
  @exports {function} isRemoteResourceAction
  @exports {function} isCacheableRequest
  @exports {function} isPromise
**/

import RemoteResource from '../lib/RemoteResource';

/**
  @name isRemoteResourceAction
  @desc determines if an action should be processed by this middleware or not
    by checking that the action contains the RemoteResource Symbol
  @param {object} action
  @returns {boolean} isValid
**/
export function isRemoteResourceAction(action) {
  return (
    action && action.hasOwnProperty
    && (action.hasOwnProperty(RemoteResource) || !!action[RemoteResource])
  );
}

/**
  @name isCacheableRequest
  @desc determines if the request is cacheable based on HTTP verb used,
    will return false for actionable HTTP verbs like POST or DELETE
  @param {string} httpMethod
  @returns {boolean} result
**/
const uncacheableMethods = [ 'POST', 'PUT', 'PATCH', 'DELETE' ];
export function isCacheableRequest(httpMethod) {
  return !~uncacheableMethods.indexOf(httpMethod.toUpperCase());
}

/**
  @name isPromise
  @desc determines if a given value is a promise
  @param {any} potentialPromise
  @returns {boolean} result
**/
export function isPromise(potentialPromise) {
  return potentialPromise && typeof potentialPromise.then === 'function' &&
    typeof potentialPromise['catch'] === 'function'; // eslint-disable-line
}

Add `PATCH` as an uncacheable method


"use strict";

config.$inject = [ '$stateProvider' ];

function config ($stateProvider) {

	$stateProvider
		.state('main.project', {
			url: '/proyectos/{projectId}',
			templateUrl: "templates/components/main/project/project.html",
			controller: 'ProjectController as vm',
			onEnter: onStateEnter
		});
}

let onStateEnter = [ '$rootScope',
	function (rootScope) {
		rootScope.viewTitle  = "Vinculacion | Proyecto";
    	rootScope.viewStyles = "main project";
    }
];

module.exports = config;

"use strict";

config.$inject = [ '$stateProvider' ];

function config ($stateProvider) {

	$stateProvider
		.state('main.project', {
			url: '/proyectos/?projectId',
			templateUrl: "templates/components/main/project/project.html",
			controller: 'ProjectController as vm',
			onEnter: onStateEnter
		});
}

let onStateEnter = [ '$rootScope',
	function (rootScope) {
		rootScope.viewTitle  = "Vinculacion | Proyecto";
    	rootScope.viewStyles = "main project";
    }
];

module.exports = config;

Fix url param for project


var wincmd = require('./binaries')
var exec = require('child_process').exec
var DarwinEventLogger = require('./darwin')

/**
 * EventLogger Constructor
 *
 * @param {Object|string} [config={}] Configuration
 * @param {string} [config.source='NodeJS'] Source
 * @param {string} [config.eventLog='APPLICATION'] Event Log
 */
function EventLogger (config) {
  DarwinEventLogger.call(this, config)
}
EventLogger.prototype = Object.create(DarwinEventLogger.prototype)

/**
 * Write
 *
 * @param {string} messageType Message Type
 * @param {string} message Message
 * @param {number} [code=1000] Code
 * @param {Function} [callback] Callback
 */
EventLogger.prototype.write = function (messageType, message, code, callback) {
  if (message == null) return
  if (message.trim().length === 0) return
  code = code || 1000

  var cmd = 'eventcreate /L ' + this.eventLog + ' /T ' + messageType + ' /SO "' + this.source + '" /D "' + message + '" /ID ' + code

  exec(cmd, function (err) {
    if (err && err.message.indexOf('Access is Denied')) wincmd.elevate(cmd, callback)
    else if (callback) callback(err)
  })
}

EventLogger.prototype.constructor = EventLogger
module.exports = EventLogger

// var wincmd = require('./binaries')
var spawn = require('child_process').spawn
var DarwinEventLogger = require('./darwin')

/**
 * EventLogger Constructor
 *
 * @param {Object|string} [config={}] Configuration
 * @param {string} [config.source='NodeJS'] Source
 * @param {string} [config.eventLog='APPLICATION'] Event Log
 */
function EventLogger (config) {
  DarwinEventLogger.call(this, config)
}
EventLogger.prototype = Object.create(DarwinEventLogger.prototype)

/**
 * Write
 *
 * @param {string} messageType Message Type
 * @param {string} message Message
 * @param {number} [code=1000] Code
 * @param {Function} [callback] Callback
 */
EventLogger.prototype.write = function (messageType, message, code, callback) {
  if (message == null) return
  if (message.trim().length === 0) return
  code = code || 1000

  var cmd = [
    'eventcreate',
    '/L', this.eventLog,
    '/T', messageType,
    '/SO', this.source,
    '/D', message,
    '/ID', code
  ]

  const eventcreate = spawn(cmd)
  eventcreate.stdout.on('data', function (data) {
    console.log('stdout: ' + data)
  })
  eventcreate.stderr.on('data', function (data) {
    if (callback) {
      console.log(data)
      callback(data)
    }
  })
}

EventLogger.prototype.constructor = EventLogger
module.exports = EventLogger

Replace exec with spawn for Electron apps


import Registry from './Registry';
import {flow, isFunction, isString, omit} from 'lodash';

export default class DataHandler {

  /**
   * Register a new data handler using the registry.
   */
  static set(path, handler) {
    Registry.set('dataHandlers.' + path, handler);
  }

  /**
   * Retrieves a data handler given an object path.
   */
  static get(path) {
    return Registry.get('dataHandlers.' + path);
  }

  /**
   * Call all the data handlers.
   */
  static handle(hs, componentData, dashboardData, e) {
    let handlers = (hs || []).map((h) => {
      let handler = isString(h) ? { name: h } : h ;
      let funcHandler = DataHandler.get(handler.name);
      let args = omit(handler,'name');
      return funcHandler.bind(this, componentData, dashboardData, args, e);
    });

    let handle = flow(handlers);
    return (isFunction(handle)) ? handle(componentData, dashboardData) : componentData;
  }
}

import Registry from './Registry';
import {flow, isFunction, isString, omit} from 'lodash';

export default class DataHandler {

  /**
   * Register a new data handler using the registry.
   */
  static set(path, handler) {
    Registry.set('dataHandlers.' + path, handler);
  }

  /**
   * Retrieves a data handler given an object path.
   */
  static get(path) {
    return Registry.get('dataHandlers.' + path);
  }

  /**
   * Call all the data handlers
   *
   * @@TODO - we should catch failures here and
   * @@TODO - provide meaningful error messages
   */
  static handle(hs, componentData, dashboardData, e) {
    try {
      let handlers = (hs || []).map((h) => {
        console.log('DH', arguments, h);
        let handler = isString(h) ? { name: h } : h ;
        let funcHandler = DataHandler.get(handler.name);
        let args = omit(handler,'name');
        return funcHandler.bind(this, componentData, dashboardData, args, e);
      });

      let handle = flow(handlers);
      return (isFunction(handle)) ? handle(componentData, dashboardData) : componentData;
    } catch (e) {
      console.error("Error in data handler. This could mean that one of your data handlers is missing from the registry. Here are the handlers we're trying to process:", e, arguments);
    }
  }
}

Add a dumb catch to the data handlers handle call