// Thanks to GVSU https://github.com/gvsulib/Summon-2.0-Scripts) and others for sharing your summon hacks

$(document).ready(function() {

  //Dev
//  var cssPath = '//bypass.hazchem.library.uq.edu.au/summonhacks/summonhacks/',libDetailPageId, newHref, libCurrentURL, record, recordParts, thisID,libCurrentURL = window.location.hash.substring(1);
  //Staging
  var cssPath = '//libio.library.uq.edu.au/summonhacks/',libDetailPageId, newHref, libCurrentURL, record, recordParts, thisID,libCurrentURL = window.location.hash.substring(1);
  // Add custom styles
  $('head').append('<link rel="stylesheet" type="text/css" href="' + cssPath + 'summon2mods.css" />');

  // Accessibility added for advanced search titles
  $('div.searchBox div.queryBox span.caret').parent().attr('title','advanced search');
  $('div.search div.queryBox span.caret').parent().attr('title','advanced search');

  //Add text to the advanced search button to clearly indicate what it is
  $('div.search div.queryBox span.caret').parent().attr('value', 'Advanced');

});

// Thanks to GVSU https://github.com/gvsulib/Summon-2.0-Scripts) and others for sharing your summon hacks

$(document).ready(function() {

  //Dev
//  var cssPath = '//bypass.hazchem.library.uq.edu.au/summonhacks/summonhacks/',libDetailPageId, newHref, libCurrentURL, record, recordParts, thisID,libCurrentURL = window.location.hash.substring(1);
  //Staging
  var cssPath = '//libio.library.uq.edu.au/summonhacks/',libDetailPageId, newHref, libCurrentURL, record, recordParts, thisID,libCurrentURL = window.location.hash.substring(1);
  // Add custom styles
  $('head').append('<link rel="stylesheet" type="text/css" href="' + cssPath + 'summon2mods.css" />');

  // Accessibility added for advanced search titles
  $('div.searchBox div.queryBox span.caret').parent().attr('title','advanced search');
  $('div.search div.queryBox span.caret').parent().attr('title','advanced search');

  //Add text to the advanced search button to clearly indicate what it is
  $('div.search div.queryBox span.caret').parent().prepend('Advanced');

});

Prepend 'Advanced' instead of replacing the carat span


// imports
var gulp = require('gulp');
var browserify  = require('browserify');
var source      = require('vinyl-source-stream');
var uglify = require('gulp-uglify');
var buffer      = require('vinyl-buffer');

// build src
gulp.task('browserify', function(cb){
 	return browserify('./src/app.js', {
            debug: true
        })
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('./www/'));

    cb();
});

// build in release mode
gulp.task('browserify:release', function(cb){

 	return browserify('./src/app.js')
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./www/'));

    cb();
});

// copy fonts
gulp.task('fonts', function(cb){
 	return gulp.src('node_modules/ionic-framework/release/fonts/**')
        .pipe(gulp.dest('./www/fonts/'));
    cb();
});

// copy assets
gulp.task('assets', function(cb){
 	return gulp.src('./assets/**')
        .pipe(gulp.dest('./www/'));
    cb();
});

// copy templates
gulp.task('templates', function(cb){
    return gulp.src('./src/**/*.html')
        .pipe(gulp.dest('./www/'));
    cb();
});

// imports
var gulp = require('gulp');
var browserify  = require('browserify');
var source      = require('vinyl-source-stream');
var uglify = require('gulp-uglify');
var buffer      = require('vinyl-buffer');

// build src
gulp.task('browserify', function(cb){
 	return browserify('./src/app.js', {
            debug: true
        })
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(gulp.dest('./www/'));

    cb();
});

// build in release mode
gulp.task('browserify:release', function(cb){

 	return browserify('./src/app.js')
        .bundle()
        .pipe(source('bundle.js'))
        .pipe(buffer())
        .pipe(uglify())
        .pipe(gulp.dest('./www/'));

    cb();
});

// copy fonts
gulp.task('fonts', function(cb){
 	return gulp.src('node_modules/ionic-npm/fonts/**')
        .pipe(gulp.dest('./www/fonts/'));
    cb();
});

// copy assets
gulp.task('assets', function(cb){
 	return gulp.src('./assets/**')
        .pipe(gulp.dest('./www/'));
    cb();
});

// copy templates
gulp.task('templates', function(cb){
    return gulp.src('./src/**/*.html')
        .pipe(gulp.dest('./www/'));
    cb();
});

Update path fonts gulp task


// Modules.
let gulp = require('gulp'),
    requireDir = require('require-dir'),
    runSequence = require('gulp-run-sequence');

// Require all tasks within tasks directory, including subfolders.
requireDir('./build', { recurse: true });
requireDir('./copy', { recurse: true });
requireDir('./test', { recurse: true });
requireDir('./develop', { recurse: true });
requireDir('./package', { recurse: true });

// gulp command.
gulp.task('default', () => {
    'use strict';

    runSequence(
        'build'
    );
});

// gulp build command.
gulp.task('build', () => {
    'use strict';

    runSequence(
        'copy:lib',
        'copy:fonts',
        'build:less',
        'build:js'
    );
});

// gulp test command.
gulp.task('test', () => {
    'use strict';

    runSequence(
        'test:jscs',
        'test:jshint',
        'test:karma'
    );
});

// gulp package command.
gulp.task('package', () => {
    'use strict';

    runSequence(
        'package:clean',
        'package:css',
        'package:fonts',
        'package:js',
        'package:images',
        'package:partials',
        'package:templates',
        'package:zip'
    );
});

// gulp watch command.
gulp.task('watch', () => {
    'use strict';

    runSequence(
        'develop:watch'
    );
});

// Modules.
let gulp = require('gulp'),
    requireDir = require('require-dir'),
    runSequence = require('gulp-run-sequence');

// Require all tasks within tasks directory, including subfolders.
requireDir('./build', { recurse: true });
requireDir('./copy', { recurse: true });
requireDir('./test', { recurse: true });
requireDir('./develop', { recurse: true });
requireDir('./package', { recurse: true });

// gulp command.
gulp.task('default', () => {
    'use strict';

    runSequence(
        'build'
    );
});

// gulp build command.
gulp.task('build', () => {
    'use strict';

    runSequence(
        'copy:lib',
        'copy:fonts',
        'build:less',
        'build:js'
    );
});

// gulp test command.
gulp.task('test', () => {
    'use strict';

    runSequence(
        'test:jscs',
        'test:jshint',
        'test:karma'
    );
});

// gulp package command.
gulp.task('package', () => {
    'use strict';

    runSequence(
        'build',
        'package:clean',
        'package:css',
        'package:fonts',
        'package:js',
        'package:images',
        'package:partials',
        'package:templates',
        'package:zip'
    );
});

// gulp watch command.
gulp.task('watch', () => {
    'use strict';

    runSequence(
        'develop:watch'
    );
});

Add missing build sequence to gulp package command.


// @flow

type Point = {
  x: number,
  y: number
}

export const convertSpaces = (element: string): string =>
  element.replace('%20', '_').replace(' ', '_')

export const angleRadians = (p1: Point, p2: Point): number =>
  Math.atan2(p2.y - p1.y, p2.x - p1.x)

export const radial = (point: Point, radius: number, radians: number): Point => ({
  x: Math.cos(radians) * radius + point.x,
  y: Math.sin(radians) * radius + point.y
})

export const smallest = (a : number, b : number): number => a < b ? a : b
export const largest = (a : number, b : number): number => a > b ? a : b

Add helper functions smaller and largert


import _ from "lodash"
import Str from "underscore.string"

// Transform from `addr__name_id` to `addr.nameId`
// TODO: Memoize to improve performance
export function serialize(row) {
  if (row == null) return null
  return _.transform(row, function(result, value, key) {
    let segments = key.split("__")
    let record = result

    for (let seg of segments.slice(0, segments.length - 1)) {
      let name = Str.camelize(seg)

      if (record[name] == null) {
        record[name] = {}
      }

      record = record[name]
    }

    let name = Str.camelize(segments[segments.length - 1])
    record[name] = row[key]
  })
}

// Transform from `addr.nameId` to `addr__name_id`
// TODO: Memoize to improve performance
export function deserialize(item) {
  if (item == null) return null

  let row = {}

  function expand(obj, prefix) {
    _.each(obj, function(value, key) {
      let text = Str.underscored(key)
      let name = prefix ? prefix + "__" + text : text
      if (_.isPlainObject(value)) {
        expand(value, name)
      } else {
        row[name] = value
      }
    })
  }

  expand(item, null)

  return row
}

export default {
  serialize,
  deserialize
}

import _ from "lodash"
import Str from "underscore.string"

// Transform from `addr__name_id` to `addr.nameId`
// TODO: Memoize to improve performance
export function serialize(row) {
  if (row == null) return null
  return _.transform(row, function(result, value, key) {
    let segments = key.split("__")
    let record = result

    for (let seg of segments.slice(0, segments.length - 1)) {
      let name = Str.camelize(seg)

      if (record[name] == null) {
        record[name] = {}
      }

      record = record[name]
    }

    let name = Str.camelize(segments[segments.length - 1])
    record[name] = row[key]
  })
}

// Transform from `addr.nameId` to `addr__name_id`
// TODO: Memoize to improve performance
export function deserialize(item) {
  if (item == null) return null

  let row = {}

  function clean(value) {
    if (value instanceof require("buffer").Buffer) {
      // Buffers need to be encoded
      value = "\\x" + value.toString("hex")
    }

    return value
  }

  function expand(obj, prefix) {
    _.each(obj, function(value, key) {
      let text = Str.underscored(key)
      let name = prefix ? prefix + "__" + text : text
      if (_.isPlainObject(value)) {
        expand(value, name)
      } else {
        row[name] = clean(value, name)
      }
    })
  }

  expand(item, null)

  return row
}

export default {
  serialize,
  deserialize
}

Add encoding for Buffers (that pass through deserialize)


process.title = 'test-server';

var fs = require('fs');
var hapi = require('hapi');
var inert   = require('inert');

var root = fs.readFileSync(__dirname + '/layout_partials/root.hbt').toString();

var server = new hapi.Server();

server.connection({
  host: '0.0.0.0',
  port: 8080
});

server.register(inert, function() {});

server.route({
  method: 'GET',
  path: root + '/{param*}',
  handler: {
    directory: {
      path: __dirname + '/http',
      index: true
    }
  }
});

server.start(function () {
  console.log('Server running at: ' + server.info.uri + root + '/');
});

process.title = 'test-server';

var fs = require('fs');
var hapi = require('hapi');
var inert   = require('inert');

var root = fs.readFileSync(__dirname + '/layout_partials/root.hbt').toString();

var server = new hapi.Server();

server.connection({
  host: '0.0.0.0',
  port: 8080
});

server.register(inert, function() {});

server.route({
  method: 'GET',
  path: root + '/{param*}',
  handler: {
    directory: {
      path: __dirname + '/http',
      index: true
    }
  }
});

server.start(function () {
  console.log('Server running at: http://localhost:8080' + root + '/');
});

Change test server location message


/**
 * An implementation of insertionSort
 *
 * @name insertionSort
 * @function
 * @param {Array} xs the list to sort
 */
export function insertionSort(xs) {
  for (let i = 1; i < xs.length; i++) {
    for (let j = 0; j < i; j++) {
      if(xs[i] < xs[j]) {
        xs.splice(j, 0, xs.splice(i, 1)[0]);
      }
    }
  }

  return xs;
}

/**
 * An implementation of insertionSort
 *
 * @name insertionSort
 * @function
 * @param {Array} xs the list to sort
 *
 * 1. Assume the first item is sorted.
 * 2. Check each item in the list to see if its smaller than the first item.
 * 3. If any smaller item was found insert it in the space before the first item.
 * 4. Repeat 1 - 3 for every other item in the list.
 */
export function insertionSort(xs) {
  // 1.
  for (let i = 1; i < xs.length; i++) {
    for (let j = 0; j < i; j++) {
      // 2.
      if(xs[i] < xs[j]) {
        // 3.
        xs.splice(j, 0, xs.splice(i, 1)[0]);
      }
    }
  }

  return xs;
}

Add documentation for each step in the insertionSort process


// __spec__.js
import React from 'react';
import { shallow } from 'enzyme';

import { WithDragAndDrop, DraggableContext } from './with-drag-and-drop';
import Row from '../row';

describe('WithDragAndDrop', () => {
  it('has a DragDropContainer', () => {
    expect(WithDragAndDrop.name).toBe('DragDropContainer');
  });

  it('calls connectDragSource and connectDropTarget', () => {
    const OriginalComponent = WithDragAndDrop.DecoratedComponent;

    // Stub the React DnD connector functions with an identity function
    // -- https://react-dnd.github.io/react-dnd/docs-testing.html
    const identity = jasmine.createSpy('identity'); // el => el;

    let wrapper = shallow(
      <OriginalComponent
          connectDragSource={ identity }
          connectDropTarget={ identity }>
        <Row />
      </OriginalComponent>
    );

    expect(identity.calls.count()).toEqual(2);
  });
});

// __spec__.js
import React from 'react';
import { shallow } from 'enzyme';

import { WithDragAndDrop, DraggableContext } from './with-drag-and-drop';

describe('WithDragAndDrop', () => {
  it('has a DragDropContainer', () => {
    expect(WithDragAndDrop.name).toBe('DragDropContainer');
  });

  it('calls connectDragSource and connectDropTarget', () => {
    const OriginalComponent = WithDragAndDrop.DecoratedComponent;

    // Stub the React DnD connector functions with an identity function
    //
    // Track calls using count.
    // Return el, otherwise React complains that WithDragAndDrop.render()
    // doesn't return a valid React element.
    let count = 0;
    const identity = (el) => {
      count += 1;
      return el;
    };

    let wrapper = shallow(
      <OriginalComponent
          connectDragSource={ identity }
          connectDropTarget={ identity }>
        <div>
          Draggable
        </div>
      </OriginalComponent>
    );

    expect(count).toEqual(2);
  });
});

Fix spec that caused an error in React 15


import React from 'react'
import ToolSwitcher from './ToolSwitcher'
import RenderTool from './RenderTool'
import {Router, Route, NotFound, Redirect} from 'router:@sanity/base/router'
import styles from '../styles/DefaultLayout.css'
import tools from 'all:tool:@sanity/base/tool'
import absolutes from 'all:component:@sanity/base/absolutes'
import LoginStatus from './LoginStatus'
import Logo from './Logo'

class DefaultLayout extends React.Component {
  render() {
    const activeToolName = this.props.params.tool

    return (

            <Logo />

          <ToolSwitcher tools={tools} activeToolName={activeToolName} className={styles.toolSwitcher} />
          <LoginStatus />

          <Router>
            <Redirect path="/" to={`/${tools[0].name}`} />
            <Route path="/:tool/*" component={RenderTool} />
          </Router>

        {absolutes.map((Abs, i) => <Abs key={i} />)}

    )
  }
}

export default DefaultLayout

import React from 'react'
import ToolSwitcher from './ToolSwitcher'
import RenderTool from './RenderTool'
import {Router, Route, NotFound, Redirect} from 'router:@sanity/base/router'
import styles from '../styles/DefaultLayout.css'
import tools from 'all:tool:@sanity/base/tool'
import absolutes from 'all:component:@sanity/base/absolutes'
import LoginStatus from './LoginStatus'
import Logo from './Logo'

class DefaultLayout extends React.Component {
  render() {
    const activeToolName = this.props.params.tool

    return (

            <Logo />

          <ToolSwitcher tools={tools} activeToolName={activeToolName} className={styles.toolSwitcher} />
          <LoginStatus />

          <Router>
            <Redirect path="/" to={`/${tools.length ? tools[0].name : ''}`} />
            <Route path="/:tool/*" component={RenderTool} />
          </Router>

        {absolutes.map((Abs, i) => <Abs key={i} />)}

    )
  }
}

export default DefaultLayout

Fix bug when no tools were installed


// inferno module
import React from 'react';
import ReactDOM from "react-dom";
import { Router, Route, browserHistory } from 'react-router';

// scss module
import './scss/main.scss';

// state modules
import { Provider } from 'react-redux';
import store from './shared/store';

// app component
import App from './App.jsx';
import Workspace from './Workspace.jsx';
import WorkspaceController from './components/workspaces/WorkspacesController.jsx';

const routes = (
    <Provider store={ store }>
        <Router history={ browserHistory }>
            <Route component={ App }>
                <Route path="/" component={ WorkspaceController } />
            </Route>
        </Router>
    </Provider>
);

ReactDOM.render(routes, document.getElementById('app-root'));

// inferno module
import React from 'react';
import ReactDOM from "react-dom";
import { Router, Route, browserHistory } from 'react-router';

// scss module
import './scss/main.scss';

// state modules
import { Provider } from 'react-redux';
import store from './shared/store';

// app component
import App from './App.jsx';
import WorkspaceController from './components/sidebar/WorkspacesController.jsx';

const routes = (
    <Provider store={ store }>
        <Router history={ browserHistory }>
            <Route component={ App }>
                <Route path="/" component={ WorkspaceController } />
            </Route>
        </Router>
    </Provider>
);

ReactDOM.render(routes, document.getElementById('app-root'));

Fix route from app.jsx to workspace controller component


const webpackConfig = require('./webpack.config');
webpackConfig.devtool = 'inline-source-map';
webpackConfig.externals = {
  'react/lib/ExecutionEnvironment': true,
  'react/lib/ReactContext': 'window'
};

module.exports = (config) => {
  config.set({
    browsers: ['PhantomJS'],
    singleRun: true,
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai'],
    files: ['tests.webpack.js'],
    plugins: [
      'karma-phantomjs-launcher',
      'karma-chai',
      'karma-mocha',
      'karma-sourcemap-loader',
      'karma-webpack',
      'karma-mocha-reporter',
      'karma-sinon',
      'karma-sinon-chai'
    ],
    preprocessors: {
      'tests.webpack.js': ['webpack', 'sourcemap']
    },
    reporters: ['mocha'],
    webpack: webpackConfig,
    webpackServer: {
      noInfo: true
    },
    autoWatch: true
  });
};

const webpackConfig = require('./webpack.config');
webpackConfig.devtool = 'inline-source-map';
webpackConfig.externals = {
  'react/lib/ExecutionEnvironment': true,
  'react/lib/ReactContext': 'window',
  'react/addons': true
};

module.exports = (config) => {
  config.set({
    browsers: ['PhantomJS'],
    singleRun: true,
    frameworks: ['mocha', 'chai', 'sinon', 'sinon-chai'],
    files: ['tests.webpack.js'],
    plugins: [
      'karma-phantomjs-launcher',
      'karma-chai',
      'karma-mocha',
      'karma-sourcemap-loader',
      'karma-webpack',
      'karma-mocha-reporter',
      'karma-sinon',
      'karma-sinon-chai'
    ],
    preprocessors: {
      'tests.webpack.js': ['webpack', 'sourcemap']
    },
    reporters: ['mocha'],
    webpack: webpackConfig,
    webpackServer: {
      noInfo: true
    },
    autoWatch: true
  });
};

Fix karma tests not building


module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', 'browserify'],
    files: [
      'test/*'
    ],
    reporters: ['progress', 'coverage'],
    port: 9876,
    runnerPort: 9100,
    colors: true,
    logLevel: config.LOG_DEBUG,
    autoWatch: true,
    browsers: ['PhantomJS'],
    captureTimeout: 60000,
    singleRun: false,
    browserify: {
      watch: true,
      transform: ['browserify-shim', 'browserify-istanbul']
    },
    preprocessors: {
        'test/*': ['browserify'],
        'lib/*': ['coverage']
    },
    coverageReporter: {
      type : 'html',
      dir : 'coverage/'
    }
  });
};

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', 'browserify'],
    files: [
      'test/*'
    ],
    reporters: ['progress', 'coverage'],
    port: 9876,
    runnerPort: 9100,
    colors: true,
    logLevel: config.LOG_DEBUG,
    autoWatch: true,
    browsers: ['PhantomJS'],
    captureTimeout: 60000,
    singleRun: false,
    browserify: {
      watch: true,
      debug: true,
      transform: ['browserify-shim', 'browserify-istanbul']
    },
    preprocessors: {
        'test/*': ['browserify'],
        'lib/*': ['coverage']
    },
    coverageReporter: {
      type : 'html',
      dir : 'coverage/'
    }
  });
};

Add source maps to tests


var rows = 0;
var cols = 10;
var table;
var edit_border = "thin dotted grey";

function text(str)
{
    return document.createTextNode(str);
}

function init()
{
    table = document.getElementById("wftable");
    addRows(4);
}

function addRows(numrows)
{
    numrows += rows;

    if (table.tBodies.length < 1) {
	table.appendChild(document.createElement('tbody'));
    }

    for (; rows < numrows; rows++) {
	table.tBodies[table.tBodies.length - 1].appendChild(text("\n"));
	var row = table.insertRow(-1);
	row.appendChild(text("\n"));

	for (c = 0; c < cols; c++) {
	    var cell = row.insertCell(-1);
	    cell.innerHTML = rows.toString().concat(",", c.toString());
	    cell.style.border = edit_border;
	    row.appendChild(text("\n"));
	}
    }
}

function addCols(numcols)
{
    cols += numcols;

    for (r = 0; r < rows; r++) {
	var row = table.rows[r];

	for (c = row.cells.length; c < cols; c++) {
	    var cell = row.insertCell(-1);
	    cell.innerHTML = r.toString().concat(",", c.toString());
	    cell.style.border = edit_border;
	    row.appendChild(text("\n"));
	}
    }
}

var rows = 0;
var cols = 10;
var table;
var edit_border = "thin dotted grey";

function text(str)
{
    return document.createTextNode(str);
}

function cellContents(rowindex, colindex)
{
    return " ";
}

function init()
{
    table = document.getElementById("wftable");
    addRows(4);
}

function addRows(numrows)
{
    numrows += rows;

    if (table.tBodies.length < 1) {
	table.appendChild(document.createElement('tbody'));
    }

    for (; rows < numrows; rows++) {
	table.tBodies[table.tBodies.length - 1].appendChild(text("\n"));
	var row = table.insertRow(-1);
	row.appendChild(text("\n"));

	for (c = 0; c < cols; c++) {
	    var cell = row.insertCell(-1);
	    cell.innerHTML = cellContents(rows, c);
	    cell.style.border = edit_border;
	    row.appendChild(text("\n"));
	}
    }
}

function addCols(numcols)
{
    cols += numcols;

    for (r = 0; r < rows; r++) {
	var row = table.rows[r];

	for (c = row.cells.length; c < cols; c++) {
	    var cell = row.insertCell(-1);
	    cell.innerHTML = cellContents(r, c);
	    cell.style.border = edit_border;
	    row.appendChild(text("\n"));
	}
    }
}

Add cellContents: nbsp for now


var web3 = require('web3')
var rm = require('web3/lib/web3/requestmanager')

var web3api = function(provider) {

    this.requestmanager = rm.getInstance();

    try {
        web3.setProvider(new web3.providers.HttpProvider(provider));
    } catch(e) {
        console.error("Could not connect: %s", e);
    }
}

web3api.prototype.getBalance = function(address) {
    var bignum = web3.eth.getBalance('0x' + address);
    return bignum.toNumber();
}

web3api.prototype.injectTransaction = function(signedTx) {
    // this function will only work if you run the go client
    return this.requestmanager.send({
        method: 'eth_sendRawTransaction',
        params: ['0x' + signedTx]
    });
}

web3api.prototype.getNonce = function(address) {
    return web3.eth.getTransactionCount('0x' + address);
}

web3api.prototype.estimateGas = function(txObject) {
    return web3.eth.estimateGas(txObject);
}

web3api.prototype.getWeb3 = function() {
    return web3;
}

module.exports = web3api;

var web3 = require('web3')
var rm = require('web3/lib/web3/requestmanager')

var web3api = function(provider) {

    this.requestmanager = rm.getInstance();

    try {
        web3.setProvider(new web3.providers.HttpProvider(provider));
    } catch(e) {
        console.error("Could not connect: %s", e);
    }
}

web3api.prototype.getBalance = function(address) {
    var bignum = web3.eth.getBalance('0x' + address);
    return bignum.toNumber();
}

web3api.prototype.injectTransaction = function(signedTx) {
    // this function will only work if you run the go client
    return this.requestmanager.send({
        method: 'eth_sendRawTransaction',
        params: ['0x' + signedTx]
    }).slice(2);
}

web3api.prototype.getNonce = function(address) {
    return web3.eth.getTransactionCount('0x' + address);
}

web3api.prototype.estimateGas = function(txObject) {
    return web3.eth.estimateGas(txObject);
}

web3api.prototype.getWeb3 = function() {
    return web3;
}

module.exports = web3api;

Remove the prepended 0x returned from RPC.


function searchRequestBuilder(request) {
}
exports.search = searchRequestBuilder;

function searchRequestBuilder(request) {
  var params = request.params;

  var queries = {};
  queries.result = {
    source: params.tableName,
    output: {
      startTime:   true,
      elapsedTime: true,
      count:       true,
      attributes:  true,
      recodes:     true
    }
  };

  if (params.attributes)
    queries.result.attributes = params.attributes.split(',');
  if (params.limit)
    queries.result.limit = parseInt(params.limit);
  if (params.match_escalation_threshold)
    queries.result.matchEscalationThreshold = parseInt(params.match_escalation_threshold);
  if (params.match_to)
    queries.result.matchTo = params.match_to.split(',');
  if (params.offset)
    queries.result.offset = parseInt(params.offset);
  if (params.query)
    queries.result.query = params.query;
  if (params.sort_by)
    queries.result.sortBy = params.sort_by.split(',');

  return { queries: queries };
}
exports.search = searchRequestBuilder;

Implement request message builder from REST request


import { uglify } from "rollup-plugin-uglify";
import typescript from "rollup-plugin-typescript2";
import resolve from "rollup-plugin-node-resolve";
import license from "rollup-plugin-license";

const base = {
	input: "src/skinview3d.ts",
	output: [
		{
			format: "umd",
			name: "skinview3d",
			file: "dist/skinview3d.browser.js",
			indent: "\t",
			globals: {
				"three": "THREE"
			}
		},
		{
			format: "es",
			file: "dist/skinview3d.module.js",
			indent: "\t"
		}
	],
	external: [
		"three"
	],
	plugins: [
		resolve(),
		typescript(),
		license({
			banner: `
				skinview3d (https://github.com/bs-community/skinview3d)

				MIT License
				`
		})
	]
};

export default [
	base,
	Object.assign({}, base, {
		output: Object.assign({}, base.output[0], { file: "dist/skinview3d.browser.min.js" }),
		plugins: (() => {
			const plugin = base.plugins.slice();
			plugin.splice(1, 0, uglify());
			return plugin;
		})()
	})
];

import { uglify } from "rollup-plugin-uglify";
import typescript from "rollup-plugin-typescript2";
import resolve from "rollup-plugin-node-resolve";
import license from "rollup-plugin-license";

const base = {
	input: "src/skinview3d.ts",
	output: [
		{
			format: "umd",
			name: "skinview3d",
			file: "dist/skinview3d.js",
			indent: "\t",
			globals: {
				"three": "THREE"
			}
		},
		{
			format: "es",
			file: "dist/skinview3d.module.js",
			indent: "\t"
		}
	],
	external: [
		"three"
	],
	plugins: [
		resolve(),
		typescript(),
		license({
			banner: `
				skinview3d (https://github.com/bs-community/skinview3d)

				MIT License
				`
		})
	]
};

export default [
	base,
	Object.assign({}, base, {
		output: Object.assign({}, base.output[0], { file: "dist/skinview3d.min.js" }),
		plugins: (() => {
			const plugin = base.plugins.slice();
			plugin.splice(1, 0, uglify());
			return plugin;
		})()
	})
];

Fix filename of bundled file


/**
 * @fileoverview Enforce no single element style arrays
 * @author Michael Gall
 */

'use strict';

module.exports = {
  meta: {
    docs: {
      description:
        'Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes',
      category: 'Stylistic Issues',
      recommended: false,
      url: '',
    },
    fixable: 'code',
  },

  create(context) {
    function reportNode(JSXExpressionNode) {
      context.report({
        node: JSXExpressionNode,
        message:
          'Single element style arrays are not necessary and cause unnecessary re-renders',
        fix(fixer) {
          const realStyleNode = JSXExpressionNode.value.expression.elements[0];
          const styleSource = context.getSourceCode().getText(realStyleNode);
          return fixer.replaceText(JSXExpressionNode.value.expression, styleSource);
        },
      });
    }

    // --------------------------------------------------------------------------
    // Public
    // --------------------------------------------------------------------------
    return {
      JSXAttribute(node) {
        if (node.name.name !== 'style') return;
        if (node.value.expression.type !== 'ArrayExpression') return;
        if (node.value.expression.elements.length === 1) {
          reportNode(node);
        }
      },
    };
  },
};

/**
 * @fileoverview Enforce no single element style arrays
 * @author Michael Gall
 */

'use strict';

module.exports = {
  meta: {
    docs: {
      description:
        'Disallow single element style arrays. These cause unnecessary re-renders as the identity of the array always changes',
      category: 'Stylistic Issues',
      recommended: false,
      url: '',
    },
    fixable: 'code',
  },

  create(context) {
    function reportNode(JSXExpressionNode) {
      context.report({
        node: JSXExpressionNode,
        message:
          'Single element style arrays are not necessary and cause unnecessary re-renders',
        fix(fixer) {
          const realStyleNode = JSXExpressionNode.value.expression.elements[0];
          const styleSource = context.getSourceCode().getText(realStyleNode);
          return fixer.replaceText(JSXExpressionNode.value.expression, styleSource);
        },
      });
    }

    // --------------------------------------------------------------------------
    // Public
    // --------------------------------------------------------------------------
    return {
      JSXAttribute(node) {
        if (node.name.name !== 'style') return;
        if (!node.value.expression) return;
        if (node.value.expression.type !== 'ArrayExpression') return;
        if (node.value.expression.elements.length === 1) {
          reportNode(node);
        }
      },
    };
  },
};

Fix issue when style prop is not an expression


module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  extends: 'airbnb-base',
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // check if imports actually resolve
  'settings': {
    'import/resolver': {
      'webpack': {
        'config': 'build/webpack.base.conf.js'
      }
    }
  },
  // add your custom rules here
  'rules': {
    // don't require .vue extension when importing
    'import/extensions': ['error', 'always', {
      'js': 'never',
      'vue': 'never'
    }],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'no-console': process.env.NODE_ENV === 'production' ? 2 : 0
  }
}

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  extends: 'airbnb-base',
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // check if imports actually resolve
  'settings': {
    'import/resolver': {
      'webpack': {
        'config': 'build/webpack.base.conf.js'
      }
    }
  },
  // add your custom rules here
  'rules': {
    // don't require .vue extension when importing
    'import/extensions': ['error', 'always', {
      'js': 'never',
      'vue': 'never'
    }],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
    'no-console': process.env.NODE_ENV === 'production' ? 2 : 0
  },
  'env': {
    'browser': true
  }
}

Stop ESLint complaining about localStorage


import React from 'react'

import GraphiQL from 'graphiql'
import 'graphiql/graphiql.css'

export default class extends React.Component {
	static useNavigation = false

	fetch(params) {
		return fetch('/graphql', {
			credentials: 'same-origin',
			method: 'POST',
			headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
			body: JSON.stringify(params),
		}).then(response => response.json())
	}

	render() {
		return <GraphiQL fetcher={this.fetch} />
	}
}

import React from 'react'

import GraphiQL from 'graphiql'
import 'graphiql/graphiql.css'

import Breadcrumbs from '../components/Breadcrumbs'

export default class extends React.Component {
	static useNavigation = false

	fetch(params) {
		return fetch('/graphql', {
			credentials: 'same-origin',
			method: 'POST',
			headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
			body: JSON.stringify(params),
		}).then(response => response.json())
	}

	render() {
		return <div>
			<Breadcrumbs items={[['Run GraphQL queries', '/graphiql']]} />
			<GraphiQL fetcher={this.fetch} />
		</div>
	}
}

Add Breadcrumbs to graphiql page


import styled from 'styled-components';
import CardImgWrapper from '../CardImgWrapper';

const FileWrapper = styled(CardImgWrapper)`
  height: 401px;
  width: 100%;
  display: flex;
  > img {
    width: 100%;
    object-fit: contain;
    margin: auto;
  }

  .cropper-view-box {
    outline-color: #ffffff;
  }
  .cropper-point {
    background-color: #ffffff;
    border-radius: 50%;
  }

  .point-se {
    &:before {
      display: none;
    }
    height: 5px;
    width: 5px;
  }
`;

export default FileWrapper;

import styled from 'styled-components';
import CardImgWrapper from '../CardImgWrapper';

const FileWrapper = styled(CardImgWrapper)`
  height: 401px;
  width: 100%;
  display: flex;
  > img {
    width: 100%;
    object-fit: contain;
    margin: auto;
  }

  .cropper-view-box {
    outline-color: ${({ theme }) => theme.main.colors.white};
  }
  .cropper-point {
    background-color: ${({ theme }) => theme.main.colors.white};
    border-radius: 50%;
  }

  .point-se {
    &:before {
      display: none;
    }
    height: 5px;
    width: 5px;
  }
`;

export default FileWrapper;

Use theme for bkg color


'use strict';

var EditprofileModel = require('../models/editprofile');
var easySession = require('easy-session');

//Middleware
var auth = require('../lib/auth');

module.exports = function (router) {

    var model = new EditprofileModel();

    router.get('/', auth(), easySession.isLoggedIn(), function (req, res) {

        res.render('editprofile', model);

    });

};

'use strict';

var easySession = require('easy-session');

//Middleware
var auth = require('../lib/auth');

module.exports = function (router) {

    router.get('/', auth(), easySession.isLoggedIn(), function (req, res) {

		if(req.session.hasRole(['board', 'user']) && req.session.userID) {
			//Use session varibale instead of get variable
			User.findOne({_id: req.session.userID}, {role: 1, name: 1}, function(err, profile){

				if(err){
					console.error(err);
					throw err; //Handle better later...
				}
				var params = {
					userID: req.session.userID,
					ownerID: profile.id
				};

				if(new resourceCheck(req, params)){
					var model = {user: profile};
					return res.render('editprofile', model);

				}

				if(!(new resourceCheck(req, params))){
					return res.sendStatus(403);
				}

			});

		}else{

			return res.render('errors/404', {url:req.url});

		}

    });

};

Update the profile edit route handler with resoruce check function.


import React, {PropTypes, Component} from 'react';
import {connect} from 'react-algoliasearch-helper';

export default function createHitsPerPage(Composed) {
  class HitsPerPageWrapper extends Component {
    static propTypes = {
      helper: PropTypes.object.isRequired,
    };

    refine = hitsPerPage => {
      this.props.helper.setState(
        this.props.helper.getState().setHitsPerPage(hitsPerPage)
      ).search();
    };

    render() {
      return (
        <Composed
          refine={this.refine}
          {...this.props}
        />
      );
    }
  }

  return connect(state => ({
    hitsPerPage: state.searchParameters.hitsPerPage,
  }))(HitsPerPageWrapper);
}

import React, {PropTypes, Component} from 'react';
import {connect} from 'react-algoliasearch-helper';

export default function createHitsPerPage(Composed) {
  class HitsPerPageWrapper extends Component {
    static propTypes = {
      helper: PropTypes.object.isRequired,
    };

    refine = hitsPerPage => {
      this.props.helper.setQueryParameter('hitsPerPage', hitsPerPage).search();
    };

    render() {
      return (
        <Composed
          refine={this.refine}
          {...this.props}
        />
      );
    }
  }

  return connect(state => ({
    hitsPerPage: state.searchParameters.hitsPerPage,
  }))(HitsPerPageWrapper);
}

Use helper.setQueryParameter instead of manipulating the state directly


Ext.define('SlateAdmin.view.progress.NavPanel', {
    extend: 'SlateAdmin.view.LinksNavPanel',
    xtype: 'progress-navpanel',

    title: 'Student Progress',
    data: true,

    applyData: function(data) {
        if (data !== true) {
            return data;
        }

        return [
            {
                text: 'Section Interim Reports',
                href: '#progress/interims/report',
                children: [
                    {
                        text: 'Print / Export',
                        href: '#progress/interims/print'
                    },
                    {
                        text: 'Email',
                        href: '#progress/interims/email'
                    }
                ]
            },
            {
                text: 'Section Term Reports',
                href: '#progress/terms/report',
                children: [
                    {
                        text: 'Search & Print',
                        href: '#progress/terms/print'
                    },
                    {
                        text: 'Email',
                        href: '#progress/terms/email'
                    }
                ]
            }
        ];
    }
});

Ext.define('SlateAdmin.view.progress.NavPanel', {
    extend: 'SlateAdmin.view.LinksNavPanel',
    xtype: 'progress-navpanel',

    title: 'Student Progress',
    data: true,

    applyData: function(data) {
        if (data !== true) {
            return data;
        }

        return [
            {
                text: 'Section Interim Reports',
                href: '#progress/interims/report',
                children: [
                    {
                        text: 'Print / Export',
                        href: '#progress/interims/print'
                    },
                    {
                        text: 'Email',
                        href: '#progress/interims/email'
                    }
                ]
            },
            {
                text: 'Section Term Reports',
                href: '#progress/terms/report',
                children: [
                    {
                        text: 'Search & Print',
                        href: '#progress/terms/print'
                    }
                    // ,{
                    //     text: 'Email',
                    //     href: '#progress/terms/email'
                    // }
                ]
            }
        ];
    }
});

Comment out narratives email menu item


import React, { PureComponent } from 'react';
import { Counter, Heading1, Section } from '../../components';
import style from './counter.css';

class CounterTest extends PureComponent {

  render () {
    return (

          <Heading1>Counters</Heading1>

              <Counter className={style.counter} count={999} />
              <Counter className={style.counter} count={9} size="small" />
              <Counter className={style.counter} color="ruby" count={100} maxCount={99} />
              <Counter className={style.counter} color="ruby" count={9} size="small" />
              <Counter className={style.counter} color="ruby" />
              <Counter className={style.counter} color="ruby" size="small" />

    );
  }
}

export default CounterTest;

import React, { PureComponent } from 'react';
import { Counter, Heading1, Section } from '../../components';
import style from './counter.css';

class CounterTest extends PureComponent {

  render () {
    return (

          <Heading1>Counters</Heading1>

              <Counter className={style.counter} count={999} />
              <Counter className={style.counter} count={9} size="small" />
              <Counter className={style.counter} count={0} size="small" />
              <Counter className={style.counter} color="ruby" count={100} maxCount={99} />
              <Counter className={style.counter} color="ruby" count={9} size="small" />
              <Counter className={style.counter} color="ruby" count={0} size="small" />
              <Counter className={style.counter} color="ruby" />
              <Counter className={style.counter} color="ruby" size="small" />

    );
  }
}

export default CounterTest;

Add extra Counter component in spec to show the result with value '0'


// Download the Node helper library from twilio.com/docs/node/install
// These consts are your accountSid and authToken from https://www.twilio.com/console
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const express = require('express');
const app = express();

app.post('/enqueue_call', (request, response) => {
  const resp = new VoiceResponse();

  const json = { account_number: '12345abcdef' };

  resp
    .enqueueTask({
      workflowSid: 'WW0123456789abcdef0123456789abcdef',
      waitUrl: '/hold_music.php',
      action: '/post_bridge_survey.php',
    })
    .task({}, JSON.stringify(json));

  response.setHeader('Content-Type', 'application/xml');
  response.write(resp.toString());
  response.end();
});

app.listen(8080);

// Download the Node helper library from twilio.com/docs/node/install
// These consts are your accountSid and authToken from https://www.twilio.com/console
const VoiceResponse = require('twilio').twiml.VoiceResponse;
const express = require('express');
const app = express();

app.post('/enqueue_call', (request, response) => {
  const resp = new VoiceResponse();

  const json = { account_number: '12345abcdef' };

  resp
    .enqueue({
      workflowSid: 'WW0123456789abcdef0123456789abcdef',
      waitUrl: '/hold_music.php',
      action: '/post_bridge_survey.php',
    })
    .task({}, JSON.stringify(json));

  response.setHeader('Content-Type', 'application/xml');
  response.write(resp.toString());
  response.end();
});

app.listen(8080);

Update snippet to use .enqueue


angular.module("bmComponents").directive("bmChosen", ["$timeout",
    function ($timeout) {

        return {
            restrict : "A",
            link : function(scope, element, attrs) {
                element.chosen();

                scope.$watch(attrs.bmChosen, function (data) {
                    if (data) element.trigger("chosen:updated");
                });

                scope.$watch(attrs.ngDisabled, function (data) {
                    if (data === false || data === true) element.trigger("chosen:updated");
                });

                scope.$on("switchMode", function() {
                    var classes = element.attr("class").split(/\s+/),
                        spanClass = classes.filter(function (className) {
                            return className.indexOf("span") > -1;
                        })[0];

                    element.before("

");
                    element.next(".chosen-container").css("width", element.prev().css("width"));
                });
            }
        }
    }
]);

angular.module("bmComponents").directive("bmChosen", ["$timeout",
    function ($timeout) {

        return {
            restrict : "A",
            link : function(scope, element, attrs) {
                element.chosen();

                scope.$watch(attrs.bmChosen, function (data) {
                    if (data) {
                        $timeout(function () {
                            element.trigger("chosen:updated");
                        });
                    }
                });

                scope.$watch(attrs.ngDisabled, function (data) {
                    if (data === false || data === true) {
                        $timeout(function () {
                            element.trigger("chosen:updated");
                        });
                    }
                });

                scope.$on("switchMode", function() {
                    $timeout(function () {
                        element.next(".chosen-container").css("width", element.parent().width() + "px");
                    });
                });
            }
        }
    }
]);

Update chosen directive to work with newer AngularJS versions.


// @flow

import React from 'react';
import { DatePicker } from 'antd';
import { func, string, any } from 'prop-types';
import moment from 'moment';

import CellStyled from './Cell.styles';
import { getDateFormat } from '../../utils';
import { MODES } from '../../constants';

type Props = {
	children: any,
	onChange: func,
	format?: string,
	mode: string,
};

const DateCell = ({ children, onChange, format, mode }: Props) => (
	<CellStyled>
		{mode === MODES.EDIT ? (
			<DatePicker
				showTime
				defaultValue={
					children ? moment(children, getDateFormat(format)) : null
				}
				format={getDateFormat(format)}
				css={{
					width: '100% !important',
				}}
				onChange={(momentObject, dateString) => {
					if (children !== dateString) {
						// only update value if date string has changed
						onChange(dateString || null);
					}
				}}
			/>
		) : (
			children && moment(children).format(getDateFormat(format))
		)}
	</CellStyled>
);

DateCell.propTypes = {
	onChange: func.isRequired,
	children: any,
	format: string,
	mode: string,
};

export default DateCell;

// @flow

import React from 'react';
import { DatePicker } from 'antd';
import { func, string, any } from 'prop-types';
import moment from 'moment';

import CellStyled from './Cell.styles';
import { getDateFormat } from '../../utils';
import { MODES } from '../../constants';

type Props = {
	children: any,
	onChange: func,
	format?: string,
	mode: string,
};

const DateCell = ({ children, onChange, format, mode }: Props) => (
	<CellStyled>
		{mode === MODES.EDIT ? (
			<DatePicker
				showTime
				defaultValue={children ? moment(children) : null}
				format={getDateFormat(format)}
				css={{
					width: '100% !important',
				}}
				onChange={(momentObject, dateString) => {
					if (children !== dateString) {
						// only update value if date string has changed
						onChange(dateString || null);
					}
				}}
			/>
		) : (
			children && moment(children).format(getDateFormat(format))
		)}
	</CellStyled>
);

DateCell.propTypes = {
	onChange: func.isRequired,
	children: any,
	format: string,
	mode: string,
};

export default DateCell;

Fix date picker NAN issue


import Phaser from 'phaser'

export default class extends Phaser.Sprite {
    constructor ({ game, x, y, asset }) {
        super(game, x, y, asset)
        this.anchor.setTo(0.5)
        this.height = 40;
        this.width = 40;

        this.game.physics.p2.enable(this, false);
        this.body.setCircle(10);
        this.body.mass = 50;
        this.body.damping = 0.98;
    }

    update () {
        var bodies = this.game.physics.p2.hitTest(this.position, [this.game.road.body]);
        if (bodies.length === 0) {
            this.scale.setTo(this.scale.x-0.01, this.scale.y-0.01);
            if (this.scale.x < 0.05) {
                this.destroy();
            }
        }
    }

    onBeginContact() {
    }
}

import Phaser from 'phaser'

export default class extends Phaser.Sprite {
    constructor ({ game, x, y, asset }) {
        super(game, x, y, asset)
        this.anchor.setTo(0.5)
        this.height = 40;
        this.width = 40;

        this.game.physics.p2.enable(this, false);
        this.body.setCircle(10);
        this.body.mass = 50;
        this.body.damping = 0.98;
    }

    update () {
        /*var bodies = this.game.physics.p2.hitTest(this.position, [this.game.road.body]);
        if (bodies.length === 0) {
            this.scale.setTo(this.scale.x-0.01, this.scale.y-0.01);
            if (this.scale.x < 0.05) {
                this.destroy();
            }
        }*/
    }

    onBeginContact() {
    }
}

Remove sprites falling because collisions are too slow


import DS from 'ember-data';
import OsfModel from 'ember-osf/models/osf-model';

export default OsfModel.extend({
    name: DS.attr('string'),
    logoPath: DS.attr('string'),
    bannerPath: DS.attr('string'),
    description: DS.attr('string'),
    advisoryBoard: DS.attr('string'),
    emailContact: DS.attr('string'),
    emailSupport: DS.attr('string'),
    socialTwitter: DS.attr('string'),
    socialFacebook: DS.attr('string'),
    socialInstagram: DS.attr('string'),
    headerText: DS.attr('string'),
    subjectsAcceptable: DS.attr(),
    // Relationships
    taxonomies: DS.hasMany('taxonomy'),
    preprints: DS.hasMany('preprint', { inverse: 'provider', async: true }),
});

import DS from 'ember-data';
import OsfModel from 'ember-osf/models/osf-model';

export default OsfModel.extend({
    name: DS.attr('string'),
    logoPath: DS.attr('string'),
    bannerPath: DS.attr('string'),
    description: DS.attr('string'),
    example: DS.attr('string'),
    advisoryBoard: DS.attr('string'),
    emailContact: DS.attr('string'),
    emailSupport: DS.attr('string'),
    socialTwitter: DS.attr('string'),
    socialFacebook: DS.attr('string'),
    socialInstagram: DS.attr('string'),
    headerText: DS.attr('string'),
    subjectsAcceptable: DS.attr(),
    // Relationships
    taxonomies: DS.hasMany('taxonomy'),
    preprints: DS.hasMany('preprint', { inverse: 'provider', async: true }),
});

Add example to preprint provider (example guid)


const Server                    = require('dominion');
const Config                    = use('config');

Server.addComponent(require('./components/sessions'));
Server.addComponent(require('./components/permissions'));
Server.addComponent(require('./components/accounts'));
Server.addComponent(require('./components/tracking'));
Server.addComponent(require('./components/logging'));
Server.addComponent(require('./components/authorize'));
Server.addComponent(require('./components/notifications'));
Server.addComponent(require('./components/media'));

Server.addComponent(require('./components/favorites'));

Server.start(Config);

/* *** OpenAPI documentation ***
const fs = require("fs");
const openAPIJSON = Server.openApiJSON({
    "title": "Awesome APIs",
    "description": "Awesome APIs",
    "version": "1.0.0",
    "contact": {
        "email": "yura.chaikovsky@gmail.com"
    }
});
fs.writeFileSync("<filePath>", JSON.stringify(openAPIJSON, null, 4));
*/

const Server                    = require('dominion');
const Config                    = use('config');

Server.addComponent(require('./components/sessions'));
Server.addComponent(require('./components/permissions'));
Server.addComponent(require('./components/accounts'));
Server.addComponent(require('./components/tracking'));
Server.addComponent(require('./components/logging'));
Server.addComponent(require('./components/authorize'));
Server.addComponent(require('./components/notifications'));
Server.addComponent(require('./components/media'));

Server.addComponent(require('./components/favorites'));

Server.start(Config);

/* *** OpenAPI documentation ***
if (Config.env.development) {
    const fs = require("fs");
    const openAPIJSON = Server.openApiJSON({
        "title": "Awesome APIs",
        "description": "Awesome APIs",
        "version": "1.0.0",
        "contact": {
            "email": "yura.chaikovsky@gmail.com"
        }
    });
    fs.writeFileSync("<filePath>", JSON.stringify(openAPIJSON, null, 4));
}
*/

Add open api generation template


import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Col } from 'react-bootstrap';

export default class PTCustomCheckbox extends PureComponent {
	static propTypes = {
		title: PropTypes.string.isRequired,
		name: PropTypes.string.isRequired,
		isChecked: PropTypes.bool.isRequired,
		onChange: PropTypes.func,
		disabled: PropTypes.bool,
	};

	toggleCheckbox = () => {
	  const { disabled = false, onChange } = this.props;
		return !disabled && onChange(name);
  };

	render() {
		const { title, name, isChecked, disabled = false } = this.props;

		return (
      <Col xs={6} sm={4}>

              <input type="checkbox" id={`dashboard-${name}`} name={`dashboard-${name}`} checked={isChecked} onChange={this.toggleCheckbox} />
              <label htmlFor={`dashboard-${name}`} />

            <label htmlFor={`dashboard-${name}`} className="fcustominp-label">{title}

      </Col>
    )
  }
};

import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { Col } from 'react-bootstrap';

export default class PTCustomCheckbox extends PureComponent {
	static propTypes = {
		title: PropTypes.string.isRequired,
		name: PropTypes.string.isRequired,
		isChecked: PropTypes.bool.isRequired,
		onChange: PropTypes.func,
		disabled: PropTypes.bool,
	};

	toggleCheckbox = () => {
	  const { disabled = false, name, onChange } = this.props;
		return !disabled && onChange(name);
  };

	render() {
		const { title, name, isChecked, disabled = false } = this.props;

		return (
      <Col xs={6} sm={4}>

              <input type="checkbox" id={`dashboard-${name}`} name={`dashboard-${name}`} checked={isChecked} onChange={this.toggleCheckbox} />
              <label htmlFor={`dashboard-${name}`} />

            <label htmlFor={`dashboard-${name}`} className="fcustominp-label">{title}

      </Col>
    )
  }
};

Fix Settings of Patients Summary.


'use strict';

var axios = require('axios');
var db = require('./db');
var limit = 100;

function save(tokens) {
  var operations = tokens.map(function(token) {
    return {replaceOne: {filter: {_id: token._id}, replacement: token, upsert: true}};
  });

  var collection = db().collection('ethereum_tokens');
  return collection.bulkWrite(operations)
    .then(function() {
      return true;
    });
}

function getFromAPI() {
  return axios({
    url: 'https://api.ethplorer.io/getTop',
    params: {
      apiKey: 'freekey',
      criteria: 'cap',
      limit: limit
    }
  }).then(function(response) {
    if (!response.data) throw new Error('Bad ethereumTokens response');
    response.data.tokens.shift();
    var rank = 0;
    return response.data.tokens.map(function(item) {
      return {
        _id: rank++,
        address: item.address,
        name: item.name,
        decimals: parseInt(item.decimals),
        symbol: item.symbol,
        price: item.price ? parseFloat(item.price.rate) : 0.0,
      }
    });
  });
}

function getAllFromCache() {
  var collection = db().collection('ethereum_tokens');
  return collection
    .find({}, {projection: {_id: 0}})
    .sort({symbol: 1})
    .limit(limit)
    .toArray();
}

module.exports = {
  save: save,
  getFromAPI: getFromAPI,
  getAllFromCache: getAllFromCache
};

'use strict';

var axios = require('axios');
var db = require('./db');
var limit = 50;

function save(tokens) {
  var operations = tokens.map(function(token) {
    return {replaceOne: {filter: {_id: token._id}, replacement: token, upsert: true}};
  });

  var collection = db().collection('ethereum_tokens');
  return collection.bulkWrite(operations)
    .then(function() {
      return true;
    });
}

function getFromAPI() {
  return axios({
    url: 'https://api.ethplorer.io/getTop',
    params: {
      apiKey: 'freekey',
      criteria: 'cap',
      limit: limit
    }
  }).then(function(response) {
    if (!response.data) throw new Error('Bad ethereumTokens response');
    response.data.tokens.shift();
    var rank = 0;
    return response.data.tokens.map(function(item) {
      return {
        _id: rank++,
        address: item.address,
        name: item.name,
        decimals: parseInt(item.decimals),
        symbol: item.symbol,
        price: item.price ? parseFloat(item.price.rate) : 0.0,
      }
    });
  });
}

function getAllFromCache() {
  var collection = db().collection('ethereum_tokens');
  return collection
    .find({}, {projection: {_id: 0}})
    .sort({symbol: 1})
    .limit(limit)
    .toArray();
}

module.exports = {
  save: save,
  getFromAPI: getFromAPI,
  getAllFromCache: getAllFromCache
};

Update ethereum tokens limit to 50


import Ember from 'ember';
import layout from '../templates/components/bootstrap-multi-select';
import InputableMixin from '../mixins/components/inputable';

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

  selected: null,
  placeholder: null,
  options: null,
  onChange: null,
  label: null,

  disabled: false,
  loadingMessage: null,
  renderInPlace: false,
  allowClear: false,
  searchEnabled: false,
  searchField: null,
  required: false,
});

import Ember from 'ember';
import layout from '../templates/components/bootstrap-multi-select';
import InputableMixin from '../mixins/components/inputable';

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

  selected: null,
  placeholder: null,
  options: null,
  onChange: null,
  label: null,

  disabled: false,
  loadingMessage: null,
  renderInPlace: false,
  allowClear: true,
  searchEnabled: false,
  searchField: null,
  required: false,
});

Update default clear to true on multi-select


import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';

moduleForComponent('supplementary-file-browser', 'Integration | Component | supplementary file browser', {
    integration: true
});

test('it renders', function(assert) {
    // Set any properties with this.set('myProperty', 'value');
    // Handle any actions with this.on('myAction', function(val) { ... });

    // Construct a fake preprint object to satisfy browser needs
    let providerFiles = () => Ember.RSVP.resolve(Ember.ArrayProxy.create({
        content: Ember.A(),
        meta: {
            pagination: {
                total: 1
            }
        }}));
    let providersQuery =  Ember.RSVP.resolve(Ember.A([{
            name: 'osfstorage',
            query: providerFiles
    }]));
    let preprint = Ember.Object.create({
        files: providersQuery
    });

    this.set('preprint', preprint);

    this.render(hbs`{{supplementary-file-browser preprint=preprint}}`);

    assert.equal(this.$().text().trim(), '');

    //  this.on('changeFile', function() {});
});

//   {{supplementary-file-browser preprint=model projectURL=model.links.html chooseFile=(action 'chooseFile')}}

import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';

moduleForComponent('supplementary-file-browser', 'Integration | Component | supplementary file browser', {
    integration: true
});

test('it renders', function(assert) {
    // Set any properties with this.set('myProperty', 'value');
    // Handle any actions with this.on('myAction', function(val) { ... });

    // Construct a fake preprint object to satisfy browser needs
    let providerFiles = () => Ember.RSVP.resolve(Ember.ArrayProxy.create({
        content: Ember.A(),
        meta: {
            pagination: {
                total: 1
            }
        }}));
    let providersQuery =  Ember.RSVP.resolve(Ember.A([{
            name: 'osfstorage',
            query: providerFiles
    }]));

    let node = Ember.Object.create({
        dateModified: '10-11-2016',
        title:'My Preprint Title'
    });

    let file = Ember.Object.create({

    });
    let preprint = Ember.Object.create({
        primaryFile: file,
        node: node,
        provider: 'osf',
        files: providersQuery
    });

    this.set('preprint', preprint);

    this.render(hbs`{{supplementary-file-browser preprint=preprint}}`);

    assert.equal(this.$().text().trim(), '');

    //  this.on('changeFile', function() {});
});

//   {{supplementary-file-browser preprint=model projectURL=model.links.html chooseFile=(action 'chooseFile')}}

Add node to preprint object.


(function() {
  introJs()
  .start()
  .onchange(function(targetElement)  {
    switch(this._currentStep) {
      case 1:
        break;
      case 2:
        break;
      default:
        break;
    }
  })
  .onexit(function() {
    window.location = "../../newtab/newtab.html";
  })
  .oncomplete(function() {
    window.location = "../../newtab/newtab.html";
  });
})();

(function() {
  introJs()
  .start()
  .onchange(function(targetElement)  {
    switch(this._currentStep) {
      case 3:
        //show edit controls
        utils.editControls.wrap.style.opacity = 1.0;
        //and put text in thing if empty
        if(!utils.thing.value) utils.thing.value = "Go to the Gym";
        break;
      case 2:
        break;
      default:
        break;
    }
  })
  .onexit(function() {
    window.location = "../../newtab/newtab.html";
  })
  .oncomplete(function() {
    window.location = "../../newtab/newtab.html";
  });
})();

Add functionality to step number three


var http = require('http');
var util = require('./util');
var counter=0;

http.createServer(function (req, res) {
    var answer =  util.helloWorld();

    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(answer+' '+counter);
    counter = counter + 1;
    console.log(counter);

}).listen(1337, '127.0.0.1' );
//counter = 0;
console.log('Server running at http://127.0.0.1:1337/');

var http = require('http');
var util = require('./util');
var counter = 0;
var port = 1337;

http.createServer(function (req, res) {
    var answer = util.helloWorld();

    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end(answer + ' ' + counter);
    counter = counter + 1;
    console.log(counter);

}).listen(port, '127.0.0.1');
console.log('Server running at http://127.0.0.1:' + port + '/');

REFACTOR Extract port into its own variable


/* global chrome, confirm, localStorage */

var utils = require('./utils');

function StorageHandler (updateFiles) {
  this.sync = function () {
    if (typeof chrome === 'undefined' || !chrome || !chrome.storage || !chrome.storage.sync) {
      return;
    }

    var obj = {};
    var done = false;
    var count = 0;

    function check (key) {
      chrome.storage.sync.get(key, function (resp) {
        console.log('comparing to cloud', key, resp);
        if (typeof resp[key] !== 'undefined' && obj[key] !== resp[key] && confirm('Overwrite "' + utils.fileNameFromKey(key) + '"? Click Ok to overwrite local file with file from cloud. Cancel will push your local file to the cloud.')) {
          console.log('Overwriting', key);
          localStorage.setItem(key, resp[key]);
          updateFiles();
        } else {
          console.log('add to obj', obj, key);
          obj[key] = localStorage[key];
        }
        done++;
        if (done >= count) {
          chrome.storage.sync.set(obj, function () {
            console.log('updated cloud files with: ', obj, this, arguments);
          });
        }
      });
    }

    for (var y in window.localStorage) {
      console.log('checking', y);
      obj[y] = window.localStorage.getItem(y);
      if (y.indexOf(utils.getCacheFilePrefix()) !== 0) {
        continue;
      }
      count++;
      check(y);
    }
  };
}

module.exports = StorageHandler;

/* global chrome, confirm */

var utils = require('./utils');

function StorageHandler (updateFiles) {
  this.sync = function () {
    if (typeof chrome === 'undefined' || !chrome || !chrome.storage || !chrome.storage.sync) {
      return;
    }

    var obj = {};
    var done = false;
    var count = 0;

    function check (key) {
      chrome.storage.sync.get(key, function (resp) {
        console.log('comparing to cloud', key, resp);
        if (typeof resp[key] !== 'undefined' && obj[key] !== resp[key] && confirm('Overwrite "' + utils.fileNameFromKey(key) + '"? Click Ok to overwrite local file with file from cloud. Cancel will push your local file to the cloud.')) {
          console.log('Overwriting', key);
          window.localStorage.setItem(key, resp[key]);
          updateFiles();
        } else {
          console.log('add to obj', obj, key);
          obj[key] = window.localStorage[key];
        }
        done++;
        if (done >= count) {
          chrome.storage.sync.set(obj, function () {
            console.log('updated cloud files with: ', obj, this, arguments);
          });
        }
      });
    }

    for (var y in window.localStorage) {
      console.log('checking', y);
      obj[y] = window.localStorage.getItem(y);
      if (y.indexOf(utils.getCacheFilePrefix()) !== 0) {
        continue;
      }
      count++;
      check(y);
    }
  };
}

module.exports = StorageHandler;

Use window.localStorage in all cases


const dimGrey = '#5C6F68';
const gunMetal = '#2A2E35';
const gunMetal2 = '#2D3047';
const purpleTaupe = '#484349';
const darkElectricBlue = '#5D737E';
const stormCloud = '#4F616B';
const outerSpace = '#404F56';
const richBlack = '#022F40';
const onyx = '#36393B';

const black = onyx;
const red = '#FF7C7A';
const green = '#8FD5A6';
const yellow = '#FFE57F';
const blue = '#378AAD';
const magenta = '#8C82AF';
const cyan = '#8CCEC6';
const white = '#F4F1DE';
const lightBlack = '#817F823';
const lightWhite = '#FFFFFA';

module.exports = {
  plugins: [
  ],
  config: {
    padding: '17px',
    fontSize: 17,
    fontFamily: '"Fira Mono", monospace',
    cursorShape: 'BLOCK',
    cursorColor: white,
    foregroundColor: lightWhite,
    backgroundColor: black,
    borderColor: lightBlack,
    colors: {
      black,
      red,
      green,
      yellow,
      blue,
      magenta,
      cyan,
      white,
      lightBlack,
      lightRed: red,
      lightGreen: green,
      lightYellow: yellow,
      lightBlue: blue,
      lightMagenta: magenta,
      lightCyan: cyan,
      lightWhite,
    },
  },
};

const black = '#36393B';
const red = '#FF7C7A';
const green = '#8FD5A6';
const yellow = '#FFE57F';
const blue = '#378AAD';
const magenta = '#8C82AF';
const cyan = '#8CCEC6';
const white = '#F4F1DE';
const lightBlack = '#817F823';
const lightWhite = '#FFFFFA';

module.exports = {
  plugins: [
  ],
  config: {
    padding: '17px',
    fontSize: 17,
    fontFamily: '"Fira Mono", monospace',
    cursorShape: 'BLOCK',
    cursorColor: white,
    foregroundColor: lightWhite,
    backgroundColor: black,
    borderColor: lightBlack,
    colors: {
      black,
      red,
      green,
      yellow,
      blue,
      magenta,
      cyan,
      white,
      lightBlack,
      lightRed: red,
      lightGreen: green,
      lightYellow: yellow,
      lightBlue: blue,
      lightMagenta: magenta,
      lightCyan: cyan,
      lightWhite,
    },
  },
};

Update color draft with favorite 'black' version


import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router';
import { actions as patientActions } from '../redux/modules/patient';
// import styles from './HomeView.scss';
// import MultiGraph from '../components/MultiGraph';
// import CreatePatient from '../components/CreatePatient';

// We define mapStateToProps where we'd normally use
// the @connect decorator so the data requirements are clear upfront, but then
// export the decorated component after the main class definition so
// the component can be tested w/ and w/o being connected.
// See: http://rackt.github.io/redux/docs/recipes/WritingTests.html
const mapStateToProps = (state) => ({
  graphs: state.graphs,
  patients: state.patients.searchResults
});

export class HomeView extends React.Component {
  render () {
    var patientList = () => {
      return this.props.patients.map((p) => {
        return (

            <Link to={'/patient/' + p.id}>{p.name}</Link>

        );
      });
    };

    return (

Patients

        {patientList()}
        {
          // <MultiGraph graphs={this.props.graphs} />
        }

    );
  }
}

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

HomeView.propTypes = {
  createPatient: React.PropTypes.func,
  graphs: React.PropTypes.array,
  patients: React.PropTypes.array
};

Add key to list of patients.


 var config = require('yaml-config').readConfig(__dirname + '/../config/config.yml')
  , mail = require('../config/mail')(config)
  , emailTemplates = require('email-templates')
  , nodemailer = require('nodemailer');

// send mail with templates
exports.sendMail = function (name, to, subject, data, callback) {
  var template = 'welcome.jade';
  templateOptions = {
    user: {
      email: 'keith@webizly.com'
    }
  }
  jade.renderFile(path.join(__dirname, '../email_templates/account_activation', template), templateOptions , function(err, text) {
    if (err) {
      console.log(err);
    } else {
        var mailOptions = {
          from: "mywebclass@webizly.com", // sender address
          to: "keith@webizly.com", // list of receivers
          subject: "Hello", // Subject line
          text: "Hello world", // plaintext body
          html: text
        }
        if (typeof to !== 'undefined') {
           mailOptions.to = to;
         }
         if (typeof subject !== 'undefined') {
           mailOptions.subject = subject;
         }
        mail.sendMail(mailOptions, function(error, response) {
          if (error) {
            console.log(error);
          } else {
            console.log("Message sent: " + response.message);
          }
        });
        mail.close();
        if (callback !== undefined) {
          callback(error, response);
        }
      }
  });
}

var config = require('yaml-config')
  .readConfig(__dirname + '/../config/config.yml')
  , mail = require('../config/mail')(config)
  , emailTemplates = require('email-templates')
  , nodemailer = require('nodemailer');

// send mail with templates
exports.sendMail = function (name, to, subject, data, callback) {
  var template = 'welcome.jade';
  templateOptions = {
    user: {
      email: 'keith@webizly.com'
    }
  };

  jade.renderFile(path.join(__dirname, '../email_templates/account_activation',
    template), templateOptions, function (err, text) {
    if (err) {
      console.log(err);
    } else {
      var mailOptions = {
        from: "mywebclass@webizly.com", // sender address
        to: "keith@webizly.com", // list of receivers
        subject: "Hello", // Subject line
        text: "Hello world", // plaintext body
        html: text
      };

      if (typeof to !== 'undefined') {
        mailOptions.to = to;
      }

      if (typeof subject !== 'undefined') {
        mailOptions.subject = subject;
      }

      mail.sendMail(mailOptions, function (error, response) {
        if (error) {
          console.log(error);
        } else {
          console.log("Message sent: " + response.message);
        }
      });

      mail.close();

      if (callback !== undefined) {
        callback(error, response);
      }
    }
  });
};

Add missing semicolons and wrapped the line to 80 columns


var vm = require('vm')
var Headers = require('@http/headers')
var requestOptions = require('../config/options')

exports.filter = function (options) {
  var result = {}

  for (var key in options) {
    if (requestOptions.indexOf(key) === -1) {
      result[key] = options[key]
    }
  }
  result.headers = result.headers.toObject()

  return result
}

exports.response = function (res) {
  res.headers = new Headers(res.headers)
}

exports.rfc3986 = function (str) {
  return str.replace(/[!'()*]/g, function (c) {
    return '%' + c.charCodeAt(0).toString(16).toUpperCase()
  })
}

exports.isJSON = function (res) {
  var type = res.headers.get('content-type')
    , encoding = res.headers.get('content-encoding')

  return (/json|javascript/.test(type) || /json/.test(encoding))
}

exports.isJSONP = function (body) {
  return /^\w+[^(]*\(.+\)/.test(body)
}

exports.parseJSONP = function (body) {
  var func = body.replace(/(^\w+[^(]*)/, '$1')

  var obj = {}
  obj[func] = function (json) {return json}

  var sandbox = vm.createContext(obj)
  var json = vm.runInContext(body, sandbox)

  // either object or string
  return json
}

var vm = require('vm')
var Headers = require('@http/headers')
var requestOptions = require('../config/options')

exports.filter = function (options) {
  var result = {}

  for (var key in options) {
    if (requestOptions.indexOf(key) === -1) {
      result[key] = options[key]
    }
  }
  result.headers = result.headers.toObject()

  return result
}

exports.response = function (res) {
  res.headers = new Headers(res.headers)
}

exports.rfc3986 = function (str) {
  return str.replace(/[!'()*]/g, function (c) {
    return '%' + c.charCodeAt(0).toString(16).toUpperCase()
  })
}

exports.isJSON = function (res) {
  var type = res.headers.get('content-type')
    , encoding = res.headers.get('content-encoding')

  return (/json|javascript/.test(type) || /json/.test(encoding))
}

exports.isJSONP = function (body) {
  return /^\w+[^(]*\(.+\)/.test(body)
}

exports.parseJSONP = function (body) {
  var func = body.replace(/(^\w+[^(]*).*/, '$1')

  var obj = {}
  obj[func] = function (json) {return json}

  var sandbox = vm.createContext(obj)
  var json = vm.runInContext(body, sandbox)

  // either object or string
  return json
}

Fix JSONP function name extraction


const shell = require('shelljs');
const path = require('path');

console.log('Patch react-devtools-core');

// backend vender is backward compatibility for RN <= 0.42
// the problem related to https://github.com/facebook/react-devtools/pull/749
// fixed in core v2.3 but have no patch in the backend vender
const rdBackend = path.join(
  __dirname,
  '../dist/node_modules/react-devtools-core/vendor/backend-1.0.6.js'
);
shell.sed(
  '-i',
  'window.requestIdleCallback',
  'window.__REQUEST_IDLE_CALLBACK_REPLACED_BY_PATCH__',
  rdBackend
);
shell.sed(
  '-i',
  'window.cancelIdleCallback',
  'window.__CANCEL_IDLE_CALLBACK_REPLACED_BY_PATCH__',
  rdBackend
);

const rdStandalone = path.join(
  __dirname,
  '../dist/node_modules/react-devtools-core/build/standalone.js'
);
// Hide source map of react-devtools-core
// for optimize chrome devtools
shell.sed(
  '-i',
  '//# sourceMappingURL=standalone.js.map',
  '',
  rdStandalone
);
// Avoid logging from react-devtools-core
// log: connected, disconnected
// error: listening error (can be seen directly in the panel)
shell.sed(
  '-i',
  // eslint-disable-next-line
  /\(_console[0-9]* = console\).(log|warn|error).apply\(_console[0-9]*, \[ "\[React DevTools\]" \].concat\(args\)\)/,
  '',
  rdStandalone
);

console.log('Patch react-dev-utils/launchEditor');

shell.sed(
  '-i',
  /require\('chalk'\)/g,
  '{red:f=>f,cyan:f=>f,green:f=>f}',
  path.join(__dirname, '../node_modules/react-dev-utils/launchEditor.js')
);

const shell = require('shelljs');
const path = require('path');

console.log('Patch react-devtools-core');

const rdStandalone = path.join(
  __dirname,
  '../dist/node_modules/react-devtools-core/build/standalone.js'
);
// Hide source map of react-devtools-core
// for optimize chrome devtools
shell.sed('-i', '//# sourceMappingURL=standalone.js.map', '', rdStandalone);
// Avoid logging from react-devtools-core
// log: connected, disconnected
// error: listening error (can be seen directly in the panel)
shell.sed(
  '-i',
  // eslint-disable-next-line
  /\(_console[0-9]* = console\).(log|warn|error).apply\(_console[0-9]*, \[ "\[React DevTools\]" \].concat\(args\)\)/,
  '',
  rdStandalone
);

console.log('Patch react-dev-utils/launchEditor');

shell.sed(
  '-i',
  /require\('chalk'\)/g,
  '{red:f=>f,cyan:f=>f,green:f=>f}',
  path.join(__dirname, '../node_modules/react-dev-utils/launchEditor.js')
);

Remove backend patch of react-devtools-core


'use strict';

if ($('body').hasClass('ng-tns-0-0')) {
	setupNewPlayer();
} else {
	setupMainPlayer();
}

function setupNewPlayer() {
	Connector.playerSelector = '.content-wrapper';

	Connector.albumSelector = '.now_playing_list.ng-star-inserted:not(.dim) .title .album';

	Connector.getArtistTrack = () => {
		let text = document.title;
		return Util.splitArtistTrack(text);
	};

	Connector.isPlaying = () => $('#play-button').hasClass('active');

	Connector.trackArtSelector = '.now_playing_list.ng-star-inserted:not(.dim) img';
}

function setupMainPlayer() {
	Connector.playerSelector = '#header';

	Connector.artistTrackSelector = '#nowplaying_title > b';

	Connector.trackArtSelector = '#nowplaying_title > img';

	Connector.isPlaying = () => $('#play_button').hasClass('button_active');
}

'use strict';

Connector.playerSelector = '.content-wrapper';

Connector.albumSelector = '.now_playing_list.ng-star-inserted:not(.dim) .title .album';

Connector.getArtistTrack = () => {
	const text = document.title;
	return Util.splitArtistTrack(text);
};

Connector.isPlaying = () => $('#play-button').hasClass('active');

Connector.trackArtSelector = '.now_playing_list.ng-star-inserted:not(.dim) img';

Remove old Radio Paradise player support


'use strict';

angular.module('roles').run(['Menus', 'MenuControl', function (Menus, MenuControl, ENV) {
		Menus.addMenuItem('systemMenu', {
			title: 'System Roles',
			state: 'admin.roles.list',
			roles: MenuControl.menuRolesBuilder(['admin', 'eao'])
		});
	}
]);

'use strict';

angular.module('roles').run(['Menus', 'MenuControl', function (Menus, MenuControl) {
		Menus.addMenuItem('systemMenu', {
			title: 'System Roles',
			state: 'admin.roles.list',
			roles: MenuControl.menuRolesBuilder(['admin'])
		});
	}
]);

Adjust for admin role only


var StartView = function(homeView) {

    this.homeView = homeView;

    this.initialize = function() {
        // 'div' wrapper to attach html and events to
        this.el = $('<div/>');
    };

    this.render = function() {
	if (!this.homeView) {
	    this.homeView = { enteredName:  "" }
	}
        this.el.html(StartView.template(this.homeView));

        return this;
    };

    this.getPhoneGapPath = function() {

	var path = window.location.pathname;
	path = path.substr( path, path.length - 10 );
	return 'file://' + path;
    };

    this.playAudio = function() {

	var url = this.getPhoneGapPath() + 'audio/eab-innovation.wav';

	var snd = new Media(url, function () { console.log("playAudio():Audio Success"); },
			         function (err) { console.log("playAudio():Audio Error: " + err); }
			   );

	// Play audio
	snd.play();

    };

    this.crossfade = function(delay) {
	$("#svg-bubbles-div").delay(delay).animate({ opacity: 0 }, 700);
	$("#after-bubbles").delay(delay).css("display","block").animate({ opacity: 1 }, 700);

	this.playAudio();
    };

    this.initialize();
}

StartView.template = Handlebars.compile($("#start-tpl").html());

var StartView = function(homeView) {

    this.homeView = homeView;

    this.initialize = function() {
        // 'div' wrapper to attach html and events to
        this.el = $('<div/>');
    };

    this.render = function() {
	if (!this.homeView) {
	    this.homeView = { enteredName:  "" }
	}
        this.el.html(StartView.template(this.homeView));

        return this;
    };

    this.getPhoneGapPath = function() {

	var path = window.location.pathname;
	path = path.substr( path, path.length - 10 );
	return 'file://' + path;
    };

    this.playAudio = function() {

	var url = this.getPhoneGapPath() + 'audio/eab-innovation.mp3';

	var snd = new Media(url, function () { console.log("playAudio():Audio Success"); },
			         function (err) { console.log("playAudio():Audio Error: " + err); }
			   );

	// Play audio
	snd.play();

    };

    this.crossfade = function(delay) {
	$("#svg-bubbles-div").delay(delay).animate({ opacity: 0 }, 700);
	$("#after-bubbles").delay(delay).css("display","block").animate({ opacity: 1 }, 700);

	this.playAudio();
    };

    this.initialize();
}

StartView.template = Handlebars.compile($("#start-tpl").html());

Switch to media playing an MP3 file to see if it helps iPad version


exports.config = {
  allScriptsTimeout: 11000,

  specs: [
    '*.js'
  ],

  capabilities: {
    'browserName': 'chrome'
  },

  baseUrl: 'https://localhost:8000/',

  framework: 'jasmine',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 30000
  }
};

exports.config = {
  allScriptsTimeout: 11000,

  specs: [
    '*.js'
  ],

  capabilities: {
    'browserName': 'firefox'
  },

  baseUrl: 'https://localhost:8000/',

  framework: 'jasmine',

  jasmineNodeOpts: {
    defaultTimeoutInterval: 30000
  }
};

Use Firefox so Protractor will work inside Vagrant.


var satAttr = 'Modified Copernicus' +
    ' Sentinel data 2016 by ' +
    'SentinelMap' ;

var osmAttr = ' | © OSM' +
    ' contributors data by ' +
    'Mapzen' ;

var Attr = satAttr + osmAttr ;

var scLayer = Tangram.leafletLayer({
    scene: 'scene@1.1.yaml',
    attribution: Attr,
});

var map = L.map('map' , {
    center: [ 48.92, 11.25],
    //center: [ 47.04, 8.44],
    zoom: 6,
    maxZoom: 16,
    minZoom: 5,
    layers: [scLayer],
    zoomControl: false
});

var baseLayers = {
    "Sentinel-2": scLayer,
};

L.control.zoom({position: 'topright'}).addTo(map);

var hash = new L.Hash(map);

var sidebar = L.control.sidebar('sidebar').addTo(map);

// DEBUG
/*
scLayer.scene.subscribe({
    load: function (e) {
        console.log('scene loaded:', e);
    }
});

scLayer.scene.subscribe({
    view_complete: function () {
	console.log('scene view complete');
    }
});
*/

var satAttr = 'Modified Copernicus' +
    ' Sentinel data 2016 by ' +
    'SentinelMap' ;

var osmAttr = ' | © OSM' +
    ' contributors data by ' +
    'Mapzen' ;

var Attr = satAttr + osmAttr ;

var scLayer = Tangram.leafletLayer({
    scene: 'scene@1.1.yaml',
    attribution: Attr,
});

var map = L.map('map' , {
    center: [ 48.92, 11.25],
    //center: [ 47.04, 8.44],
    zoom: 6,
    maxZoom: 16,
    minZoom: 5,
    layers: [scLayer],
    zoomControl: false
});

var baseLayers = {
    "Sentinel-2": scLayer,
};

L.control.zoom({position: 'bottomright'}).addTo(map);

var hash = new L.Hash(map);

var sidebar = L.control.sidebar('sidebar').addTo(map);

// DEBUG
/*
scLayer.scene.subscribe({
    load: function (e) {
        console.log('scene loaded:', e);
    }
});

scLayer.scene.subscribe({
    view_complete: function () {
	console.log('scene view complete');
    }
});
*/

Move zoom control on bottom right


var assert = require("assert");
var path = require("path");
var transform = require("./lib/visit").transform;
var guessTabWidth = require("./lib/util").guessTabWidth;
var recast = require("recast");
var esprimaHarmony = require("esprima");

assert.ok(
  /harmony/.test(esprimaHarmony.version),
  "Bad esprima version: " + esprimaHarmony.version
);

function regenerate(source) {
  var options = {
    tabWidth: guessTabWidth(source),
    // Use the harmony branch of Esprima that installs with regenerator
    // instead of the master branch that recast provides.
    esprima: esprimaHarmony
  };
  var ast = recast.parse(source, options);
  return recast.print(transform(ast), options);
}

// To modify an AST directly, call require("regenerator").transform(ast).
regenerate.transform = transform;

regenerate.runtime = {
  dev: path.join(__dirname, "runtime", "dev.js"),
  min: path.join(__dirname, "runtime", "min.js")
};

// To transform a string of ES6 code, call require("regenerator")(source);
module.exports = regenerate;

var assert = require("assert");
var path = require("path");
var transform = require("./lib/visit").transform;
var guessTabWidth = require("./lib/util").guessTabWidth;
var recast = require("recast");
var esprimaHarmony = require("esprima");
var genFunExp = /\bfunction\s*\*/;

assert.ok(
  /harmony/.test(esprimaHarmony.version),
  "Bad esprima version: " + esprimaHarmony.version
);

function regenerate(source) {
  if (!genFunExp.test(source)) {
    return source; // Shortcut: no generators to transform.
  }

  var options = {
    tabWidth: guessTabWidth(source),
    // Use the harmony branch of Esprima that installs with regenerator
    // instead of the master branch that recast provides.
    esprima: esprimaHarmony
  };

  var ast = recast.parse(source, options);
  return recast.print(transform(ast), options);
}

// To modify an AST directly, call require("regenerator").transform(ast).
regenerate.transform = transform;

regenerate.runtime = {
  dev: path.join(__dirname, "runtime", "dev.js"),
  min: path.join(__dirname, "runtime", "min.js")
};

// To transform a string of ES6 code, call require("regenerator")(source);
module.exports = regenerate;

Return unmodified source immediately if no generator functions detected.


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

const entry = path.join(__dirname, './Sources/index.js');
const sourcePath = path.join(__dirname, './Sources');
const outputPath = path.join(__dirname, './dist');

const vtkRules = require('./Utilities/config/rules-vtk.js');
const linterRules = require('./Utilities/config/rules-linter.js');

module.exports = {
  entry,
  output: {
    path: outputPath,
    filename: 'vtk.js',
  },
  module: {
    rules: [
      { test: entry, loader: 'expose-loader?vtk' },
    ].concat(linterRules, vtkRules),
  },
  resolve: {
    modules: [
      path.resolve(__dirname, 'node_modules'),
      sourcePath,
    ],
    alias: {
      'vtk.js': __dirname,
    },
  },
};

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

const entry = path.join(__dirname, './Sources/index.js');
const sourcePath = path.join(__dirname, './Sources');
const outputPath = path.join(__dirname, './dist');

const vtkRules = require('./Utilities/config/rules-vtk.js');
const linterRules = require('./Utilities/config/rules-linter.js');

module.exports = {
  entry,
  output: {
    path: outputPath,
    filename: 'vtk.js',
    libraryTarget: 'umd',
  },
  module: {
    rules: [
      { test: entry, loader: 'expose-loader?vtk' },
    ].concat(linterRules, vtkRules),
  },
  resolve: {
    modules: [
      path.resolve(__dirname, 'node_modules'),
      sourcePath,
    ],
    alias: {
      'vtk.js': __dirname,
    },
  },
};

Use UMD as lib target


var screenshare = require('..');
var media = require('rtc-media');

screenshare.window(function(err, constraints) {
  media(constraints).render(document.body);
});

var screenshare = require('..');
var media = require('rtc-media');

screenshare.window(function(err, constraints) {
  if (err) {
    return console.error('Could not capture window: ', err);
  }

  console.log('attempting capture with constraints: ', constraints);
  media({ constraints: constraints })
    .on('error', function(err) {
      console.error('Could not capture: ', err);
    })
    .once('capture', function(stream) {
      console.log('Successfully captured stream: ', stream);
    })
    .render(document.body);
});

Add error handling and logging to the example


var path = require('path');
var webpack = require('webpack');
var package = require('./package.json');

minimize = process.argv.indexOf('--minimize') !== -1;

var conf = {
    entry: ['babel-polyfill', './src/index.js'],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: package.name + '.js'
    },
    module: {
    loaders: [
        {
            test: /\.js$/,
            loader: 'babel-loader',
            query: {
                presets: ['es2015']
            }
        },
    ]},
    resolve: {
        root: [path.resolve('./src'), path.resolve('./node_modules')],
        extensions: ['', '.js'],
    },
    stats: {
        colors: true
    },
    devtool: 'source-map',
    plugins: [
        new webpack.optimize.DedupePlugin()
    ]
}

if(minimize){
    conf.plugins.push(new webpack.optimize.UglifyJsPlugin());
    conf.output.filename = package.name + '.min.js'
    delete conf.devtool;
}

module.exports = conf;

var path = require('path');
var webpack = require('webpack');
var package = require('./package.json');

minimize = process.argv.indexOf('--minimize') !== -1;

var conf = {
    entry: ['babel-polyfill', './src/index.js'],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: package.name + '.js'
    },
    module: {
    loaders: [
        {
            test: /\.js$/,
            loader: 'babel-loader',
            query: {
                presets: ['es2015']
            }
        },
    ]},
    resolve: {
        root: [path.resolve('./src'), path.resolve('./node_modules')],
        extensions: ['', '.js'],
    },
    stats: {
        colors: true
    },
    devtool: 'source-map',
    plugins: [
        new webpack.optimize.DedupePlugin()
    ]
}

if(minimize){
    conf.plugins.push(new webpack.optimize.UglifyJsPlugin());
    conf.output.filename = package.name + '.min.js';
}

module.exports = conf;

Enable source-map for minimized build


'use strict';

var path = require('path');
var webpack = require('webpack');
var prod = process.env.NODE_ENV === 'production';

var config = {
    devtool: prod ? null : 'eval',

    entry: [
        path.join(__dirname, 'demo', 'src', 'demo.js')
    ],

    output: {
        path: path.join(__dirname, 'demo', 'dist', 'js'),
        filename: 'demo.js',
        publicPath: '/demo/dist'
    },

    externals: {
        'react': 'React',
        'react-dom': 'ReactDOM'
    },

    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel',
            exclude: /node_modules/,
            query: {
                cacheDirectory: true,
                presets: ['react']
            }
        }, {
            test: /\.json$/,
            loader: 'json'
        }]
    },

    plugins: [
        new webpack.NoErrorsPlugin()
    ]
};

if (prod) {
    config.plugins.push(new webpack.optimize.DedupePlugin());
    config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true));
    config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

module.exports = config;

'use strict';

var path = require('path');
var webpack = require('webpack');
var prod = process.env.NODE_ENV === 'production';

var config = {
    devtool: prod ? null : 'eval',

    entry: [
        path.join(__dirname, 'demo', 'src', 'demo.js')
    ],

    output: {
        path: path.join(__dirname, 'demo', 'dist', 'js'),
        filename: 'demo.js',
        publicPath: '/demo/dist'
    },

    externals: {
        'react': {
            root: 'React',
            commonjs: 'react',
            commonjs2: 'react',
            amd: 'react'
        },
        'react-dom': {
            root: 'ReactDOM',
            commonjs: 'react-dom',
            commonjs2: 'react-dom',
            amd: 'react-dom'
        }
    },

    module: {
        loaders: [{
            test: /\.js$/,
            loader: 'babel',
            exclude: /node_modules/,
            query: {
                cacheDirectory: true,
                presets: ['react']
            }
        }, {
            test: /\.json$/,
            loader: 'json'
        }]
    },

    plugins: [
        new webpack.NoErrorsPlugin()
    ]
};

if (prod) {
    config.plugins.push(new webpack.optimize.DedupePlugin());
    config.plugins.push(new webpack.optimize.OccurenceOrderPlugin(true));
    config.plugins.push(new webpack.optimize.UglifyJsPlugin());
}

module.exports = config;

Fix issue with react external name


import Vue from 'vue';
import FileManager from 'src/components/file-manager/FileManager';

describe('FileManager.vue', () => {
  const Constructor = Vue.extend(FileManager);
  const vm = new Constructor().$mount();

  it('should render userInputs navbar component', () => {
    expect(vm.$el.querySelector('.navbar'))
      .to.not.equal(null);
  });
  it('should render userInputs userActions component', () => {
    expect(vm.$el.querySelector('.userActions'))
      .to.not.equal(null);
  });
  it('should render create folder button', () => {
    expect(vm.$el.querySelector('.userActions #button-create-folder'))
      .to.not.equal(null);
  });
  it('should render download button', () => {
    expect(vm.$el.querySelector('.userActions #button-file-download'))
      .to.not.equal(null);
  });
  it('should render delete button', () => {
    expect(vm.$el.querySelector('.userActions #button-delete'))
      .to.not.equal(null);
  });
  it('should render icon view button', () => {
    expect(vm.$el.querySelector('.userActions #button-icon-view'))
      .to.not.equal(null);
  });
  it('should render list view button', () => {
    expect(vm.$el.querySelector('.userActions #button-list-view'))
      .to.not.equal(null);
  });
  it('should render Documents component', () => {
    expect(vm.$el.querySelector('.documents'))
      .to.not.equal(null);
  });
});

import Vue from 'vue';
import FileManager from 'src/components/file-manager/FileManager';

describe('FileManager.vue', () => {
  const Constructor = Vue.extend(FileManager);
  const vm = new Constructor().$mount();

  it('should render userInputs navbar component', () => {
    expect(vm.$el.querySelector('.navbar'))
      .to.not.equal(null);
  });
  it('should render userInputs userActions component', () => {
    expect(vm.$el.querySelector('.userActions'))
      .to.not.equal(null);
  });
  it('should render create folder button', () => {
    expect(vm.$el.querySelector('.userActions #button-create-folder'))
      .to.not.equal(null);
  });
  it('should render download button', () => {
    expect(vm.$el.querySelector('.userActions #button-file-download'))
      .to.not.equal(null);
  });
  it('should render delete button', () => {
    expect(vm.$el.querySelector('.userActions #button-delete'))
      .to.not.equal(null);
  });
  it('should render icon view button', () => {
    expect(vm.$el.querySelector('#button-icon-view'))
      .to.not.equal(null);
  });
  it('should render list view button', () => {
    expect(vm.$el.querySelector('#button-list-view'))
      .to.not.equal(null);
  });
  it('should render Documents component', () => {
    expect(vm.$el.querySelector('.documents'))
      .to.not.equal(null);
  });
});

Update test case for FileManager


var lastScrollTop;

$(function(){

    var direction = 'down';

    lastScrollTop = 0;

    $(window).on('scroll', scrollOnScroll);
});

function scrollOnScroll() {

    var windowTop = $(window).scrollTop();
    var activeScrollSection = $('.scroll-target.active');
    var scrollTarget = activeScrollSection.next('.scroll-target');

    if ( scrollTarget.length != 0 ) {
        var scrollTargetTop = scrollTarget.offset().top;
    }

    direction = getScrollDirection();

    if ( !activeScrollSection.hasClass('animating') ) {

        $(window).off('scroll', scrollOnScroll);

        if ( windowTop < scrollTargetTop && direction == 'down' ) {

            activeScrollSection.addClass('animating');

            $('html, body').stop().animate({ scrollTop: scrollTargetTop}, 1000, function() {

                scrollTarget.addClass('active');
                activeScrollSection.removeClass('active').removeClass('animating');

                // Clear/wait for residual scroll functions
                $(window).clearQueue();
                setTimeout(function(){
                    $(window).on('scroll', scrollOnScroll);
                }, 100);

            });
        }
    }
}

function getScrollDirection() {

    var currentScrollTop = $(this).scrollTop();
    var direction;

    if ( currentScrollTop > lastScrollTop ) {
        direction = 'down';
    } else {
       direction = 'up';
    }

    lastScrollTop = currentScrollTop;
    return direction;
}

var direction;

$(function(){

    $('body').css('overflow', 'hidden');
    $(document).on('mousewheel DOMMouseScroll MozMousePixelScroll', scrollFunctions);
});

$(window).load(function(){

    $(window).scrollTop(0);
});

function scrollFunctions() {

    getScrollDirection();
    scrollOnScroll();
}

function scrollOnScroll() {

    if ( direction != undefined ) {

        var activeScrollSection = $('.scroll-target.active');

        if ( !activeScrollSection.hasClass('animating') ) {

            if ( direction == 'down' ) {
                var scrollTarget = activeScrollSection.next('.scroll-target');
            } else {
                var scrollTarget = activeScrollSection.prev('.scroll-target');
            }

            if ( scrollTarget.length != 0 ) {
                var scrollTargetTop = scrollTarget.offset().top;
            }

            console.log("Not animating");
            console.log("Target: " + scrollTarget.text());

            activeScrollSection.addClass('animating');

            $('html, body').animate({ scrollTop: scrollTargetTop}, 1400, function() {

                scrollTarget.addClass('active');
                activeScrollSection.removeClass('active').removeClass('animating');

                $(document).off('mousewheel DOMMouseScroll MozMousePixelScroll', scrollFunctions);

                setTimeout(function(){
                    $(document).on('mousewheel DOMMouseScroll MozMousePixelScroll', scrollFunctions);
                }, 500);

            });
        }
    }
}

function getScrollDirection() {

    $('body').bind('mousewheel', function(e){
        if(e.originalEvent.wheelDelta / 120 > 0) {
            direction = 'up';
        }
        else{
            direction = 'down';
        }
    });
}

function preventScroll(event) {

    event.preventDefault();
}

Rewrite to use mousewheel functions for detecting scroll direction, turning scroll on/off