import React, { Component } from 'react';
import jQuery from 'jquery';
import wut from 'wut.css';

export default class App extends Component {
    render() {
        return
NO!!This is MY APP!!!!! How ?Where Who Wut now? OMG!!

    }
}

import React, { Component } from 'react';
import jQuery from 'jquery';
import wut from 'wut.css';

export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 1
        };
    }
    componentDidMount() {
        setInterval(() => {
            this.setState({ counter: this.state.counter + 1 });
        }, 1000);
    }

    render() {
        return (

Counter: {this.state.counter}

        )
    }
}

Add state to provide that the hot reload is working with state retention


import d3 from 'd3';
import fcRebind from 'd3fc-rebind';
import {getStockFluxData} from '../../../../../../node_modules/stockflux-core/src/services/StockFluxService';

export default function() {
    var historicFeed = getStockFluxData(),
        granularity,
        candles;

    var allowedPeriods = d3.map();
    allowedPeriods.set(60 * 60 * 24, 'daily');
    allowedPeriods.set(60 * 60 * 24 * 7, 'weekly');

    var stockFluxAdaptor = function stockFluxAdaptor(cb) {
        var startDate = new Date();
        historicFeed.start(startDate);
        historicFeed(cb);
    };

    stockFluxAdaptor.candles = function(x) {
        if (!arguments.length) {
            return candles;
        }
        candles = x;
        return stockFluxAdaptor;
    };

    stockFluxAdaptor.granularity = function(x) {
        if (!arguments.length) {
            return granularity;
        }
        if (!allowedPeriods.has(x)) {
            throw new Error('Granularity of ' + x + ' is not supported.');
        }
        granularity = x;
        return stockFluxAdaptor;
    };

    stockFluxAdaptor.apiKey = function() {
        throw new Error('Not implemented.');
    };

    stockFluxAdaptor.database = function() {
        throw new Error('Not implemented.');
    };

    stockFluxAdaptor.columnNameMap = function() {
        throw new Error('Not implemented.');
    };

    fcRebind.rebindAll(stockFluxAdaptor, historicFeed);

    return stockFluxAdaptor;
}

import d3 from 'd3';
import fcRebind from 'd3fc-rebind';
import {getStockFluxData} from 'stockflux-core/src/services/StockFluxService';

export default function() {
    var historicFeed = getStockFluxData(),
        granularity,
        candles;

    var allowedPeriods = d3.map();
    allowedPeriods.set(60 * 60 * 24, 'daily');
    allowedPeriods.set(60 * 60 * 24 * 7, 'weekly');

    var stockFluxAdaptor = function stockFluxAdaptor(cb) {
        var startDate = new Date();
        historicFeed.start(startDate);
        historicFeed(cb);
    };

    stockFluxAdaptor.candles = function(x) {
        if (!arguments.length) {
            return candles;
        }
        candles = x;
        return stockFluxAdaptor;
    };

    stockFluxAdaptor.granularity = function(x) {
        if (!arguments.length) {
            return granularity;
        }
        if (!allowedPeriods.has(x)) {
            throw new Error('Granularity of ' + x + ' is not supported.');
        }
        granularity = x;
        return stockFluxAdaptor;
    };

    stockFluxAdaptor.apiKey = function() {
        throw new Error('Not implemented.');
    };

    stockFluxAdaptor.database = function() {
        throw new Error('Not implemented.');
    };

    stockFluxAdaptor.columnNameMap = function() {
        throw new Error('Not implemented.');
    };

    fcRebind.rebindAll(stockFluxAdaptor, historicFeed);

    return stockFluxAdaptor;
}

Fix relative import to be absolute


describe('Get a user to login and show dashboard:', function() {
    it('should let a user login', function() {
        driver = browser.driver;

        driver.get(browser.params.live_server_url + 'login/');

        expect(driver.getTitle()).toEqual('HelloLily | Login');

        driver.findElement(By.id('id_username')).sendKeys('user1@lily.com');
        driver.findElement(By.id('id_password')).sendKeys('testing');
        driver.findElement(By.id('id_password')).submit();

        expect(driver.getTitle()).toEqual('HelloLily | Welcome!');
    });
});

describe('Get a user to login and show dashboard:', function() {
    it('should let a user login', function() {
        driver = browser.driver;

        driver.get(browser.params.live_server_url + 'login/');

        expect(driver.getTitle()).toEqual('HelloLily | Login');

        driver.findElement(By.id('id_username')).sendKeys('user1@lily.com');
        driver.findElement(By.id('id_password')).sendKeys('testing');
        driver.findElement(By.id('id_password')).submit();

        expect(driver.getTitle()).toEqual('Dashboard - HelloLily');
    });
});

Fix end to end test


const tokenHeader = 'Sanity-Token'
const projectHeader = 'Sanity-Project-ID'

exports.getRequestOptions = config => {
  const headers = {}

  if (config.token) {
    headers[tokenHeader] = config.token
  }

  if (!config.useProjectHostname) {
    headers[projectHeader] = config.projectId
  }

  return {
    headers: headers,
    timeout: config.timeout || 15000,
    json: true
  }
}

const tokenHeader = 'Sanity-Token'
const projectHeader = 'Sanity-Project-ID'

exports.getRequestOptions = config => {
  const headers = {}

  if (config.token) {
    headers[tokenHeader] = config.token
  }

  if (!config.useProjectHostname) {
    headers[projectHeader] = config.projectId
  }

  return {
    headers: headers,
    timeout: config.timeout || 15000,
    withCredentials: true,
    json: true
  }
}

Set withCredentials flag on requests


'use strict';

var bowlingApp = angular.module('bowling', ['ngRoute']);

bowlingApp.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.otherwise({
            redirectTo: '/main'
        });
    }]);

bowlingApp.factory("dataProvider", ['$q', function ($q) {
    var dataLoaded = false;

    return {
        getData: function () {
            if (!dataLoaded) {
                var result = bowling.initialize({"root": "testdata"}, $q);
                return result.then(function (league) {
                    dataLoaded = true;
                    return league;
                });
            } else {
                return $q(function (resolve, reject) {
                    resolve(bowling.currentLeague);
                });
            }
        }
    }
}]);

'use strict';

var bowlingApp = angular.module('bowling', ['ngRoute']);

bowlingApp.config(['$routeProvider',
    function($routeProvider) {
        $routeProvider.otherwise({
            redirectTo: '/main'
        });
    }]);

bowlingApp.factory("dataProvider", ['$q', function ($q) {
    var dataLoaded = false;
    var currentPromise = null;

    return {
        getData: function () {

            if (currentPromise == null) {
                if (!dataLoaded) {
                    var result = bowling.initialize({"root": "polarbowler"}, $q);
                    currentPromise = result.then(function (league) {
                        dataLoaded = true;
                        currentPromise = null;
                        return league;
                    });
                } else {
                    return $q(function (resolve, reject) {
                        resolve(bowling.currentLeague);
                    });
                }
            }

            return currentPromise;
        }
    }
}]);

Fix issue with multiple loads


import React, { Component, PropTypes } from 'react';
import PrintIcon from 'react-icons/lib/md/print';
import Button from '../Button';

export default class PrintButton extends Component {
  shouldComponentUpdate() {
    return false;
  }

  handlePrint() {
    const d3svg = document.getElementById('d3svg');
    if (!d3svg) {
      window.print();
      return;
    }

    const g = d3svg.firstChild;
    const currTransform = g.getAttribute('transform');
    g.setAttribute('transform', 'translate(57, 10) scale(1)');
    window.print();
    g.setAttribute('transform', currTransform);
  }

  render() {
    return (
      <Button Icon={PrintIcon} onClick={this.handlePrint}>Print</Button>
    );
  }
}

import React, { Component, PropTypes } from 'react';
import PrintIcon from 'react-icons/lib/md/print';
import Button from '../Button';

export default class PrintButton extends Component {
  shouldComponentUpdate() {
    return false;
  }

  handlePrint() {
    const d3svg = document.getElementById('d3svg');
    if (!d3svg) {
      window.print();
      return;
    }

    const initHeight = d3svg.style.height;
    const initWidth = d3svg.style.width;
    const box = d3svg.getBBox();
    d3svg.style.height = box.height;
    d3svg.style.width = box.width;
    window.print();
    d3svg.style.height = initHeight;
    d3svg.style.width = initWidth;
  }

  render() {
    return (
      <Button Icon={PrintIcon} onClick={this.handlePrint}>Print</Button>
    );
  }
}

Fix printing the state graph svg


/*jslint browser: true, undef: true, white: false, laxbreak: true *//*global Ext,Slate*/
Ext.define('SlateAdmin.store.people.progress.NoteRecipients', {
    extend: 'Ext.data.Store',
    requires: [
        'SlateAdmin.model.person.progress.NoteRecipient'
    ],

    model: 'SlateAdmin.model.person.progress.NoteRecipient',
    groupField: 'RelationshipGroup',
    sorters: [{
        sorterFn: function (p1, p2) {
            if (p1.get('RelationshipGroup') != 'Other' && p2.get('RelationshipGroup') != 'Other') {
                return 0;
            }

            if (p1.get('RelationshipGroup') != 'Other') {
                return 1;
            }

            if (p2.get('RelationshipGroup') != 'Other') {
                return -1;
            }

            return -1;
        }
    }]
});

Ext.define('SlateAdmin.store.people.progress.NoteRecipients', {
    extend: 'Ext.data.Store',

    model: 'SlateAdmin.model.person.progress.NoteRecipient',
    config: {
        grouper: {

            /**
             * Higher indexes are higher priority
             */
            groupsPriority: [
                'Teachers',
                'School Contacts'
            ],

            property: 'RelationshipGroup',
            sorterFn: function (record1, record2) {
                return (
                    this.groupsPriority.indexOf(record1.get('RelationshipGroup'))
                    > this.groupsPriority.indexOf(record2.get('RelationshipGroup'))
                        ? -1
                        : 1
                );
            }
        },

        sorters: [{

            /**
             * Higher indexes are higher priority
             */
            labelsPriority: [
                'Student',
                'Advisor'
            ],

            sorterFn: function (record1, record2) {
                var label1 = record1.get('Label'),
                    label2 = record2.get('Label'),
                    labelPriority1 = this.labelsPriority.indexOf(label1),
                    labelPriority2 = this.labelsPriority.indexOf(label2);

                if (labelPriority1 == labelPriority2) {
                    if (label1 == label2) {
                        return 0;
                    }

                    return label1 < label2 ? -1 : 1;
                }

                return labelPriority1 > labelPriority2 ? -1 : 1;
            }
        }]
    }
});

Sort recipients by group/label priorities and then by label


import * as types from './ActionTypes'
import axios from 'axios'

export function addPattern(name, pattern) {
  return {
    type: types.ADD_PATTERN,
    name: name,
    pattern: pattern
  }
}

export function selectPattern(pattern) {
  return {
    type: types.SELECT_PATTERN,
    name: pattern
  }
}

export function deselectPattern(pattern) {
  return {
    type: types.DESELECT_PATTERN,
    name: pattern
  }
}

export function changeText(text) {
  return function(dispatch) {
    dispatch(requestData(text))
  }
}

function requestData() {
  return {
    type: types.REQUEST_DATA
  }
}

function receiveData(json) {
  return {
    type: types.RECEIVE_DATA,
    data: json
  }
}

function receiveError(json) {
  return {
    type: types.RECEIVE_ERROR,
    data: json
  }
}

export function evaluateText(pattern, text) {
  return function(dispatch) {
    dispatch(requestData())
    return axios.post('api.riveter.site/v1/process/', {
      pattern: pattern,
      textContent: text
    })
    .then(function(data) {
      dispatch(receiveData(data))
    })
    .catch(function(err) {
      dispatch(receiveError(err))
    })
  }
}

import * as types from './ActionTypes'
import axios from 'axios'

export function addPattern(name, pattern) {
  return {
    type: types.ADD_PATTERN,
    name: name,
    pattern: pattern
  }
}

export function selectPattern(pattern) {
  return {
    type: types.SELECT_PATTERN,
    name: pattern
  }
}

export function deselectPattern(pattern) {
  return {
    type: types.DESELECT_PATTERN,
    name: pattern
  }
}

export function changeText(text) {
  return function(dispatch) {
    dispatch(requestData(text))
  }
}

function requestData() {
  return {
    type: types.REQUEST_DATA
  }
}

function receiveData(json) {
  return {
    type: types.RECEIVE_DATA,
    data: json
  }
}

function receiveError(json) {
  return {
    type: types.RECEIVE_ERROR,
    data: json
  }
}

export function evaluateText(pattern, text) {
  return function(dispatch) {
    dispatch(requestData())
    return axios.post('http://api.riveter.site/v1/process/', {
      pattern: pattern,
      textContent: text
    })
    .then(function(data) {
      dispatch(receiveData(data))
    })
    .catch(function(err) {
      dispatch(receiveError(err))
    })
  }
}

Update URL to work correctly.


#!/usr/bin/env node
var fs = require('fs')
var path = require('path')

var cli = require('../lib/cli')

cli(process.stdin, process.stdout, process.argv.slice(2), function (err, args) {
  if (err) {
    console.error(err)
    return process.exit(1)
  }

  if (args.version) {
    var pkg = require('../package.json')
    console.log(pkg.version)

    return process.exit(1)
  } else if (args.help) {
    var help = fs.createReadStream(path.resolve(__dirname, 'help.txt'))

    help.on('end', function () {
      process.exit(1)
    })

    help.pipe(process.stderr)
  }
})

#!/usr/bin/env node
var fs = require('fs')
var path = require('path')

var cli = require('../lib/cli')

cli(process.stdin, process.stdout, process.argv.slice(2), function (err, args) {
  if (err) {
    console.error(
      'You had an error in your syntax. Please run with `--help` for usage.',
      `\n${err.message}`
    )

    return process.exit(1)
  }

  if (args.version) {
    var pkg = require('../package.json')
    console.log(pkg.version)

    return process.exit(1)
  } else if (args.help) {
    var help = fs.createReadStream(path.resolve(__dirname, 'help.txt'))

    help.on('end', function () {
      process.exit(1)
    })

    help.pipe(process.stderr)
  }
})

Update error output in CLI


var pg = require('pg');

function insertTemp(temp) {
  pg.connect(process.env.DATABASE_URL, function(err, client) {
    if (err) throw err;

    client.query('INSERT INTO temperature (date_measured, temp)' +
      'VALUES ($1,$2) RETURNING id', [new Date(), temp],
      function(err, result) {
        if (err) {
          console.log(err)
        } else {
          console.log("Insert temperature with id: " + result.rows[0].id)
        }
      });
  });
}

function getTemp(response) {
  console.log("get Temp i repo kallt");
  pg.connect(process.env.DATABASE_URL, function(err, client) {
        if (err) {
          console.log("error pa getTemp")
        }

        var query = client.query('SELECT date_measured, temp FROM temperature');
        var rows = [];

        query.on('row', function(row, result) {
            result.addRow(row);
          });

        query.on('end', function(result) {
            response.send(result.rows);
          });
        });
      }

      module.exports.insertTemp = insertTemp;
      module.exports.getTemp = getTemp;

var pg = require('pg');

function insertTemp(temp) {
  pg.connect(process.env.DATABASE_URL, function(err, client) {
    if(handleError(err)){
      console.log("error i pg connection");
      return;
    }

    client.query('INSERT INTO temperature (date_measured, temp)' +
      'VALUES ($1,$2) RETURNING id', [new Date(), temp],
      function(err, result) {
        if (err) {
          console.log(err)
        } else {
          console.log("Insert temperature with id: " + result.rows[0].id)
        }
      });
  });
}

function getTemp(response) {
  console.log("get Temp i repo kallt");
  pg.connect(process.env.DATABASE_URL, function(err, client) {
        if(handleError(err,client)) {
            console.log("error i pg connection");
            return;
        }

        var query = client.query('SELECT date_measured, temp FROM temperature');
        var rows = [];

        query.on('row', function(row, result) {
            result.addRow(row);
          });

        query.on('end', function(result) {
            response.send(result.rows);
          });
        });
      }

  function handleError(error, client) {
    // no error occurred, continue with the request
     if(!err) return false;

     // An error occurred, remove the client from the connection pool.
     // A truthy value passed to done will remove the connection from the pool
     // instead of simply returning it to be reused.
     // In this case, if we have successfully received a client (truthy)
     // then it will be removed from the pool.
     if(client){
       done(client);
     }
     res.writeHead(500, {'content-type': 'text/plain'});
     res.end('An error occurred');
     return true;
  }
      module.exports.insertTemp = insertTemp;
      module.exports.getTemp = getTemp;

Improve error handling on PG connection


import React, { Component } from 'react';

/**
 * Gets display name of the component.
 *
 * @param  {Component} WrappedComponent     React component
 * @return {String}                         Component name
 */
function getDisplayName(WrappedComponent) {
    return WrappedComponent.displayName ||
        WrappedComponent.name ||
        'Component';
}

/**
 * Connects the store to the React component.
 *
 * @example
 *     const Comp = connect(store)(MyComponent);
 *
 * @param  {Object} store      Store instance
 * @return {Function}          HOC factory function
 */
export const connect = (store) => (WrappedComponent) => {
    return class ConnectedComponent extends Component {
        static displayName = `HOC(${getDisplayName(WrappedComponent)})`;

        state = store.state;

        componentWillMount() {
            this.unsubscribe = store.subscribe(newState => {
                this.setState(newState);
            });
        }

        componentWillUnmount() {
            this.unsubscribe();
        }

        render() {
            return (
                <WrappedComponent { ...this.props } { ...this.state } />
            );
        }
    }
}

import React, { Component } from 'react';

/**
 * Gets display name of the component.
 *
 * @param  {Component} WrappedComponent     React component
 * @return {String}                         Component name
 */
function getDisplayName(WrappedComponent) {
    return WrappedComponent.displayName ||
        WrappedComponent.name ||
        'Component';
}

/**
 * Connects the store to the React component.
 *
 * @example
 *     const Comp = connect(store)(MyComponent);
 *
 * @param  {Object} store      Store instance
 * @return {Function}          HOC factory function
 */
export const connect = (store) => (WrappedComponent) => {
    return class ConnectedComponent extends Component {
        static displayName = `HOC(${getDisplayName(WrappedComponent)})`;

        state = { data: store.state };

        componentDidMount() {
            this._unsubscribe = store.subscribe(newState => {
                this.setState({ data: newState });
            });

            // handle cases where values could
            // have changed between render and mount
            if (this.state.data !== store.state) {
                this.setState({ data: store.state });
            }
        }

        componentWillUnmount() {
            this._unsubscribe && this._unsubscribe();
        }

        render() {
            return (
                <WrappedComponent {...this.props} {...this.state.data} />
            );
        }
    }
}

Update connect HOC to use proper lifecycle method


// App config the for production environment.
// Do not require this directly. Use ./src/config instead.

const HOST = process.env.HOST || "api.openfisca.fr",
  apiBaseUrl = process.env.API_URL || `https://${HOST}`,
  gitHubProject = "openfisca/openfisca-france",
  gitWebpageUrl = "https://github.com/openfisca/legislation-explorer",
  piwikConfig = {
    url: "stats.data.gouv.fr",
    siteId: 4
  },
  useCommitReferenceFromApi = true,
  websiteUrl = "https://www.openfisca.fr/"

export default {
  apiBaseUrl,
  gitHubProject,
  gitWebpageUrl,
  piwikConfig,
  useCommitReferenceFromApi,
  websiteUrl
}

// App config the for production environment.
// Do not require this directly. Use ./src/config instead.

const HOST = process.env.HOST || "api.openfisca.fr",
  apiBaseUrl = process.env.API_URL || `https://${HOST}`,
  gitHubProject = "openfisca/openfisca-france",
  gitWebpageUrl = "https://github.com/openfisca/legislation-explorer",
  piwikConfig = {
    url: "stats.data.gouv.fr",
    siteId: 4,
    trackErrors: true
  },
  useCommitReferenceFromApi = true,
  websiteUrl = "https://www.openfisca.fr/"

export default {
  apiBaseUrl,
  gitHubProject,
  gitWebpageUrl,
  piwikConfig,
  useCommitReferenceFromApi,
  websiteUrl
}

Use trackErrors option of piwik-react-router


/* export anthracite */
var anthracite = {
    // Uncomment and add your firebase URL
    // firebase : "https://<YOUR-APP-HERE>.firebaseio.com/"

    // Other config params

    // Authentication type
    // auth : "password|jwt"

    // Login URL to use for jwt logins
    // loginBaseUrl : "http://some.url.here/for/logging/in/using-jwt"

    // Disable all write actions by setting locked to true
    // locked : true|false

    // Object containing default values for crucible fields
    // defaults : {
    //     String to use as the default start time for publishing,
    //     will use midnight if not specified
    //     publish_start_time : ""
    // }
};

window.anthracite = {
    // Uncomment and add your firebase URL
    // firebase : "https://<YOUR-APP-HERE>.firebaseio.com/"

    // Other config params

    // Authentication type
    // auth : "password|jwt"

    // Login URL to use for jwt logins
    // loginBaseUrl : "http://some.url.here/for/logging/in/using-jwt"

    // Disable all write actions by setting locked to true
    // locked : true|false

    // Object containing default values for crucible fields
    // defaults : {
    //     String to use as the default start time for publishing,
    //     will use midnight if not specified
    //     publish_start_time : ""
    // }
};

Clean up example config a bit


import * as React from 'react';
import Radium from 'radium';

type SpanT = {
  span: 1 | 2 | 3 | 4 | 5 | 6,
  children: React.Node
};

const Span = ({span = 6, children}: SpanT) => {
  const style = {
    boxSizing: 'border-box',
    display: 'flex',
    flexBasis: '100%',
    // Bug fix for Firefox; width and flexBasis don't work on horizontally scrolling code blocks
    maxWidth: '100%',
    flexWrap: 'wrap',
    margin: '24px 0 0 0',
    padding: 0,
    position: 'relative',
    '@media (min-width: 640px)': {
      flexBasis: `calc(${span / 6 * 100}% - 10px)`,
      // Bug fix for Firefox; width and flexBasis don't work on horizontally scrolling code blocks
      maxWidth: `calc(${span / 6 * 100}% - 10px)`,
      margin: '24px 10px 0 0'
    }
  };
  return (
    <div style={style}>
      {children}
    </div>
  );
};

export default Radium(Span);

import React from 'react';
import Radium from 'radium';

type SpanT = {
  span: 1 | 2 | 3 | 4 | 5 | 6,
  children: React.Node
};

const Span = ({span = 6, children}: SpanT) => {
  const style = {
    boxSizing: 'border-box',
    display: 'flex',
    flexBasis: '100%',
    // Bug fix for Firefox; width and flexBasis don't work on horizontally scrolling code blocks
    maxWidth: '100%',
    flexWrap: 'wrap',
    margin: '24px 0 0 0',
    padding: 0,
    position: 'relative',
    '@media (min-width: 640px)': {
      flexBasis: `calc(${span / 6 * 100}% - 10px)`,
      // Bug fix for Firefox; width and flexBasis don't work on horizontally scrolling code blocks
      maxWidth: `calc(${span / 6 * 100}% - 10px)`,
      margin: '24px 10px 0 0'
    }
  };
  return (
    <div style={style}>
      {children}
    </div>
  );
};

export default Radium(Span);

Fix botched React default require in bundled module


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

const { isDevelopment, isTest } = require('../configuration');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WebpackSplitByPath = require('webpack-split-by-path');

const basePlugins = [
    new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
        __DEV__: isDevelopment
    }),
    new WebpackSplitByPath([{
        name: 'vendor',
        path: [path.join(__dirname, '../node_modules')]
    }]),
    new HtmlWebpackPlugin({ template: './src/index.html', inject: 'body' }),
    new CopyWebpackPlugin([{
        from: './src/assets/favicon.ico',
        to: 'assets'
    }]),
    new webpack.NoErrorsPlugin()
];
const developmentPlugins = [new webpack.HotModuleReplacementPlugin()];
const productionPlugins = [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.OccurrenceOrderPlugin(true),
    new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
];

module.exports = isTest ? undefined : basePlugins.concat(isDevelopment ?
    developmentPlugins :
    productionPlugins
);

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

const { isDevelopment, isTest } = require('../configuration');

const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WebpackSplitByPath = require('webpack-split-by-path');

const basePlugins = [
    new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
        __DEV__: isDevelopment
    }),
    new WebpackSplitByPath([{
        name: 'vendor',
        path: [path.join(__dirname, '../node_modules')]
    }]),
    new HtmlWebpackPlugin({ template: './src/index.html', inject: 'body' }),
    new CopyWebpackPlugin([{
        from: './src/assets/favicon.ico',
        to: 'assets'
    }]),
    new webpack.NoErrorsPlugin()
];
const developmentPlugins = [new webpack.HotModuleReplacementPlugin()];
const productionPlugins = [
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } })
];

module.exports = isTest ? undefined : basePlugins.concat(isDevelopment ?
    developmentPlugins :
    productionPlugins
);

Fix a webpack plugin for production


import Ember from 'ember';
export default Ember.Component.extend({
  firstName: '',
  lastName: '',
  company: '',
  firstInitial: (function() {
    return this.get("firstName")[0] || this.get("company")[0];
  }).property('firstName', 'lastName'),
  lastInitial: (function() {
    return this.get("lastName")[0] || "";
  }).property('lastName'),
  classNames: 'initials-avatar',
  attributeBindings: ['style'],
  style: (function() {
    return "color:" + (this.get("colorOffset") !== void 0 ? this.get("colors")[this.get("colorOffset") % this.get("colors").length] : "#CCCCCC");
  }).property('color-offset'),
  colors: ["#FFCCCC", "#CCFFCC", "#CCCCFF"]
});

import Ember from 'ember';
export default Ember.Component.extend({
  firstName: '',
  lastName: '',
  company: '',
  firstInitial: (function() {
    return this.get("firstName")[0] || this.get("company")[0];
  }).property('firstName', 'lastName'),
  lastInitial: (function() {
    return this.get("lastName")[0] || "";
  }).property('lastName'),
  classNames: 'initials-avatar',
  attributeBindings: ['style'],
  style: (function() {
      var computedColor = (this.get("colorOffset") !== void 0 ? this.get("colors")[this.get("colorOffset") % this.get("colors").length] : "#CCCCCC");
    return "color: " + computedColor + "; border-color:" + computedColor;
  }).property('color-offset'),
  colors: ["#FFCCCC", "#CCFFCC", "#CCCCFF"]
});

Set border color to match text color.


var rookAction = function() {
	$( ".white-square, .black-square" ).droppable({
		activeClass: "ui-state-hover",
		hoverClass: "ui-state-active",

		drop: function( event, ui ) {
			if($(this).index() === startPos.index() && startPos.children().attr("class") === "white-rook white-piece chess-piece ui-draggable ui-draggable-handle"){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			};
			if($(this).index() === startPos.index() && startPos.children().attr("class") === "black-rook black-piece chess-piece ui-draggable ui-draggable-handle"){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			};
		}
	});
};

var rookAction = function() {
	$( ".white-square, .black-square" ).droppable({
		activeClass: "ui-state-hover",
		hoverClass: "ui-state-active",

		drop: function( event, ui ) {

			if($(this).index() === startPos.index() && startPos.children().attr("class") === "white-rook white-piece chess-piece ui-draggable ui-draggable-handle" && $(this).children().hasClass("white-piece") === false){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			}
			else if($(this).parent()[0] === startPos.parent()[0] && startPos.children().attr("class") === "white-rook white-piece chess-piece ui-draggable ui-draggable-handle" && $(this).children().hasClass("white-piece") === false){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			};
			if($(this).index() === startPos.index() && startPos.children().attr("class") === "black-rook black-piece chess-piece ui-draggable ui-draggable-handle" && $(this).children().hasClass("black-piece") === false){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			}
			else if($(this).parent()[0] === startPos.parent()[0] && startPos.children().attr("class") === "black-rook black-piece chess-piece ui-draggable ui-draggable-handle" && $(this).children().hasClass("black-piece") === false){
			    playerTurn();
			    return $( this )
			    .html( ui.draggable );
			};
		}
	});
};

Add logic for Rook horiz movement, can't take own pieces.


module.exports = {
    networks: {
        development: {
            host: "localhost",
            port: 8545,
            network_id: "*" // Match any network id
        }
    }
    //,
    //mocha: {
    //    reporter: 'mocha-junit-reporter'
    //}
};

module.exports = {
    networks: {
        development: {
            host: "localhost",
            port: 8545,
            network_id: "*" // Match any network id
        }
    }
    ,
    mocha: {
       reporter: 'mocha-junit-reporter'
    }
};

Change reporter to junit reporter


"use strict";
/**
 * Model for individual books.
 */
 define([
    "underscore",
    "backbone"
], function(_, Backbone) {
    var Book = Backbone.Model.extend({
        idAttribute: "_id",
        defaults: {
            'type': 'book',
            'public': true
        },
        url: function(){
            return '_rewrite/data/' + this.get('id');

        /**
         * Because CouchDB returns id & rev for some calls, and _id and _rev for others,
         * handle those special cases here.
         **/
        parse: function(response, options) {
            if (_.has(response, "id") && _.has(response, "rev")) {
                response["_id"] = response["id"];
                response["_rev"] = response["rev"];
                delete response["id"];
                delete response["rev"];
                // Also get rid of "ok" key.
                if (_.has(response, "ok")) {
                    delete response["ok"];
                }
            }
            return response;
        }
    });

    return Book;
});

"use strict";
/**
 * Model for individual books.
 */
 define([
    "underscore",
    "backbone"
], function(_, Backbone) {
    var Book = Backbone.Model.extend({
        idAttribute: "_id",
        defaults: {
            'type': 'book',
            'public': true
        },
        url: function(){
            var urlPrefix = '_rewrite/data/';
            if (this.isNew()) {
                // Do not include non-existent server ID.
                return urlPrefix;
            } else {
                return urlPrefix + this.get(this.idAttribute);
            }
        },

        /**
         * Because CouchDB returns id & rev for some calls, and _id and _rev for others,
         * handle those special cases here.
         **/
        parse: function(response, options) {
            if (_.has(response, "id") && _.has(response, "rev")) {
                response["_id"] = response["id"];
                response["_rev"] = response["rev"];
                delete response["id"];
                delete response["rev"];
                // Also get rid of "ok" key.
                if (_.has(response, "ok")) {
                    delete response["ok"];
                }
            }
            return response;
        }
    });

    return Book;
});

Return url root when no id exists


const istanbulAPI = require('istanbul-api');
const libCoverage = require('istanbul-lib-coverage');

function Istanbul(runner) {
  runner.on('end', () => {
    const mainReporter = istanbulAPI.createReporter();
    const coverageMap = libCoverage.createCoverageMap();

    coverageMap.merge(global.__coverage__ || {});

    mainReporter.addAll(['text', 'html']);
    mainReporter.write(coverageMap, {});
  });
}

module.exports = Istanbul;

const istanbulAPI = require('istanbul-api');
const libCoverage = require('istanbul-lib-coverage');
const Spec = require('mocha/lib/reporters/spec');

module.exports = class Istanbul extends Spec {
  constructor(runner) {
    super(runner);

    runner.on('end', () => {
      const mainReporter = istanbulAPI.createReporter();
      const coverageMap = libCoverage.createCoverageMap();

      coverageMap.merge(global.__coverage__ || {});

      mainReporter.addAll(['text', 'html']);
      mainReporter.write(coverageMap, {});
    });
  }
};

Update style of coverage reporter to be more ES6 like


define([], function () {
  var HelpDialog = function (summernote) {
    var self = this;
    var ui = $.summernote.ui;

    var $editor = summernote.layoutInfo.editor;
    var options = summernote.options;
    var lang = options.langInfo;

    this.initialize = function () {
      var $container = options.dialogsInBody ? $(document.body) : $editor;

      var body = [
        '
',
        'Summernote @VERSION · ',
        'Project · ',
        'Issues',
        '
'
      ].join('');

      this.$dialog = ui.dialog({
        title: lang.options.help,
        body: body
      }).render().appendTo($container);
    };

    this.destroy = function () {
      ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    };

    /**
     * show help dialog
     *
     * @return {Promise}
     */
    this.showHelpDialog = function () {
      return $.Deferred(function (deferred) {
        ui.onDialogHidden(self.$dialog, function () {
          deferred.resolve();
        });
        ui.showDialog(self.$dialog);
      }).promise();
    };

    this.show = function () {
      summernote.invoke('editor.saveRange');
      this.showHelpDialog().then(function () {
        summernote.invoke('editor.restoreRange');
      });
    };
  };

  return HelpDialog;
});

define([], function () {
  var HelpDialog = function (context) {
    var self = this;
    var ui = $.summernote.ui;

    var $editor = context.layoutInfo.editor;
    var options = context.options;
    var lang = options.langInfo;

    this.initialize = function () {
      var $container = options.dialogsInBody ? $(document.body) : $editor;

      var body = [
        '
',
        'Summernote @VERSION · ',
        'Project · ',
        'Issues',
        '
'
      ].join('');

      this.$dialog = ui.dialog({
        title: lang.options.help,
        body: body
      }).render().appendTo($container);
    };

    this.destroy = function () {
      ui.hideDialog(this.$dialog);
      this.$dialog.remove();
    };

    /**
     * show help dialog
     *
     * @return {Promise}
     */
    this.showHelpDialog = function () {
      return $.Deferred(function (deferred) {
        ui.onDialogHidden(self.$dialog, function () {
          deferred.resolve();
        });
        ui.showDialog(self.$dialog);
      }).promise();
    };

    this.show = function () {
      context.invoke('editor.saveRange');
      this.showHelpDialog().then(function () {
        context.invoke('editor.restoreRange');
      });
    };
  };

  return HelpDialog;
});

Rename summernote to context in module.


/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */

(function() {
    'use strict';

    window.bootstrapSuperdesk = function bootstrap(config, apps) {

        angular.module('superdesk.config').constant('config', config);
        angular.module('superdesk').constant('lodash', _);

        // setup default route for superdesk - set it here to avoid it being used in unit tests
        angular.module('superdesk').config(['$routeProvider', function($routeProvider) {
            $routeProvider.when('/', {redirectTo: '/workspace'});
        }]);

        // load apps & bootstrap
        var body = angular.element('body');
        body.ready(function() {
            angular.bootstrap(body, apps, {strictDi: true});
            window.superdeskIsReady = true;
        });
    };
})();

/**
 * This file is part of Superdesk.
 *
 * Copyright 2013, 2014 Sourcefabric z.u. and contributors.
 *
 * For the full copyright and license information, please see the
 * AUTHORS and LICENSE files distributed with this source code, or
 * at https://www.sourcefabric.org/superdesk/license
 */

(function() {
    'use strict';

    window.bootstrapSuperdesk = function bootstrap(config, apps) {

        angular.module('superdesk.config').constant('config', config);
        angular.module('superdesk').constant('lodash', _);

        // setup default route for superdesk - set it here to avoid it being used in unit tests
        angular.module('superdesk').config(['$routeProvider', function($routeProvider) {
            $routeProvider.when('/', {redirectTo: '/workspace/monitoring'});
        }]);

        // load apps & bootstrap
        var body = angular.element('body');
        body.ready(function() {
            angular.bootstrap(body, apps, {strictDi: true});
            window.superdeskIsReady = true;
        });
    };
})();

Set monitoring as the default page after login (SDNTB-180)


const React = require('react')
const should = require('should')
const { shallow } = require('enzyme')
const { expect } = require('chai')

import DropdownAlert from '../DropdownAlert'
import {
  View,
  Text,
  StyleSheet,
  TouchableHighlight,
  Animated,
  Modal,
  StatusBar,
  Image
} from "react-native"

describe('DropdownAlert', () => {
  it('should exist', () => {
    let wrapper = shallow(<DropdownAlert />)
    should.exist(wrapper)
  })
  it('should find custom sub components', () => {
    let wrapper = shallow(<DropdownAlert imageUri={'https://facebook.github.io/react/img/logo_og.png'} />)
    wrapper.instance().alert('custom', 'Title', 'Message')
    wrapper.update()
    expect(wrapper.find(Modal)).to.have.length(1)
    expect(wrapper.find(StatusBar)).to.have.length(1)
    expect(wrapper.find(View)).to.have.length(2)
    expect(wrapper.find(Animated.View)).to.have.length(1)
    expect(wrapper.find(TouchableHighlight)).to.have.length(1)
    expect(wrapper.find(Text)).to.have.length(2)
    expect(wrapper.find(Image)).to.have.length(1)
  })
  it('should dismiss', () => {
    let wrapper = shallow(<DropdownAlert />)
    wrapper.instance().dismiss()
    wrapper.update()
    wrapper.instance().should.be.ok
  })
})

const React = require('react')
const should = require('should')
const { shallow } = require('enzyme')
const { expect } = require('chai')

import DropdownAlert from '../DropdownAlert'
import {
  View,
  Text,
  StyleSheet,
  TouchableHighlight,
  Animated,
  Modal,
  StatusBar,
  Image
} from "react-native"

describe('DropdownAlert', () => {
  it('should exist', () => {
    let wrapper = shallow(<DropdownAlert />)
    should.exist(wrapper)
  })
  it('should find custom sub components', () => {
    let wrapper = shallow(<DropdownAlert imageUri={'https://facebook.github.io/react/img/logo_og.png'} />)
    wrapper.instance().alert('custom', 'Title', 'Message')
    wrapper.update()
    expect(wrapper.find(Modal)).to.have.length(1)
    expect(wrapper.find(StatusBar)).to.have.length(0)
    expect(wrapper.find(View)).to.have.length(2)
    expect(wrapper.find(Animated.View)).to.have.length(1)
    expect(wrapper.find(TouchableHighlight)).to.have.length(1)
    expect(wrapper.find(Text)).to.have.length(2)
    expect(wrapper.find(Image)).to.have.length(1)
  })
  it('should dismiss', () => {
    let wrapper = shallow(<DropdownAlert />)
    wrapper.instance().dismiss()
    wrapper.update()
    wrapper.instance().should.be.ok
  })
})

Fix test for sub components


/* jshint browser: true, jquery: true */
/* global AgileSprint:false, console:false */

var AgileSprintManager = function(options) {
//  if(options.server === null || options.server === undefined) {
//    return null;
//  }

  this.widgetManager = (options.widgetManager !== null && options.widgetManager !== undefined) ? options.widgetManager : null;
  this.panelManager = (options.panelManager !== null && options.panelManager !== undefined) ? options.panelManager : null;

  this.server = options.server;
};

AgileSprintManager.prototype.processMessages = function(server, id, content) {
  var processed = false;

  switch (id) {
    case AgileSprint.MESSAGE_STATS:
      this.__receivedStats(server, content);
      processed = true;
      break;
  }

  return processed;
};

AgileSprintManager.prototype.__receivedStats = function(server, d) {
  if(this.widgetManager !== null) {
    this.widgetManager.receivedData(d);
  }
};

/* jshint browser: true, jquery: true */
/* global AgileSprint:false, console:false */

var AgileSprintManager = function(options) {
//  if(options.server === null || options.server === undefined) {
//    return null;
//  }

  this.widgetManager = (options.widgetManager !== null && options.widgetManager !== undefined) ? options.widgetManager : null;
  this.panelManager = (options.panelManager !== null && options.panelManager !== undefined) ? options.panelManager : null;

  this.server = options.server;
};

AgileSprintManager.prototype.processMessages = function(server, id, content) {
  var processed = false;

  switch (id) {
    case AgileSprint.MESSAGE_STATS:
      this.__receivedStats(server, content);
      processed = true;
      break;

    case AgileSprint.MESSAGE_CONNECTIVITY_ERROR:
      this.__receivedError(server, content);
      processed = true;
      break;
  }

  return processed;
};

AgileSprintManager.prototype.__receivedStats = function(server, d) {
  if(this.widgetManager !== null) {
    this.widgetManager.receivedData(d);
  }
};

AgileSprintManager.prototype.__receivedError = function(server, d) {
  if(this.widgetManager !== null) {
    this.widgetManager.receivedError(d);
  }
};

Handle errors from agile source


Invitations = new Mongo.Collection("invitations");

InvitationsSchema = new SimpleSchema({
  emails: {
    type: [String],
    label: "E-mail address",
    regEx: SimpleSchema.RegEx.Email
  },
  file: {
    type: String,
    autoform: {
      afFieldInput: {
        type: "fileUpload",
        collection: "Files",
        label: "Choose a file"
      }
    }
  }
});

Invitations.attachSchema(InvitationsSchema);

Invitations.allow({
  "insert": function (userId, doc) {
    return true;
  },
  "update": function (userId, doc) {
    return true;
  }
});

Add allow insert and update rules


/*doc
---
title: Toggle
name: toggle_react
parent: form_react
---

<code class="pam">
  <i class="fa fa-download" alt="Install the Component">
    npm install pui-react-toggle --save
  </i>
</code>

Require the subcomponent:

```
var Toggle = require('pui-react-toggle').Toggle;
```

The Toggle component takes an `onChange` callback.

```react_example
<Toggle onChange={() => console.log('I have been toggled!')}/>
```

*/

/*doc
---
title: Toggle
name: toggle_react
parent: form_react
---

<code class="pam">
  <i class="fa fa-download" alt="Install the Component">
    npm install pui-react-toggle --save
  </i>
</code>

Require the subcomponent:

```
var Toggle = require('pui-react-toggle').Toggle;
```

The Toggle component takes an `onChange` callback.

```react_example
<Toggle onChange={() => console.log('I have been toggled!')}/>
```

Toggles accept a `checked` prop that turns on the switch.

```react_example
 <Toggle checked/>
```

*/

Document Toggle checked prop in styleguide


/**
 * Dashboard
 */

Template.dashboard.helpers({
  firstName() {
    if (Meteor.userId()) {
      return Meteor.user().profile.name.split(' ')[0];
    }
    return '';
  },
  connected() {
    return Meteor.status().connected;
  },
});

Template.dashboard.events({
  'click .new-scheme'() {
    FlowRouter.go('insertScheme');
  },
});

Template.dashboard.onCreated(function created() {
  const self = this;
  self.autorun(() => {
    if (!Meteor.userId()) {
      FlowRouter.go('landing');
    }
  });
});

/**
 * Dashboard
 */

Template.dashboard.helpers({
  firstName() {
    if (Meteor.user() && Meteor.user().profile) {
      return Meteor.user().profile.name.split(' ')[0];
    }
    return '';
  },
  connected() {
    return Meteor.status().connected;
  },
});

Template.dashboard.events({
  'click .new-scheme'() {
    FlowRouter.go('insertScheme');
  },
});

Template.dashboard.onCreated(function created() {
  const self = this;
  self.autorun(() => {
    if (!Meteor.userId()) {
      FlowRouter.go('landing');
    }
  });
});

Check user before checking for firstName.


"use strict";

var GoogleAnalytics = {};

GoogleAnalytics.TrackNavigation = function() {
  ga("send", "pageview");
};

module.exports = GoogleAnalytics;

"use strict";

var GoogleAnalytics = {};

GoogleAnalytics.TrackNavigation = function() {
  ga("send", "pageview", "/beta/" + m.route());
};

module.exports = GoogleAnalytics;

Update google analytics page tracking


const expect = require('chai').expect;
const React = require('react');
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import fakeStore from './fakeStore';

import Profile from '../../client/components/Profile.js';

const fakeProfile = {
  avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
  username: 'USERNAME',
};

describe('<Profile />', () => {
  let wrapper;

  beforeEach('render Profile', () => {
    wrapper = mount(
      <Provider store={fakeStore}>
        <Profile />
      </Provider>);
  });

  it('renders without problems', () => {
    expect(wrapper.find(Profile)).to.have.length(1);
  });

  it('should display the correct username', () => {
    expect(wrapper.find('.profile-username').text()).to.equal(fakeStore.getState().profile.username);
  });

  it('should display the correct avatar', () => {
    expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
  });
});

const expect = require('chai').expect;
const React = require('react');
import { Provider } from 'react-redux';
import { mount } from 'enzyme';
import fakeStore from './fakeStore';

import Profile from '../../client/components/Profile.js';
import RecipeContainer from '../../client/components/RecipeContainer.js';

const fakeProfile = {
  avatar: 'http://www.carderator.com/assets/avatar_placeholder_small.png',
  username: 'USERNAME',
};

describe('<Profile />', () => {
  let wrapper;

  beforeEach('render Profile', () => {
    wrapper = mount(
      <Provider store={fakeStore}>
        <Profile />
      </Provider>);
  });

  it('renders without problems', () => {
    expect(wrapper.find(Profile)).to.have.length(1);
  });

  it('should display the correct username', () => {
    expect(wrapper.find('.profile-username').text()).to.equal(fakeStore.getState().profile.username);
  });

  it('should display the correct avatar', () => {
    expect(wrapper.find('.profile-avatar').html()).to.contain(fakeStore.getState().profile.avatar);
  });

  it('should render two recipe containers', () => {
    expect(wrapper.find(RecipeContainer)).to.have.length(2);
  })
});

Check for two RecipeContainers on Profile


import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class FormButtonComponent extends Component {
  @tracked
  isActing = false;
  @action
  handleClick() {
    if (!this.isActing && this.args.onClick) {
      const ret = this.args.onClick();

      if (ret.finally) {
        this.isActing = true;
        ret.finally(() => (this.isActing = false));
      }
      return ret;
    }
  }
}

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';

export default class FormButtonComponent extends Component {
  @tracked
  isActing = false;
  @action
  handleClick() {
    if (!this.isActing && this.args.onClick) {
      const ret = this.args.onClick();

      if (ret && ret.finally) {
        this.isActing = true;
        ret.finally(() => (this.isActing = false));
      }
      return ret;
    }
  }
}

Add guard for empty response


/**
 * Return an array of function of the form x => { type, payload = x }
 */
export function createActions(...types) {
  return types.map(createAction)
}

/**
 * Create a single action of the form x => { type, payload = x }
 */
export function createAction(type) {
  return (payload, error) => (Object.assign({ type }, payload ? { payload } : {}, error ? { error } : {}))
}

/**
 * Create a single action of the form x => { type }
 * Use this for actions that do not carry any payload, this is useful especially if the action is
 * going to be used as an event handler to avoid accidentally including the DOM event as payload.
 */
export function createAction0(type) {
  return () => ({ type })
}

/**
 * Return an array of action creators.
 * Use this for actions that do not carry any payload.
 *
 * @returns {Array}
 */
export function creactActions0(...types) {
  return types.map(createAction0)
}

Add createAction0 method for action without payload


module.exports = {
  test: /\.es6\.js$|\.js$|\.jsx$/,
  exclude: /node_modules/,
  loader: 'babel',
  query: {
    presets: [
      'es2015-native-modules',
      'stage-2',
      'react',
    ].map(function(p) { return require.resolve('babel-preset-' + p) }),
    plugins: [
      'transform-class-properties',
      'transform-react-constant-elements',
      'transform-react-inline-elements',
      'lodash', // fixes the babel budnling issue
    ].map(function(p) { return require.resolve('babel-plugin-' + p) }),
  }
};

module.exports = {
  test: /\.es6\.js$|\.js$|\.jsx$/,
  exclude: /node_modules/,
  loader: 'babel',
  query: {
    presets: [
      'es2015-native-modules',
      'stage-2',
      'react',
    ],
    plugins: [
      'transform-class-properties',
      'transform-react-constant-elements',
      'transform-react-inline-elements',
      'lodash', // fixes the babel budnling issue
    ],
  }
};

Revert "Fix module resolution for npm-link'd packages"


/*
 * Copyright (C) 2014 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import router from './router'
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'

router.start()
monitorLtiMessages()

/*
 * Copyright (C) 2014 - present Instructure, Inc.
 *
 * This file is part of Canvas.
 *
 * Canvas is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License as published by the Free
 * Software Foundation, version 3 of the License.
 *
 * Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Affero General Public License along
 * with this program. If not, see <http://www.gnu.org/licenses/>.
 */

import router from './router'
import {monitorLtiMessages} from '@canvas/lti/jquery/messages'
import ready from '@instructure/ready'

ready(() => {
  router.start()
  monitorLtiMessages()
})

Fix flakey selenium specs for files


// XXX namespacing
Meteor._RemoteCollectionDriver = function (mongo_url) {
  var self = this;
  self.mongo = new Meteor._Mongo(mongo_url);
};

_.extend(Meteor._RemoteCollectionDriver.prototype, {
  open: function (name) {
    var self = this;
    var ret = {};
    _.each(
      ['find', 'findOne', 'insert', 'update', 'remove', '_ensureIndex',
       '_dropIndex'],
      function (m) {
        ret[m] = _.bind(self.mongo[m], self.mongo, name);
      });
    return ret;
  }
});

// singleton
// XXX kind of hacky
Meteor._RemoteCollectionDriver = new Meteor._RemoteCollectionDriver(process.env.MONGO_URL);

// XXX namespacing
Meteor._RemoteCollectionDriver = function (mongo_url) {
  var self = this;
  self.mongo = new Meteor._Mongo(mongo_url);
};

_.extend(Meteor._RemoteCollectionDriver.prototype, {
  open: function (name) {
    var self = this;
    var ret = {};
    _.each(
      ['find', 'findOne', 'insert', 'update', 'remove', '_ensureIndex',
       '_dropIndex'],
      function (m) {
        ret[m] = _.bind(self.mongo[m], self.mongo, name);
      });
    return ret;
  }
});

// singleton
// XXX kind of hacky
var mongoUrl = Meteor._get(__meteor_bootstrap__.deployConfig,
                           'packages', 'mongo-livedata', 'url');
// XXX bad error since it could also be set directly in METEOR_DEPLOY_CONFIG
if (!mongoUrl)
  throw new Error("MONGO_URL must be set in environment");
Meteor._RemoteCollectionDriver = new Meteor._RemoteCollectionDriver(mongoUrl);

Use deployConfig rather than $MONGO_URL in the mongo-livedata package.


var React = require('react');

var Character = React.createClass({
  getThumbnail: function() {
    var image = 'http://placehold.it/250x250';

    if(this.props.character.thumbnail) {
      image = this.props.character.thumbnail.path+'.'+this.props.character.thumbnail.extension;
    }

    return (

    )
  },

  getName: function() {
    return (

        {this.props.character.name}

    );
  },

  getDescription: function() {
    var description = this.props.character.description ? this.props.character.description : 'No description'

    return (

        {description}

    )
  },

  getLinks: function() {
    return (

        Wiki|
        More details

    )
  },

  render: function () {
    return (

            {this.getThumbnail()}

              {this.getName()}

                {this.getDescription()}
                {this.getLinks()}

    );
  }
});

module.exports = Character;

var React = require('react');

var Character = React.createClass({
  getThumbnail: function() {
    var image = 'http://placehold.it/250x250';

    if(this.props.character.thumbnail) {
      var path = this.props.character.thumbnail.path;
      var extension = this.props.character.thumbnail.extension;

      image = path+'.'+extension;
    }

    return (

    )
  },

  getName: function() {
    return (

        {this.props.character.name}

    );
  },

  getDescription: function() {
    var description = this.props.character.description || 'No description';

    return (

        {description}

    )
  },

  getLinks: function() {
    return (

        Wiki|
        More details

    )
  },

  render: function () {
    return (

            {this.getThumbnail()}

              {this.getName()}

                {this.getDescription()}
                {this.getLinks()}

    );
  }
});

module.exports = Character;

Make some fixes in the Character component methods


import React from 'react';
import _ from 'lodash';
import Icon from './Icon';

class AccountBar extends React.Component {
	handleClick = (e) => {
		var currentTarget = e.currentTarget;

		this.props.setDisplayView(currentTarget.dataset.displayType);
	}

	render() {
		var props = this.props;

		var buttons = 'compact cozy comfortable'.split(' ').map(
			(item, index) => {
				var btnClassName = `btn btn-default ${props.config.view === item ? 'active' : ''}`;
				var iconClassName = `icon-monospaced display-${item}-icon`;

				return
					<Icon className={iconClassName} name="list-ul" />
				;
			}
		);

		// console.log(this.props);

		return

					{buttons}

;
	}
}

export default AccountBar;

import React from 'react';
import _ from 'lodash';
import Icon from './Icon';

class AccountBar extends React.Component {
	handleClick = (e) => {
		var currentTarget = e.currentTarget;

		this.props.setDisplayView(currentTarget.dataset.displayType);
	}

	render() {
		var props = this.props;

		var buttons = 'compact cozy comfortable'.split(' ').map(
			(item, index) => {
				var btnClassName = `btn btn-default ${props.config.view === item ? 'active' : ''}`;
				var iconClassName = `icon-monospaced display-${item}-icon`;

				return
					<Icon className={iconClassName} name="list-ul" />
				;
			}
		);

		return

						 {props.loadPulls();}}>
							<Icon className="icon-monospaced" name="reload" />
							Reload Pulls

					{buttons}

;
	}
}

export default AccountBar;

Add ability to force reload the pulls


module.exports = {
    entry: {
      app: ['./web-src/es6/app.js']<% if (useJQuery || useBootstrap) { %>,
      libs: ['./web-src/js/dist/libs.all.js']
      <% } %>
    },
    output: {
      <% if (useJQuery || useBootstrap) { %>
        path: '/web/js'
      <% } else { %>
        filename: 'bundle.js'
      <% } %>
    },
    module: {
      rules: [
        {
          test: /\.jsx?$/,
          loader: 'babel-loader',
          query: {
              presets: ['es2015']
          }
        }
      ]
    }
};

module.exports = {
    entry: {
      app: ['./web-src/es6/app.js'<% if (useJQuery || useBootstrap) { %>, './web-src/js/dist/libs.all.js'<% } %>]
    },
    output: {
      filename: 'bundle.js'
    },
    module: {
      rules: [
        {
          test: /\.jsx?$/,
          loader: 'babel-loader',
          query: {
              presets: ['es2015']
          }
        }
      ]
    }
};

Fix that webpack task for good


#!/usr/bin/env node

var args = require('../lib/args');
var options = args.parse();
var instance;

if (options.version) {
    console.log('v' + args.version);
    process.exit(0);
} else if (options.help) {
    console.error(args.usage);
    process.exit(0);
}

if (options.cluster) {
    // Cluster support
    instance = require('../lib/cluster')(options);

    if (options.restart) {
        instance.restart();
    }
    else if (options.shutdown) {
        instance.shutdown();
    }
    else if (options.status) {
        instance.status();
    }
    else if (options.stop) {
        instance.stop();
    }
    else {
        instance.listen();
    }
} else {
    // Legacy support
    instance = require('../lib/server')(options);
    var port = options.port || require('../lib/defaults').master.port;

    if (!options.quiet) {
        console.log("combohandler: Listening on http://localhost:%d/", port);
    }

    instance.listen(port);
}

//  Local "integration" test from root of combohandler repo
//
//  Terminal:
//      ./bin/cli.js -f ./test/root.json
//      ./bin/cli.js -f ./test/root.json --cluster
//
//  Browser:
//      localhost:8000/js?a.js&b.js
//      localhost:8000/css?a.css&b.css

#!/usr/bin/env node

var args = require('../lib/args');
var options = args.parse();
var instance;

if (options.version) {
    console.log('v' + args.version);
    process.exit(0);
} else if (options.help) {
    console.error(args.usage);
    process.exit(0);
}

if (options.cluster) {
    // Cluster support
    instance = require('../lib/cluster')(options);

    if (options.restart) {
        instance.restart();
    }
    else if (options.shutdown) {
        instance.shutdown();
    }
    else if (options.status) {
        instance.status();
    }
    else if (options.stop) {
        instance.stop();
    }
    else {
        instance.listen();
    }
} else {
    // Legacy support
    instance = require('../lib/server')(options);
    var port = options.port || require('../lib/defaults').master.port;

    if (!options.quiet) {
        console.log("combohandler: Listening on http://localhost:%d/", port);
        console.log("Press Ctrl+C to exit.");
    }

    instance.listen(port);
}

//  Local "integration" test from root of combohandler repo
//
//  Terminal:
//      ./bin/cli.js -f ./test/root.json
//      ./bin/cli.js -f ./test/root.json --cluster
//
//  Browser:
//      localhost:8000/js?a.js&b.js
//      localhost:8000/css?a.css&b.css

Add message to non-cluster CLI to indicate how to exit.


var jarvis = jarvis || angular.module('jarvis', []);

jarvis.controller('PlexCtrl', ['$scope',
  function ($scope) {
    'use strict';

    $scope.$on('plex', function (ev, body) {
      if (body.movies.length > 5) {
        body.movies = body.movies.slice(0, 5);
      }
      if (body.shows.length > 5) {
        body.shows = body.shows.slice(0, 5);
      }
      angular.extend($scope, body);
    });

  }
]);

var jarvis = jarvis || angular.module('jarvis', []);

jarvis.controller('PlexCtrl', ['$scope',
  function ($scope) {
    'use strict';

    $scope.$on('plex', function (ev, body) {
      if (body.movies.length > 4) {
        body.movies = body.movies.slice(0, 4);
      }
      if (body.shows.length > 4) {
        body.shows = body.shows.slice(0, 4);
      }
      angular.extend($scope, body);
    });

  }
]);

Reduce item count in Plex widget


var events = require('events')
var util = require('util')
var web3 = require('web3')

function Contract (source) {
  this.source = source
  this.instance = null
  this.name = ''
  this.deploying = false
}
util.inherits(Contract, events.EventEmitter)

Contract.prototype.compile = async function () {
  try {
    return await web3.eth.compile.solidity(this.source)
  } catch (e) {
    console.log(e)
  }
}

Contract.prototype.deploy = function (accountAddress) {
  var self = this

  var compiled = self.compile()
    , contractName = Object.keys(compiled)[0]
    , Contract = web3.eth.contract(compiled[contractName].info.abiDefinition)

  Contract.new(
    0, // (uint initialValue)
    {
      from: accountAddress,
      data: compiled[contractName].code,
      gas: 1000000
    },
    function (err, contract) {
      if (err) return done(err)

      if (!contract.address) {
        self.deploying = true
        self.emit('deploying', contract)
      }
      else {
        self.instance = contract
        self.deploying = false
        self.emit('deployed', self.instance)
      }
  })
}

Contract.prototype.init = function (contractAddress) {
  var compiled = this.compile()
    , contractName = Object.keys(compiled)[0]
    , abiDefinition = compiled[contractName].info.abiDefinition

  this.instance = web3.eth.contract(abiDefinition).at(contractAddress)
}

module.exports = Contract

import events from 'events'
import util from 'util'
import web3 from 'web3'

class Contract extends events.EventEmitter {
  constructor(source) {
    super()
    this.source = source
    this.instance = null
    this.name = ''
    this.deploying = false
  }

  async compile () {
    return await web3.eth.compile.solidity(this.source)
  }

  async deploy (accountAddress) {
    var self = this

    var compiled = await self.compile()
      , contractName = Object.keys(compiled)[0]
      , Contract = web3.eth.contract(compiled[contractName].info.abiDefinition)

    Contract.new(
      0, // (uint initialValue)
      {
        from: accountAddress,
        data: compiled[contractName].code,
        gas: 1000000
      },
      function (err, contract) {
        if (err) return done(err)

        if (!contract.address) {
          self.deploying = true
          self.emit('deploying', contract)
        }
        else {
          self.instance = contract
          self.deploying = false
          self.emit('deployed', self.instance)
        }
    })
  }

  async init (contractAddress) {
    var compiled = await this.compile()
      , contractName = Object.keys(compiled)[0]
      , abiDefinition = compiled[contractName].info.abiDefinition

    this.instance = web3.eth.contract(abiDefinition).at(contractAddress)
  }
}

export default Contract

Use class, module and async


import Ember from 'ember';

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

  setupBootstrapDatepicker: function() {
    var self = this;

    this.$().
      datepicker({
        autoclose: this.get('autoclose') || true,
        format: this.get('format') || 'dd.mm.yyyy',
        weekStart: this.get('weekStart') || 1,
        todayHighlight: this.get('todayHighlight') || false,
        todayBtn: this.get('todayBtn') || false
      }).
      datepicker('setDate', new Date(this.get('value'))).
      on('changeDate', function(event) {
        Ember.run(function() {
          self.didSelectDate(event);
        });
      });
  }.on('didInsertElement'),

  teardownBootstrapDatepicker: function() {
    // no-op
  }.on('willDestroyElement'),

  didSelectDate: function(event) {
    var date = this.$().datepicker('getUTCDate');
    this.set('value', date.toISOString());
  }
});

import Ember from 'ember';

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

  setupBootstrapDatepicker: function() {
    var self = this,
        element = this.$();

    element.
      datepicker({
        autoclose: this.get('autoclose') || true,
        format: this.get('format') || 'dd.mm.yyyy',
        weekStart: this.get('weekStart') || 1,
        todayHighlight: this.get('todayHighlight') || false,
        todayBtn: this.get('todayBtn') || false
      }).
      on('changeDate', function(event) {
        Ember.run(function() {
          self.didSelectDate(event);
        });
      });

    if (value) {
      element.datepicker('setDate', new Date(this.get('value')));
    };
  }.on('didInsertElement'),

  teardownBootstrapDatepicker: function() {
    // no-op
  }.on('willDestroyElement'),

  didSelectDate: function(event) {
    var date = this.$().datepicker('getUTCDate');
    this.set('value', date.toISOString());
  }
});

Set value when it exists, or just leave it blank


angular.module('directives')
.directive('formChange',['$parse',function($parse) {
  return {
    'restrict' : 'A',
    'require' : 'form',
    'link' : function($scope, $elem, $attrs) {
      var cb = $scope.$eval($attrs.formChange);
      $elem.on('keyup',function() {
        cb();
        $scope.$apply();
      });
    }
  }
}])
.directive('buttonText',[function() {
  return {
    'restrict' : 'A',
    'link' : function($scope,$elem,$attrs) {

      var btnText = $attrs.buttonText,
          btnDefaultText = $attrs.buttonDefaultText|| 'Submit',
          btnDisableText = $attrs.buttonDisableText || '__undefined';

      if(!$scope[btnText]){
        $elem.text(btnDefaultText);
        return;
      }

      $scope.$watch(btnText,function(newVal){

        if(newVal == btnDisableText){
          $elem.attr('disabled',true);
          return;
        }

        $elem.removeAttr('disabled');

      });
    }
  }
}])
.directive('ngEnter', [function () {
  return {
    link : function (scope, element, attrs) {
      element.on("keydown keypress", function (event) {
        if(event.which === 13) {

          scope.$apply(function (){
              scope.$eval(attrs.ngEnter);
          });

          event.preventDefault();
        }
      });
    }
  }
}]);

Create ngEnter directive to submit value on enter


// This file is used as the root JS file for the govuk_publishing_components/design
// system aspects of Collections Publisher
//= require govuk_publishing_components/dependencies
//= require govuk_publishing_components/all_components
//= require components/autocomplete

//= require jquery-ui.sortable.min
//= require jquery_ujs

// support ES5
//= require es5-polyfill/dist/polyfill.js

// support ES6 (promises, functions, etc. - see docs)
//= require core-js-bundle/index.js

// support ES6 custom elements
//= require @webcomponents/custom-elements/custom-elements.min.js

//= require components/markdown-editor.js

// This file is used as the root JS file for the govuk_publishing_components/design
// system aspects of Collections Publisher

//= require govuk_publishing_components/dependencies
//= require govuk_publishing_components/all_components
//= require components/autocomplete

//= require jquery_ujs

// support ES5
//= require es5-polyfill/dist/polyfill.js

// support ES6 (promises, functions, etc. - see docs)
//= require core-js-bundle/index.js

// support ES6 custom elements
//= require @webcomponents/custom-elements/custom-elements.min.js

//= require components/markdown-editor.js

Remove jquery-ui.sortable from design system JS


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery.turbolinks
//= require jquery-ui.min
//= require jquery_ujs
//= require turbolinks
//= require_tree .
$(window).on('page:change', function () {
  $.getScript('https://platform.twitter.com/widgets.js');
});

Fix Twitter button Turbolinks issue.


// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.

// require kingadmin/jquery-2.1.0
//= require jquery
//= require jquery_ujs
//= requre bootstrap
//= require kingadmin/king-common.js
//= require_tree .

$(function() {
	$("#event_begin_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_end_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_registration_open_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_registration_close_date").datepicker(
		{dateformat: 'yy-mm-dd'});
});

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file.
//
// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
// about supported directives.

//= require jquery
//= require jquery_ujs
//= requre bootstrap
//= require kingadmin/king-common
//= require kingadmin/king-components
//= require kingadmin/king-form-layouts
//= require_tree .

$(function() {
	$("#event_begin_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_end_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_registration_open_date").datepicker(
		{dateformat: 'yy-mm-dd'});
	$("#event_registration_close_date").datepicker(
		{dateformat: 'yy-mm-dd'});
});

Add js files to manifest.


angular.module('zeus.services', [])
.factory('Details', function($http) {

})
.factory('Landing', function($http) {

})
.factory('Results', function($http) {

})

angular.module('zeus.services', [])
.factory('Details', function($http) {

})
.factory('Landing', function($http) {

})
.factory('Results', function($http) {
  var multiSearch = function(query) {
    return $http({
      method: 'GET',
      url: 'https://api.themoviedb.org/3/search/multi?api_key=144a52aa180019a468d95822c036cbce&language=en-US&query=' + query
    })
    .then(function(res) {
      return res;
    });
  };

  return {
    multiSearch: multiSearch
  };

});

Add GET request for a multi-search and Results factory


export default (app) => {
    class SceneService {
        constructor($resource) {
            'ngInject';

            this.Scene = $resource(
                '/api/scenes/:id/', {
                    id: '@properties.id'
                }, {
                    query: {
                        method: 'GET',
                        cache: false
                    },
                    get: {
                        method: 'GET',
                        cache: false
                    }
                }
            );
        }

        query(params = {}) {
            return this.Scene.query(params).$promise;
        }

        getSceneBounds(scene) {
            let boundsGeoJson = L.geoJSON();
            boundsGeoJson.addData(scene.dataFootprint);
            return boundsGeoJson.getBounds();
        }
    }

    app.service('sceneService', SceneService);
};

export default (app) => {
    class SceneService {
        constructor($resource) {
            'ngInject';

            this.Scene = $resource(
                '/api/scenes/:id/', {
                    id: '@properties.id'
                }, {
                    query: {
                        method: 'GET',
                        cache: false
                    },
                    get: {
                        method: 'GET',
                        cache: false
                    }
                }
            );
        }

        query(params = {}) {
            let validParams = Object.assign(
                params,
                {minCloudCover: params.minCloudCover ? params.minCloudCover : 0}
            );
            return this.Scene.query(validParams).$promise;
        }

        getSceneBounds(scene) {
            let boundsGeoJson = L.geoJSON();
            boundsGeoJson.addData(scene.dataFootprint);
            return boundsGeoJson.getBounds();
        }
    }

    app.service('sceneService', SceneService);
};

Set minCloudCover to zero if it's absent from scene query


'use strict';

angular.module('arethusa.core').directive('sidepanelFolder', [
  'sidepanel',
  function(sidepanel) {
    return {
      scope: {},
      link: function (scope, element, attrs) {
        function setIconClass() {
          var icon = sidepanel.folded ? 'compress' : 'expand';
          scope.iconClass = 'fi-arrows-' + icon;
        }

        element.on('click', function () {
          sidepanel.toggle();
          setIconClass();
        });

        scope.sp = sidepanel;

        scope.$watch('sp.folded', function(newVal, oldVal) {
          setIconClass();
        });
      },
      template: '<i ng-class="iconClass"/>'
    };
  }
]);

'use strict';

angular.module('arethusa.core').directive('sidepanelFolder', [
  'sidepanel',
  function(sidepanel) {
    return {
      scope: {},
      link: function (scope, element, attrs) {
        function setIconClassAndText() {
          var icon = sidepanel.folded ? 'expand' : 'compress';
          var text = sidepanel.folded ? 'Show' : 'Fold';
          scope.iconClass = 'fi-arrows-' + icon;
          scope.text = text + " Panel";
        }

        element.on('click', function () {
          sidepanel.toggle();
          scope.$apply(setIconClassAndText());
        });

        scope.sp = sidepanel;

        scope.$watch('sp.folded', function(newVal, oldVal) {
          setIconClassAndText();
        });
      },
      template: '<i title="{{ text }}" ng-class="iconClass"/>'
    };
  }
]);

Fix sidepanel-folder class and title text


(function() {
    'use strict';

    // Create module
    var module = angular.module('filteredTable', []);

    function filteredTable() {

        function controller($scope) {

            $scope.predicate = null;
            $scope.reverse = false;
            $scope.sorting = {};

            $scope.orderBy = function(key) {
                // Clean old predicate sorting
                $scope.sorting[$scope.predicate] = null;

                // Set new parameters
                $scope.predicate = key;
                $scope.reverse = !$scope.reverse;
                $scope.sorting[key] = $scope.reverse ? 'desc' : 'asc';
            }

        }

        return {
            restrict: 'A',
            controller: controller
        }

    }

    // Declare directive
    module.directive('filteredTable', [filteredTable]);

})();

(function() {
    'use strict';

    // Create module
    var module = angular.module('filteredTable', []);

    function filteredTable() {

        function controller($scope) {

            $scope.predicate = null;
            $scope.reverse = false;
            $scope.sorting = {};

            $scope.orderBy = function(key) {
                // Clean old predicate sorting
                $scope.sorting[$scope.predicate] = null;

                // Set new parameters
                $scope.predicate = key;
                $scope.reverse = !$scope.reverse;
                $scope.sorting[key] = $scope.reverse ? 'desc' : 'asc';
            }

        }

        return {
            restrict: 'A',
            controller: ['$scope', controller]
        }

    }

    // Declare directive
    module.directive('filteredTable', filteredTable);

})();

Fix bug when file is minified We needed to inject scope with the full notation


module.exports = {
  description: '',
  normalizeEntityName: function () {},

  /**
    Installs specified packages at the root level of the application.
    Triggered by 'ember install <addon name>'.

    @returns {Promise} package names and versions
  */
  afterInstall: function () {
    return this.addAddonsToProject({
      packages: [
        {
          name: 'ember-frost-core',
          target: '>=0.24.0 <1.0.0'
        }
      ]
    })
  }
}

module.exports = {
  description: '',
  normalizeEntityName: function () {},

  /**
    Installs specified packages at the root level of the application.
    Triggered by 'ember install <addon name>'.

    @returns {Promise} package names and versions
  */
  afterInstall: function () {
    return this.addAddonsToProject({
      packages: [
        {
          name: 'ember-frost-core',
          target: '>=0.24.0 <=1.0.0'
        }
      ]
    })
  }
}

Change blueprint from < 1 to <= 1 for core


#!/usr/bin/env node

var nconf  = require('nconf');
var Codius = require('../lib/codius').Codius;
var Config = require('../lib/config').Config;

// Use nconf to load command line arguments and environment variables
nconf.argv()
     .env()
     .file({ file: 'HOME/.config/codius/cli.json' });
var config = new Config(nconf.get());
var command = nconf.get('_')[0];

var codius = new Codius();
codius.load(config).then(function () {
  codius.runCommand(command);
}).catch(function (err) {
  console.error(err.message);
  process.exit(1);
}).done();

#!/usr/bin/env node

var nconf  = require('nconf');
var Codius = require('../lib/codius').Codius;
var Config = require('../lib/config').Config;

// Use nconf to load command line arguments and environment variables
nconf.argv()
     .env()
     .file({ file: 'HOME/.config/codius/cli.json' });
var config = new Config(nconf.get());
var command = nconf.get('_')[0];

var codius = new Codius();
codius.load(config).then(function () {
  codius.runCommand(command);
}).catch(function (err) {
  console.error(err.stack ? err.stack : err);
  process.exit(1);
}).done();

Print a full stack trace if available.


var http = require('http');
var url = require("url");
var fs = require('fs');
var c = require('../../config.json');

var server = http.createServer(function(req, res) {
  var page = url.parse(req.url).pathname;
  console.log( page );
  if(page == '/') {
    fs.readFile('../client/index.html', 'utf8', function(err, data) {
      if(err) {
        return console.log(err);
      }

      res.writeHeader(200, {"Content-Type": "text/html"});
      res.write(data);
      res.end();
    });
  }
  else {
    /** Lecture de toutes les ressources (js, css) dans le dossier client */
    var pageSplitted = page.split( '.' );

    fs.readFile( '../client/' + page, 'utf-8', function(err, data) {
      if(err) {
        return console.log(err);
      }

      res.writeHeader(200, {"Content-Type": "text/" + pageSplitted[pageSplitted.length - 1]});
      res.write(data);
      res.end();
    });
  }
});

var snakeServer = require('./snake-server')(server);

var ipAddress = process.env.OPENSHIFT_NODEJS_IP || process.env.IP || c.ip;
var serverPort = process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || c.port;
server.listen(serverPort);

var http = require('http');
var url = require("url");
var fs = require('fs');
var c = require('../../config.json');

var server = http.createServer(function(req, res) {
  var page = url.parse(req.url).pathname;
  console.log( page );
  if(page == '/') {
    fs.readFile('./src/client/index.html', 'utf8', function(err, data) {
      if(err) {
        return console.log(err);
      }

      res.writeHeader(200, {"Content-Type": "text/html"});
      res.write(data);
      res.end();
    });
  }
  else {
    /** Lecture de toutes les ressources (js, css) dans le dossier client */
    var pageSplitted = page.split( '.' );

    fs.readFile( './src/client/' + page, 'utf-8', function(err, data) {
      if(err) {
        return console.log(err);
      }

      res.writeHeader(200, {"Content-Type": "text/" + pageSplitted[pageSplitted.length - 1]});
      res.write(data);
      res.end();
    });
  }
});

var snakeServer = require('./snake-server')(server);

var ipAddress = process.env.OPENSHIFT_NODEJS_IP || process.env.IP || c.ip;
var serverPort = process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || c.port;
server.listen(serverPort);

Resolve path to client for npm start


import BaseCourseAPI from './Base';

export default class VirtualClassroomsAPI extends BaseCourseAPI {
  /**
   * Get Braincert Virtual Classroom Access Link
   *
   * @param {number} virtualClassroomId
   * @return {Promise}
   * success response: { link }
   * error response: { errors: String } - An error string will be returned upon validation error.
   */
  accessLink(virtualClassroomId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/${virtualClassroomId}/access_link`,
      this.getCourseId(),
      virtualClassroomId,
      { format: 'json' },
    );
  }

  /**
   * Get Braincert Virtual Classroom list of recorded videos
   *
   * @param {number} virtualClassroomId
   * @return {Promise}
   * response: [video_info_hash]
   */
  recordedVideos(virtualClassroomId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/${virtualClassroomId}/recorded_videos`,
      this.getCourseId(),
      virtualClassroomId,
      { format: 'json' },
    );
  }

  /**
   * Get BrainCert Virtual Classroom recorded video access link
   *
   * @param recordId BrainCert Record ID
   * @return {Promise}
   * success response: { link }
   * error response: { errors: String } - An error string will be returned upon error.
   */
  recordedVideoLink(recordId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/recorded_video_link/${recordId}`,
      this.getCourseId(),
      { format: 'json' },
    );
  }

  _getUrlPrefix() {
    return `/courses/${this.getCourseId()}/virtual_classrooms`;
  }
}

import BaseCourseAPI from './Base';

export default class VirtualClassroomsAPI extends BaseCourseAPI {
  /**
   * Get Braincert Virtual Classroom Access Link
   *
   * @param {number} virtualClassroomId
   * @return {Promise}
   * success response: { link }
   * error response: { errors: String } - An error string will be returned upon validation error.
   */
  accessLink(virtualClassroomId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/${virtualClassroomId}/access_link`,
    );
  }

  /**
   * Get Braincert Virtual Classroom list of recorded videos
   *
   * @param {number} virtualClassroomId
   * @return {Promise}
   * response: [video_info_hash]
   */
  recordedVideos(virtualClassroomId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/${virtualClassroomId}/recorded_videos`,
    );
  }

  /**
   * Get BrainCert Virtual Classroom recorded video access link
   *
   * @param recordId BrainCert Record ID
   * @return {Promise}
   * success response: { link }
   * error response: { errors: String } - An error string will be returned upon error.
   */
  recordedVideoLink(recordId) {
    return this.getClient().get(
      `${this._getUrlPrefix()}/recorded_video_link/${recordId}`,
    );
  }

  _getUrlPrefix() {
    return `/courses/${this.getCourseId()}/virtual_classrooms`;
  }
}

Fix incorrect axios get request arguments


var program = require('commander');

program
    .option('--target <targetDevice>', 'Deploy to specific target')
    .option('--list', 'Lists available targets')
    .option('--release', 'Deploy a release build')
    .option('--nobuild', 'Skip building')
    .option('--browserify', 'Compile plugin JS at build time using browserify instead of runtime')
    .option('--buildConfig <configFile>', 'Use the specified build configuration file.')
    .parse(process.argv);

console.log('build-config: ' + JSON.stringify(program.parseOptions(process.argv)));

var program = require('commander');
var execSync = require('child_process').execSync;
var path = require('path');

var platforms;
var resultCommand = 'cordova run';

program
    .arguments('[platforms...]')
    .option('--list', 'Lists available targets')
    .option('--release', 'Deploy a release build')
    .option('--nobuild', 'Skip building')
    .option('--browserify', 'Compile plugin JS at build time using browserify instead of runtime')
    .option('--target <targetDevice>', 'Deploy to specific target')
    .option('--buildConfig <configFile>', 'Use the specified build configuration file.')
    .option('--platformSpecific <platformOptions>', 'Provide platform specific options')
    .action(function(arg) {
        platforms = arg;
    })
    .parse(process.argv);

platforms = platforms || ['browser'];
platforms.forEach(function (el) {
    resultCommand += ' ' + el;
});
['list', 'release', 'nobuild', 'browserify'].forEach(function (el) {
    if (program[el]) {
        resultCommand += ' --' + el;
    }
});
['target', 'buildConfig', 'platformSpecific'].forEach(function (el) {
    if (program[el]) {
        resultCommand += ' --' + (el === 'platformSpecific' ? ' ' : el + '=') +
            program[el];
    }
});
execSync(resultCommand, {
    stdio: 'inherit',
    cwd: path.join(process.cwd(), '/cordova')
});

Add appsngen widget run command implementation


import { connect } from 'react-redux';
import {
  fetchNavigation,
  setNavigationVisibility,
  fetchTOS,
  setPhaseVisibility,
  setPhasesVisibility,
  setDocumentState,
  fetchRecordTypes,
  fetchAttributeTypes,
  addAction,
  addRecord,
  addPhase,
  changeOrder,
  importItems,
  closeMessage
} from '../modules/home';
import HomeView from '../components/HomeView';

const mapDispatchToProps = {
  fetchNavigation,
  setNavigationVisibility,
  fetchTOS,
  setPhaseVisibility,
  setPhasesVisibility,
  setDocumentState,
  fetchRecordTypes,
  fetchAttributeTypes,
  addAction,
  addRecord,
  addPhase,
  changeOrder,
  importItems,
  closeMessage
};

const mapStateToProps = (state) => {
  return {
    navigation: state.home.navigation,
    recordTypes: state.home.recordTypes,
    selectedTOS: state.home.selectedTOS.tos,
    phases: state.home.selectedTOS.phases,
    actions: state.home.selectedTOS.actions,
    records: state.home.selectedTOS.records,
    selectedTOSPath: state.home.selectedTOS.path,
    isFetching: state.home.isFetching,
    documentState: state.home.selectedTOS.documentState,
    attributeTypes: state.home.attributeTypes,
    message: state.home.message
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(HomeView);

import { connect } from 'react-redux';
import {
  fetchNavigation,
  setNavigationVisibility,
  fetchTOS,
  setPhaseVisibility,
  setPhasesVisibility,
  setDocumentState,
  fetchRecordTypes,
  fetchAttributeTypes,
  addAction,
  addRecord,
  addPhase,
  changeOrder,
  importItems,
  closeMessage
} from '../modules/home';
import HomeView from '../components/HomeView';

const mapDispatchToProps = {
  fetchNavigation,
  setNavigationVisibility,
  fetchTOS,
  setPhaseVisibility,
  setPhasesVisibility,
  setDocumentState,
  fetchRecordTypes,
  fetchAttributeTypes,
  addAction,
  addRecord,
  addPhase,
  changeOrder,
  importItems,
  closeMessage
};

const mapStateToProps = (state) => {
  return {
    navigation: state.navigation,
    recordTypes: state.home.recordTypes,
    selectedTOS: state.tos,
    phases: state.tos.phases,
    actions: state.tos.actions,
    records: state.tos.records,
    selectedTOSPath: state.tos.path,
    isFetching: state.home.isFetching,
    documentState: state.tos.documentState,
    attributeTypes: state.home.attributeTypes,
    message: state.home.message
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(HomeView);

Add correct props to mapStateToProps


angular.module('zeus', [
  'zeus.landing',
  'zeus.results',
  'zeus.details',
  'zeus.services',
  'ngRoute'
])
.controller('zeusController', function($scope, $location) {
  $scope.searchQuery = '';
  $scope.search = function(search) {
    if (search.length < 1) {
      return;
    }
    $location.path('/results/' + search);
    $scope.searchQuery = '';
  };
})
.config(function($routeProvider, $locationProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'app/landing/landing.html',
      controller: 'LandingController'
    })
    .when('/results/:search', {
      templateUrl: 'app/results/results.html',
      controller: 'ResultsController'
    })
    .when('/:type/:id', {
      templateUrl: 'app/details/details.html',
      controller: 'DetailsController'
    });
});

angular.module('zeus', [
  'zeus.landing',
  'zeus.results',
  'zeus.details',
  'zeus.services',
  'ngRoute'
])
.controller('zeusController', function($scope, $location) {
  $scope.searchQuery = '';
  $scope.search = function(search) {
    if (search.length < 1) {
      return;
    }
    $location.path('/results/' + search + '/1');
    $scope.searchQuery = '';
  };
})
.config(function($routeProvider, $locationProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'app/landing/landing.html',
      controller: 'LandingController'
    })
    .when('/results/:search/:page', {
      templateUrl: 'app/results/results.html',
      controller: 'ResultsController'
    })
    .when('/:type/:id', {
      templateUrl: 'app/details/details.html',
      controller: 'DetailsController'
    });
});

Edit results url in router to include page number


"use strict";

var isArguments = require("lodash.isarguments");
var actualMessageValues = require("../actual-message-values");

module.exports = function(referee) {
    function isArrayLike(object) {
        return (
            Array.isArray(object) ||
            (Boolean(object) &&
                typeof object.length === "number" &&
                typeof object.splice === "function") ||
            isArguments(object)
        );
    }

    referee.isArrayLike = isArrayLike;

    referee.add("isArrayLike", {
        assert: function(actual) {
            return isArrayLike(actual);
        },
        assertMessage: "${customMessage}Expected ${actual} to be array like",
        refuteMessage:
            "${customMessage}Expected ${actual} not to be array like",
        expectation: "toBeArrayLike",
        values: actualMessageValues
    });
};

"use strict";

var isArguments = require("lodash.isarguments");
var actualMessageValues = require("../actual-message-values");

module.exports = function(referee) {
    function isArrayLike(object) {
        return (
            Array.isArray(object) ||
            (Boolean(object) &&
                typeof object.length === "number" &&
                typeof object.splice === "function") ||
            isArguments(object)
        );
    }

    referee.add("isArrayLike", {
        assert: function(actual) {
            return isArrayLike(actual);
        },
        assertMessage: "${customMessage}Expected ${actual} to be array like",
        refuteMessage:
            "${customMessage}Expected ${actual} not to be array like",
        expectation: "toBeArrayLike",
        values: actualMessageValues
    });
};

Remove referee.isArrayLike from public API


define([
  'extensions/views/table/table'
],
  function (Table) {
    var capitalize = function(string) {
      return string.replace(/(?:^|\s)\S/, function(letter) { return letter.toUpperCase(); });
    };

    var sanitizeDescription = function (rawDescription) {
      var spaceSeparatedDescription = rawDescription.replace(/-/g, " "),
          lowercaseDescription = spaceSeparatedDescription.replace(/(\s|^)lpa(\s|$)/g, " LPA ");
      return capitalize(lowercaseDescription);
    };

    var HelpUsageTable = Table.extend({

      columns: [
        {
          id: 'description',
          title: 'Description',
          sortable: true,
          getValue: function (model) {
            return sanitizeDescription(model.get('description'));
          }
        },
        {
          id: 'count',
          className: 'count numeric',
          title: 'Usage last week',
          sortable: true,
          defaultDescending: true,
          getValue: function (model) {
            return this.formatNumericLabel(model.get('count'));
          }
        }
      ],

      defaultSortColumn: 1
    });

    return HelpUsageTable;
  });

define([
  'extensions/views/table/table'
],
  function (Table) {

    var HelpUsageTable = Table.extend({

      capitalize: function(string) {
        return string.replace(/(?:^|\s)\S/, function(letter) { return letter.toUpperCase(); });
      },

      sanitizeDescription: function (rawDescription) {
        var spaceSeparatedDescription = rawDescription.replace(/-/g, " "),
          lowercaseDescription = spaceSeparatedDescription.replace(/(\s|^)lpa(\s|$)/g, " LPA ");
        return this.capitalize(lowercaseDescription);
      },

      columns: [
        {
          id: 'description',
          title: 'Description',
          sortable: true,
          getValue: function (model) {
            return this.sanitizeDescription(model.get('description'));
          }
        },
        {
          id: 'count',
          className: 'count numeric',
          title: 'Usage last week',
          sortable: true,
          defaultDescending: true,
          getValue: function (model) {
            return this.formatNumericLabel(model.get('count'));
          }
        }
      ],

      defaultSortColumn: 1
    });

    return HelpUsageTable;
  });

Move functions inside the HelpUsageTable object


App.module("Predictor", function(Mod, App, Backbone, Marionette, $, _) {

  Mod.views.PredictionResultsView = Marionette.ItemView.extend({
    template: 'predictionResultsView',
    tagName: 'div',
    templateHelpers: function() {
      return App.helpers;
    },

    onShow: function() {},

    initialize: function(options) {
      //_.bind(this.templateHelpers.convertDistance, this.unit);
    }
  });

});

App.module("Predictor", function(Mod, App, Backbone, Marionette, $, _) {

  Mod.views.PredictionResultsView = Marionette.ItemView.extend({
    template: 'predictionResultsView',
    tagName: 'div',
    templateHelpers: function() {
      return App.helpers;
    },

    onShow: function() {},

    initialize: function(options) {
      //_.bind(this.templateHelpers.convertDistance, this.unit);
      this.listenTo(App.vent, 'UnitSwitch', function(system) {
        this.render();
      });
    }
  });

});

Handle real time unit switch in results view


Template.editPoint.events({
  'submit form': function (event,template) {
    event.preventDefault();
    var updatedPoint = {
      services: $(template.find('#services')).val(),
      title: template.find('#titleField').value,
      topics: $(template.find('#topics')).val(),
      tosdr: {
        binding: true,
        point: $('input[name="point"]:checked').val(),
        tldr: template.find('#summaryField').value,
        sources: [template.find('#sourceField').value]
      }
    };
    console.log('Save point:', updatedPoint);
    Points.update(this._id, {$set: updatedPoint});
    Router.go('moderatePoints');
  }
});

Template.editPoint.events({
  'submit form': function (event,template) {
    event.preventDefault();
    var updatedPoint = {
      services: $(template.find('#services')).val(),
      title: template.find('#titleField').value,
      topics: $(template.find('#topics')).val(),
      tosdr: {
        binding: true,
        point: $('input[name="point"]:checked').val(),
        tldr: template.find('#summaryField').value,
        sources: [template.find('#sourceField').value]
      }
    };
    console.log('Save point:', updatedPoint);
    Points.update(this._id, {$set: updatedPoint});
    Router.go('points');
  }
});

Fix router after point updated