import $ from 'jquery'
import '@babel/polyfill'
import {init} from '@sentry/browser';
import 'bootstrap'

import './style/weinstein.less';

import {addGlobal} from './globals';
import {TastersView} from './views/tasterview';
import {retastebutton} from './retastebutton';
import {setUser} from './user';
import {WineCollection} from './models/wine';
import {WinesView} from './views/wineview';

// TODO: refactor away from these globals
addGlobal('$', $);
addGlobal('TastersView', TastersView);
addGlobal('retastebutton', retastebutton);
addGlobal('WineCollection', WineCollection);
addGlobal('WinesView', WinesView);
addGlobal('setUser', setUser);

console.debug('Weinstein dependencies and scripts loaded');

window.wsinit = ({csrfToken, dsn, release, environment}) => {
    $(function () {
        $.ajaxSetup({
            headers: {'X-CSRF-TOKEN': csrfToken}
        });
    });

    try {
        init({
            dsn,
            release,
            environment
        })
    } catch (e) {
        console.error('Could not initialize Sentry:', e)
    }

    console.info('Weinstein initialized');
}

import $ from 'jquery'
import '@babel/polyfill'
import {init} from '@sentry/browser';
import 'bootstrap'
import 'select2/dist/css/select2.css'
import 'select2/dist/js/select2'
import 'select2/dist/js/i18n/de'

import './style/weinstein.less';

import {addGlobal} from './globals';
import './entertab'
import {TastersView} from './views/tasterview';
import {retastebutton} from './retastebutton';
import {setUser} from './user';
import {WineCollection} from './models/wine';
import {WinesView} from './views/wineview';

// TODO: refactor away from these globals
addGlobal('$', $);
addGlobal('TastersView', TastersView);
addGlobal('retastebutton', retastebutton);
addGlobal('WineCollection', WineCollection);
addGlobal('WinesView', WinesView);
addGlobal('setUser', setUser);

console.debug('Weinstein dependencies and scripts loaded');

window.wsinit = ({csrfToken, dsn, release, environment}) => {
    $(function () {
        $.ajaxSetup({
            headers: {'X-CSRF-TOKEN': csrfToken}
        });
    });

    try {
        init({
            dsn,
            release,
            environment
        })
    } catch (e) {
        console.error('Could not initialize Sentry:', e)
    }

    console.info('Weinstein initialized');
}

Fix loading of select2 lib


var spyCallbacks = [];
var spySetState = [];

var currentPositionY = function() {
  var supportPageOffset = window.pageXOffset !== undefined;
  var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
  return supportPageOffset ? window.pageYOffset : isCSS1Compat ?
          document.documentElement.scrollTop : document.body.scrollTop;
};

if (typeof document !== 'undefined') {
  document.addEventListener('scroll', function() {
    for(var i = 0; i < spyCallbacks.length; i = i + 1) {
      spyCallbacks[i](currentPositionY());
    }
  });
}

module.exports = {
  unmount: function(){
    spySetState = [];
    spyCallbacks = [];
  },

  addStateHandler: function(handler){
    spySetState.push(handler);
  },

  addSpyHandler: function(handler){
    spyCallbacks.push(handler);
  },

  updateStates: function(){

    var length = spySetState.length;

    for(var i = 0; i < length; i = i + 1) {
      spySetState[i]();
    }

  }
};

var spyCallbacks = [];
var spySetState = [];

var currentPositionY = function() {
  var supportPageOffset = window.pageXOffset !== undefined;
  var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
  return supportPageOffset ? window.pageYOffset : isCSS1Compat ?
          document.documentElement.scrollTop : document.body.scrollTop;
};

var scrollHandler = function() {
  for(var i = 0; i < spyCallbacks.length; i = i + 1) {
    spyCallbacks[i](currentPositionY());
  }
};

if (typeof document !== 'undefined') {
  document.addEventListener('scroll', scrollHandler);
}

module.exports = {
  unmount: function(){
    document.removeEventListener('scroll', scrollHandler);
    spySetState = [];
    spyCallbacks = [];
  },

  addStateHandler: function(handler){
    spySetState.push(handler);
  },

  addSpyHandler: function(handler){
    spyCallbacks.push(handler);
  },

  updateStates: function(){

    var length = spySetState.length;

    for(var i = 0; i < length; i = i + 1) {
      spySetState[i]();
    }
  }
};

Clean up events bound on window, otherwise this will induce a memory leak.


#!/usr/bin/env node

const jsdotmd = require('../lib')
const program = require('commander')
const path = require('path')

program
  .usage('[options] <source> <destination>')
  .option(
    '-l, --langCodes <items>',
    'List of language codes that are compiled into the destination, separated by commas. Default: js,javascript,node',
    (string) => string.split(',')
  )
  .parse(process.argv)

if (program.args.length !== 2) {
  program.help(() => process.exit(1))
}

const {langCodes, args: [source, destination]} = program

const currentPath = process.cwd()
const sourcePath = path.join(currentPath, source)
const destinationPath = path.join(currentPath, destination)

jsdotmd.compile(sourcePath, destinationPath, {langCodes})
  .catch((err) => console.log('Something went wrong!', err))

#!/usr/bin/env node

const jsdotmd = require('../lib')
const program = require('commander')
const path = require('path')

program
  .usage('[options] <source> <destination>')
  .option(
    '-l, --langCodes <items>',
    'List of language codes that are compiled into the destination, separated by commas. Default: js,javascript,node',
    (string) => string.split(',')
  )
  .parse(process.argv)

if (program.args.length !== 2) {
  program.help()
}

const {langCodes, args: [source, destination]} = program

const currentPath = process.cwd()
const sourcePath = path.join(currentPath, source)
const destinationPath = path.join(currentPath, destination)

jsdotmd.compile(sourcePath, destinationPath, {langCodes})
  .catch((err) => console.log('Something went wrong!', err))

Make CLI output help if there's not enough args


/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule createRelayQuery
 * @flow
 */

'use strict';

const RelayMetaRoute = require('RelayMetaRoute');
const RelayQuery = require('RelayQuery');

const invariant = require('invariant');

function createRelayQuery(
  node: Object,
  variables: {[key: string]: mixed}
): RelayQuery.Root {
  invariant(
    typeof variables === 'object' &&
    variables != null &&
    !Array.isArray(variables),
    'Relay.Query: Expected `variables` to be an object.'
  );
  return RelayQuery.Root.create(
    node,
    RelayMetaRoute.get('$createRelayQuery'),
    variables
  );
}

module.exports = createRelayQuery;

/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule createRelayQuery
 * @flow
 */

'use strict';

const RelayMetaRoute = require('RelayMetaRoute');
const RelayQuery = require('RelayQuery');

const invariant = require('invariant');

import type {RelayConcreteNode} from 'RelayQL';
import type {Variables} from 'RelayTypes';

function createRelayQuery(
  node: RelayConcreteNode,
  variables: Variables
): RelayQuery.Root {
  invariant(
    typeof variables === 'object' &&
    variables != null &&
    !Array.isArray(variables),
    'Relay.Query: Expected `variables` to be an object.'
  );
  return RelayQuery.Root.create(
    node,
    RelayMetaRoute.get('$createRelayQuery'),
    variables
  );
}

module.exports = createRelayQuery;

Fix flow errors for Relay export


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

var async = require('async');
var cpr = require('cpr');
var cp = require('cp');

exports.copyExtraAssets = function(buildDir, assets, cb) {
  assets = assets || [];

  async.forEach(assets, function(asset, cb) {
    var from = asset.from;

    if(from.indexOf('./') === 0) {
        cp(from, path.join(buildDir, asset.to, from), cb);
    }
    else {
        cpr(from, path.join(buildDir, asset.to), cb);
    }
  }, cb);
};

exports.copyIfExists = function(from, to, cb) {
  fs.exists(from, function(exists) {
    if(exists) {
      cpr(from, to, cb);
    }
    else {
      cb();
    }
  });
};

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

var async = require('async');
var cpr = require('cpr');
var cp = require('cp');

exports.copyExtraAssets = function(buildDir, assets, cb) {
  assets = assets || [];

  async.forEach(assets, function(asset, cb) {
    var from = asset.from;
    var stats = fs.statSync(from);

    if(from.indexOf('./') === 0 && stats.isFile()) {
        cp(from, path.join(buildDir, asset.to, from), cb);
    }
    else {
        cpr(from, path.join(buildDir, asset.to), cb);
    }
  }, cb);
};

exports.copyIfExists = function(from, to, cb) {
  fs.exists(from, function(exists) {
    if(exists) {
      cpr(from, to, cb);
    }
    else {
      cb();
    }
  });
};

Check against dir when copying assets


/* @flow strict-local */
import { createSelector } from 'reselect';

import type { Narrow, Selector, User } from '../types';
import { getTyping, getUsers } from '../directSelectors';
import { getOwnEmail } from '../account/accountsSelectors';
import { getUserById } from '../users/userHelpers';
import { isPrivateOrGroupNarrow } from '../utils/narrow';
import { normalizeRecipients } from '../utils/recipient';
import { NULL_ARRAY } from '../nullObjects';

export const getCurrentTypingUsers: Selector<$ReadOnlyArray<User>, Narrow> = createSelector(
  (state, narrow) => narrow,
  state => getTyping(state),
  state => getUsers(state),
  state => getOwnEmail(state),
  (narrow, typing, users, ownEmail): User[] => {
    if (!isPrivateOrGroupNarrow(narrow)) {
      return NULL_ARRAY;
    }

    const recipients = narrow[0].operand.split(',').map(email => ({ email }));
    const normalizedRecipients = normalizeRecipients(recipients);
    const currentTyping = typing[normalizedRecipients];

    if (!currentTyping || !currentTyping.userIds) {
      return NULL_ARRAY;
    }

    return currentTyping.userIds.map(userId => getUserById(users, userId));
  },
);

/* @flow strict-local */
import { createSelector } from 'reselect';

import type { Narrow, Selector, User } from '../types';
import { getTyping } from '../directSelectors';
import { getOwnEmail } from '../account/accountsSelectors';
import { isPrivateOrGroupNarrow } from '../utils/narrow';
import { normalizeRecipients } from '../utils/recipient';
import { NULL_ARRAY, NULL_USER } from '../nullObjects';
import { getUsersById } from '../users/userSelectors';

export const getCurrentTypingUsers: Selector<$ReadOnlyArray<User>, Narrow> = createSelector(
  (state, narrow) => narrow,
  state => getTyping(state),
  state => getUsersById(state),
  state => getOwnEmail(state),
  (narrow, typing, usersById, ownEmail): User[] => {
    if (!isPrivateOrGroupNarrow(narrow)) {
      return NULL_ARRAY;
    }

    const recipients = narrow[0].operand.split(',').map(email => ({ email }));
    const normalizedRecipients = normalizeRecipients(recipients);
    const currentTyping = typing[normalizedRecipients];

    if (!currentTyping || !currentTyping.userIds) {
      return NULL_ARRAY;
    }

    return currentTyping.userIds.map(userId => usersById.get(userId) || NULL_USER);
  },
);

Use `getUsersById` for fast user search.


/*jslint node: true, expr: true */
/* global before, describe, it */
"use strict";
var assert = require("assert");
var expect = require("chai").expect;
var fs = require('fs');
var mongoose = require('mongoose');
var Promise = require('bluebird');
var should = require('should');
var _ = require('lodash');

var crypto = require('../lib/crypto');
var models = require('../lib/models');

var PASS = "s3cr37";
var user;

before(function (done) {
  models.Player.findOneAndUpdate({name: 'foobar'}, {name: 'foobar'}, {upsert: true})
    .then(function (saved) {
      user = saved;
      done();
    })
    .catch(done);
});

describe('Crypto', function() {
  it('should save user credentials', function(done) {
    crypto.saveUser({id: user.id}, PASS)
      .then(function (creds) {
        creds.salt.should.be.ok;
        creds.password_hash.should.be.ok;
        done();
      })
      .catch(done);
  });

  it('should validate user', function(done) {
    crypto.validateUser(user, PASS)
      .then(function (result) {
        result.user.should.equal(user.id);
        done();
      })
      .catch(done);
  });
});

/*jslint node: true, expr: true */
/* global before, describe, it */
"use strict";
var assert = require("assert");
var expect = require("chai").expect;
var fs = require('fs');
var mongoose = require('mongoose');
var Promise = require('bluebird');
var restify = require('restify');
var should = require('should');
var _ = require('lodash');

var crypto = require('../lib/crypto');
var models = require('../lib/models');

var PASS = "s3cr37";
var user;

before(function (done) {
  models.Player.findOneAndUpdate({name: 'foobar'}, {name: 'foobar'}, {upsert: true})
    .then(function (saved) {
      user = saved;
      done();
    })
    .catch(done);
});

describe('Crypto', function() {
  it('should save user credentials', function(done) {
    crypto.saveUser({id: user.id}, PASS)
      .then(function (creds) {
        creds.salt.should.be.ok;
        creds.password_hash.should.be.ok;
        done();
      })
      .catch(done);
  });

  it('should validate user', function(done) {
    crypto.validateUser(user, PASS)
      .then(function (result) {
        result.user.should.equal(user.id);
        done();
      })
      .catch(done);
  });

  it('should not validate with wrong pass', function(done) {
    crypto.validateUser(user, 'incorrect')
      .then(function (result) {
        done(new Error("Should have failed"));
      })
      .catch(restify.ForbiddenError, function () {
        done();
      })
      .catch(done);
  });
});

Add negative test for user validation


'use strict';

function init() {
  // Disable drag + drop event for document.
  document.addEventListener('dragover', function(event) {
    event.preventDefault();
    return false;
  }, false);

  document.addEventListener('drop', function(event) {
    event.preventDefault();
    return false;
  }, false);
  // Drag and Drop holder.
  const holder = document.getElementById('holder');
  // Placehold text in holder.
  const dragText = document.getElementById('drag-text');

  holder.ondragover = function() {
    return false;
  };

  holder.ondragleave = holder.ondragend = function() {
    return false;
  };

  holder.ondrop = function(e) {
    e.preventDefault();
    const file = e.dataTransfer.files[0];
    console.log('File you dragged here is', file.path);

    // Remove exitng video.
    const existingVideo = holder.getElementsByTagName('video')[0];
    if (existingVideo) { existingVideo.remove(); };

    dragText.className += ' hidden';

    const video = document.createElement("video");
    video.setAttribute('controls', '');
    video.setAttribute("width", '100%');
    video.setAttribute('height', '100%');
    const source = document.createElement("source");
    source.setAttribute('src', file.path);
    video.appendChild(source);
    holder.appendChild(video);
    return false;
  };
};

window.onload = init;

'use strict';

const videoClip = require('./movie.js');

function bindUI() {
  // Bind options to videoClip file.
}

function reset() {
  // Reset options to values of video file.
}

function init() {
  // Disable drag + drop event for document.
  document.addEventListener('dragover', function(event) {
    event.preventDefault();
    return false;
  }, false);
  document.addEventListener('drop', function(event) {
    event.preventDefault();
    return false;
  }, false);
  // Drag and Drop holder.
  const holder = document.getElementById('holder');
  // Placehold text in holder.
  const dragText = document.getElementById('drag-text');

  holder.ondragover = function() {
    return false;
  };

  holder.ondragleave = holder.ondragend = function() {
    return false;
  };

  holder.ondrop = function(e) {
    e.preventDefault();
    const file = e.dataTransfer.files[0];
    console.log('File you dragged here is', file.path);
    videoClip.video = file.path;
    // Remove exitng video.
    const existingVideo = holder.getElementsByTagName('video')[0];
    if (existingVideo) { existingVideo.remove(); };

    dragText.className += ' hidden';

    const video = document.createElement("video");
    video.setAttribute('controls', '');
    video.setAttribute("width", '100%');
    video.setAttribute('height', '100%');
    const source = document.createElement("source");
    source.setAttribute('src', file.path);
    video.appendChild(source);
    holder.appendChild(video);
    return true;
  };
}

window.onload = init;

Add functions to be filled later


/*
 * @license MIT License
 *
 * Copyright (c) 2014 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

/*
 * @license MIT License
 *
 * Copyright (c) 2015 Tetsuharu OHZEKI <saneyuki.snyk@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

Fix year in license block.


import View from '../View';
import HeaderAnalysesView from './HeaderAnalysesView';
import HeaderUserView from './HeaderUserView';
import HeaderImageView from './HeaderImageView';
import router from '../../router';

import headerTemplate from '../../templates/layout/header.pug';
import '../../stylesheets/layout/header.styl';

var HeaderView = View.extend({
    events: {
        'click .g-app-title': function () {
            router.navigate('', {trigger: true});
        }
    },

    initialize() {
        return View.prototype.initialize.apply(this, arguments);
    },

    render() {
        this.$el.html(headerTemplate());

        this.$('a[title]').tooltip({
            placement: 'bottom',
            delay: {show: 300}
        });

        new HeaderUserView({
            el: this.$('.h-current-user-wrapper'),
            parentView: this
        }).render();

        new HeaderImageView({
            el: this.$('.h-image-menu-wrapper'),
            parentView: this
        }).render();

        new HeaderAnalysesView({
            el: this.$('.h-analyses-wrapper'),
            parentView: this
        }).render();

        return this;
    }
});

export default HeaderView;

import View from '../View';
import HeaderAnalysesView from './HeaderAnalysesView';
import HeaderUserView from './HeaderUserView';
import HeaderImageView from './HeaderImageView';
import router from '../../router';

import headerTemplate from '../../templates/layout/header.pug';
import '../../stylesheets/layout/header.styl';

var HeaderView = View.extend({
    events: {
        'click #h-navbar-brand': function () {
            router.navigate('', {trigger: true});
        }
    },

    initialize() {
        return View.prototype.initialize.apply(this, arguments);
    },

    render() {
        this.$el.html(headerTemplate());

        this.$('a[title]').tooltip({
            placement: 'bottom',
            delay: {show: 300}
        });

        new HeaderUserView({
            el: this.$('.h-current-user-wrapper'),
            parentView: this
        }).render();

        new HeaderImageView({
            el: this.$('.h-image-menu-wrapper'),
            parentView: this
        }).render();

        new HeaderAnalysesView({
            el: this.$('.h-analyses-wrapper'),
            parentView: this
        }).render();

        return this;
    }
});

export default HeaderView;

Fix 'home' link in the header


import DS from 'ember-data';

export default DS.Model.extend({
  temp: DS.attr('number'),
  day:  DS.attr('number'),
  time: DS.attr('number'),
});

import DS from 'ember-data';

export default DS.Model.extend({
  temp: DS.attr('number'),

  // Seconds since 00:00 Monday.
  seconds: DS.attr('number'),
});

Switch to counting seconds since the beginning of the week.


import React, { Component } from 'react';

export default class App extends Component {
  render() {
    return (

Hello, world.

    );
  }
}

import React, { Component } from 'react';

export default class App extends Component {
  constructor(props) {
    super(props);

    this._ws = new WebSocket('ws://127.0.0.1:1880/ws/positions');
    this._ws.onmessage = (event) => this._handleData(JSON.parse(event.data));
  }

  _handleData(data) {
    console.log(data);
  }

  render() {
    return (

Hello, world.

    );
  }
}

Add logging of received JSON from websocket


'use strict';

//var FileUpload = require(process.cwd() + '/app/controllers/fileUpload.server.js');

module.exports = function (app) {

  //var fileUpload = new FileUpload();

  app.route('/')
      .get(function (req, res) {
          res.sendFile(process.cwd() + '/public/index.html');
      });

  //app.route('/upload')
  //    .post(fileUpload.getInfo);

};

'use strict';

//var FileUpload = require(process.cwd() + '/app/controllers/fileUpload.server.js');

module.exports = function (app) {

  //var fileUpload = new FileUpload();

  app.route('/')
    .get(function (req, res) {
      res.sendFile(process.cwd() + '/public/index.html');
    });

  app.get('/login/twitter',
    passport.authenticate('twitter'));

  app.get('/login/twitter/return',
    passport.authenticate('twitter', { failureRedirect: '/' }),
    function(req, res) {
      res.redirect('/');
    });

  //app.route('/upload')
  //    .post(fileUpload.getInfo);

};

Add routes to login with Passport


// TODO: Add more fields
function Event() {
    this.name = null;
    this.description = null;
}

$( "#sel-thing" ).change(function() {
    // Remove precreated input fields
    $(".input-field").remove();

    // What was selected
    // TODO: make generic
    if ($( "#sel-thing option:selected" ).text() == "Event") {
	var event = new Event();
	for(var propt in event){
	    $("#container").append("<input type=\"text\" class=\"form-control input-field\">");
	}
    }
});

// TODO: Add more fields
function Event() {
    this.name = null;
    this.description = null;
}

function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
}

$( "#sel-thing" ).change(function() {
    // Remove precreated input fields
    $(".deleatable").remove();

    // What was selected
    // TODO: make generic
    if ($( "#sel-thing option:selected" ).text() == "Event") {
	var event = new Event();
	for (var attribute in event) {
	    $("#container").append("
" + capitalizeFirstLetter(attribute) + ":<input type=\"text\" class=\"form-control\" id=\"" + attribute + "\">
");
	}
    }
});

Make form creation more generic


'use strict';

var fs = require('fs');
var writeDir = require('./writeDir');
var writeStream = require('./writeStream');
var writeBuffer = require('./writeBuffer');

function writeContents(writePath, file, cb) {
  var written = function(err){
    var done = function(err) {
      cb(err, file);
    };
    if (!err) {
      if (file.stat && typeof file.stat.mode === 'number') {
        fs.chmod(writePath, file.stat.mode, done);
        return;
      }
    }
    done(err);
  };

  // if directory then mkdirp it
  if (file.isDirectory()) {
    writeDir(writePath, file, written);
    return;
  }

  // stream it to disk yo
  if (file.isStream()) {
    writeStream(writePath, file, written);
    return;
  }

  // write it like normal
  if (file.isBuffer()) {
    writeBuffer(writePath, file, written);
    return;
  }

  // if no contents then do nothing
  if (file.isNull()) {
    cb(null, file);
    return;
  }
}

module.exports = writeContents;

'use strict';

var fs = require('fs');
var writeDir = require('./writeDir');
var writeStream = require('./writeStream');
var writeBuffer = require('./writeBuffer');

function writeContents(writePath, file, cb) {
  var written = function(err){
    var done = function(err) {
      cb(err, file);
    };
    if (!err) {
      if (file.stat && typeof file.stat.mode === 'number') {
        fs.stat(writePath, function(err, st) {
          if (err) {
            done(err);
            return;
          }
          // octal 7777 = decimal 4095
          if ((st.mode & 4095) !== file.stat.mode) {
            fs.chmod(writePath, file.stat.mode, done);
          } else {
            done(null);
          }
        });
        return;
      }
      return;
    }
    done(err);
  };

  // if directory then mkdirp it
  if (file.isDirectory()) {
    writeDir(writePath, file, written);
    return;
  }

  // stream it to disk yo
  if (file.isStream()) {
    writeStream(writePath, file, written);
    return;
  }

  // write it like normal
  if (file.isBuffer()) {
    writeBuffer(writePath, file, written);
    return;
  }

  // if no contents then do nothing
  if (file.isNull()) {
    cb(null, file);
    return;
  }
}

module.exports = writeContents;

Test if the file should be chmod'ed


/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

import Ajax from 'simple-ajax';

class Http {
  static get(path, callback) {
    var ajax = new Ajax(path);
    ajax.on('success', (event) => {
      var response = JSON.parse(event.target.responseText);
      callback(response.value);
    });
    ajax.send();
  }
}

module.exports = Http;

/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

import Ajax from 'simple-ajax';

class Http {
  static get(path, callback) {
    let ajax = new Ajax({
      url: path,
      method: 'GET',
    });
    ajax.on('success', event => {
      var response = JSON.parse(event.target.responseText);
      callback(response.value);
    });
    ajax.send();
  }

  static post(path, callback) {
    let ajax = new Ajax({
      url: path,
      method: 'POST',
    });
    ajax.on('success', event => {
      var response = JSON.parse(event.target.responseText);
      callback(response.value);
    });
    ajax.send();
  }
}

module.exports = Http;

Fix element tree for inspector


'use strict';

const ArchivePlugin = require('webpack-archive-plugin');
const DashboardPlugin = require('webpack-dashboard/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

const extractText = require('./extract-text');
const { rules } = require('./module');
const pages = require('./pages');

function createPagePlugin(page) {
  const filename = pages.hash.templatePages[page];
  const template = `${pages.path}/${page}`;
  return new HtmlWebpackPlugin({
    filename,
    inject: true,
    template,
  });
}

module.exports = function configurePlugins(env = {}, argv) {
  const envPlugins = env.production ? [
    new ArchivePlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
    new webpack.optimize.UglifyJsPlugin(),
  ] : [
    new DashboardPlugin()
  ];

  return [
    extractText.plugin,
    extractText.workaround(rules),
  ]
  .concat(pages.map(createPagePlugin))
  .concat(envPlugins)
  ;
};

'use strict';

const ArchivePlugin = require('webpack-archive-plugin');
const DashboardPlugin = require('webpack-dashboard/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

const extractText = require('./extract-text');
const { rules } = require('./module');
const pages = require('./pages');

function createPagePlugin(page) {
  const filename = pages.hash.templatePages[page].replace(/^\//, '');
  const template = `${pages.path}/${page}`;
  return new HtmlWebpackPlugin({
    filename,
    inject: true,
    template,
  });
}

module.exports = function configurePlugins(env = {}, argv) {
  const envPlugins = env.production ? [
    new ArchivePlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production'),
    }),
    new webpack.optimize.UglifyJsPlugin(),
  ] : [
    new DashboardPlugin()
  ];

  return [
    extractText.plugin,
    extractText.workaround(rules),
  ]
  .concat(pages.map(createPagePlugin))
  .concat(envPlugins)
  ;
};

Remove leading slash from page filenames


#!/usr/bin/env node

var ws = require('../lib/websocket');

var client = ws.connect('ws://localhost:8000', function (session) {
	session.setEncoding('utf8');
	session.send('Client');
	session.close();
	session.on('data', function (data) {
		console.log('server msg:', data);
	});
	session.on('end', function (code) {
		console.log('server ended:', code);
	});
	session.on('close', function () {
		console.log('session closed');
	});
});
client.on('error', function (error) {
	console.error(error.stack);
});

#!/usr/bin/env node

var ws = require('../lib/websocket');

var client = ws.connect('ws://localhost:8000', function (session) {
	session.setEncoding('utf8');
	session.send('Client');
	session.on('data', function (data) {
		console.log('server msg:', data);
	});
	session.on('end', function (code) {
		console.log('server ended:', code);
	});
	session.on('close', function () {
		console.log('session closed');
	});
});
client.on('error', function (error) {
	console.error(error.stack);
});

Correct the status code of close reason


#!/usr/bin/env node

var cli = require('cli'),
    hljs = require('highlight.js'),
    avaiableLanguages = hljs.listLanguages(),
    cheerio = require('cheerio'),
    Entities = require('html-entities').AllHtmlEntities,
    entities = new Entities(),
    fs = require('fs'),
    opts = cli.parse({
      selector: [
        's',
        'jQuery style selector which specifies on which elements highlighting is applied',
        'string',
        'pre code'
      ],
      output: [
        'o',
        'Output file path',
        'file',
        false
      ]
    });

cli.withStdin(function(input) {
  var $ = cheerio.load(input);
  $(opts.selector).each(function(_, elem) {
    var lang = $(elem).attr('class');
    var highlighted;
    if (lang && avaiableLanguages.indexOf(lang.toLower) != -1) {
      highlighted = hljs.highlight(lang, $(elem).text()).value;
    } else {
      highlighted = hljs.highlightAuto($(elem).text()).value;
    }
    $(elem).text(highlighted).addClass('hljs');
  });
  var out = entities.decode($.html());
  if (opts.output) {
    fs.writeFileSync(opts.output, out);
  } else {
    this.output(out);
  }
});

#!/usr/bin/env node

var cli = require('cli'),
    hljs = require('highlight.js'),
    availableLanguages = hljs.listLanguages(),
    cheerio = require('cheerio'),
    Entities = require('html-entities').AllHtmlEntities,
    entities = new Entities(),
    fs = require('fs'),
    opts = cli.parse({
      selector: [
        's',
        'jQuery style selector which specifies on which elements highlighting is applied',
        'string',
        'pre code'
      ],
      output: [
        'o',
        'Output file path',
        'file',
        false
      ]
    });

cli.withStdin(function(input) {
  var $ = cheerio.load(input);
  $(opts.selector).each(function(_, elem) {
    var lang = $(elem).attr('class');
    var highlighted;
    if (lang && availableLanguages.indexOf(lang.toLower) != -1) {
      highlighted = hljs.highlight(lang, $(elem).text()).value;
    } else {
      highlighted = hljs.highlightAuto($(elem).text()).value;
    }
    $(elem).text(highlighted).addClass('hljs');
  });
  var out = entities.decode($.html());
  if (opts.output) {
    fs.writeFileSync(opts.output, out);
  } else {
    this.output(out);
  }
});

Fix typo: avaiableLanguages -> availableLanguages


'use strict';

const crypto = require('crypto');
const Network = require('./network');
const Witness = require('./witness');
const MAX_MEMORY = Math.pow(2, 21) + (64 * 1000);

class EncryptedPromise {
  constructor (settings = {}) {
    // Assign Settings
    // TODO: make private
    this.settings = Object.assign({}, settings);

    // Create Internal State
    this._state = {
      blob: Buffer.alloc(MAX_MEMORY),
      data: JSON.stringify(this._settings)
    };

    if (this._state.data.length > this._state.blob.size) {
      throw new Error(`Promise not created, input too large, maximum size is ${MAX_MEMORY}`);
    }

    Object.defineProperty(this, '_state', { enumerable: false });

    this.load();
  }

  get id () {
    return crypto.createHash('sha256').update(this._state.data).digest('hex');
  }

  get state () {
    this.load();

    // TODO: formalize type
    return {
      type: 'EncryptedPromise',
      blob: this._state.blob
    };
  }

  set settings (map) {
    this._settings = map;
  }

  load () {
    this._state.blob.write(this._state.data);
  }

  resolve (msg) {
    return {
      id: this.id,
      msg: msg
    };
  }

  decrypt () {

  }
}

module.exports = EncryptedPromise;

'use strict';

const crypto = require('crypto');
const Network = require('./network');
const Witness = require('./witness');
const MAX_MEMORY = Math.pow(2, 21) + (64 * 1000);

class EncryptedPromise {
  constructor (settings = {}) {
    // Assign Settings
    // TODO: make private
    this.settings = Object.assign({}, settings);

    // Create Internal State
    this._state = {
      blob: Buffer.alloc(MAX_MEMORY),
      data: JSON.stringify(this._settings)
    };

    if (this._state.data.length > this._state.blob.size) {
      throw new Error(`Promise not created, input too large, maximum size is ${MAX_MEMORY}`);
    }

    Object.defineProperty(this, '_state', { enumerable: false });

    this.load();
  }

  get id () {
    return crypto.createHash('sha256').update(this._state.data).digest('hex');
  }

  get state () {
    this.load();

    // TODO: formalize type
    return {
      type: 'EncryptedPromise',
      blob: this._state.blob
    };
  }

  set settings (map) {
    this._settings = map;
  }

  async _assignState (state) {
    this.status = 'assigning';
    this._state.data = JSON.stringify(state);
    this.load();
    this.status = 'assigned';
  }

  load () {
    this.status = 'loading';
    this._state.blob.write(this._state.data);
    this.status = 'loaded';
  }

  resolve (msg) {
    return {
      id: this.id,
      msg: msg
    };
  }

  decrypt () {
    // TODO: recover state
  }
}

module.exports = EncryptedPromise;

Add missing method to Promise


exports.config = {
  host: 'selenium',

  specs: [
    './tests/acceptance/specs/**/*.spec.js'
  ],

  maxInstances: 10,
  capabilities: [{
    browserName: 'chrome'
  }],

  sync: true,
  logLevel: 'error',
  coloredLogs: true,
  bail: 0,
  screenshotPath: './tests/acceptance/results/',
  baseUrl: 'http://app:3000',

  waitforTimeout: 10 * 1000,
  connectionRetryTimeout: 90 * 1000,
  connectionRetryCount: 3,

  framework: 'mocha',
  mochaOpts: {
    ui: 'bdd',
    compilers: ['js:babel-register'],
    timeout: 10 * 1000
  },

  reporters: ['dot'],

  beforeTest: function resetApp() {
    browser.url('http://app:3000')
      .waitForVisible('.todoapp', 5 * 1000);
  }
};

exports.config = {
  host: 'selenium',

  specs: [
    './tests/acceptance/specs/**/*.spec.js'
  ],

  maxInstances: 10,
  capabilities: [{
    browserName: 'chrome'
  }],

  sync: true,
  logLevel: 'error',
  coloredLogs: true,
  bail: 0,
  baseUrl: 'http://app:3000',

  waitforTimeout: 10 * 1000,
  connectionRetryTimeout: 90 * 1000,
  connectionRetryCount: 3,

  framework: 'mocha',
  mochaOpts: {
    ui: 'bdd',
    compilers: ['js:babel-register'],
    timeout: 10 * 1000
  },

  reporters: ['dot'],

  beforeTest: function resetApp() {
    browser.url('http://app:3000')
      .waitForVisible('.todoapp', 5 * 1000);
  }
};

Disable screenshots in wdio runner


var timer = require('contimer'),
    TIMER_LABEL = '__response_timer_label__';

module.exports = function requestTimeMiddleware(cb) {
    return function(req, res, next) {
        timer.start(req, TIMER_LABEL);

        res
            .on('finish', onFinish)
            .on('cancel', onCancel);

        function onFinish() {
            var timeObj = timer.stop(req, TIMER_LABEL);
            cb(timeObj.time, req);
        }

        function onCancel() {
            res
                .removeListener('cancel', onCancel)
                .removeListener('finish', onFinish);

            // FIXME: what should we do here?
            cb(0, req);
        }

        next();
    };
};

var timer = require('contimer'),
    TIMER_LABEL = '__response_timer_label__';

module.exports = function requestTimeMiddleware(cb) {
    return function(req, res, next) {
        var timerStop = timer.start({}, TIMER_LABEL);

        res
            .on('finish', onFinish)
            .on('cancel', onCancel);

        function onFinish() {
            var timeObj = timerStop();
            cb(timeObj.time, req);
        }

        function onCancel() {
            res
                .removeListener('cancel', onCancel)
                .removeListener('finish', onFinish);

            // FIXME: what should we do here?
            cb(0, req);
        }

        next();
    };
};

Use empty object as a context instead of request object


Add Critical and Dist tasks


'use strict'

var fs = require('fs')
var promise = require('cb2promise')

function isString (str) {
  return typeof str === 'string'
}

function existeFile (filepath, cb) {
  if (!isString(filepath)) throw new TypeError('path must be a string')
  if (!cb) return promise(existeFile, filepath)

  fs.stat(filepath, function (err, stats) {
    if (!err) return cb(null, true)
    if (err.code === 'ENOENT') return cb(null, false)
    return cb(err, stats)
  })
}

existeFile.sync = function existeFileSync (filepath) {
  if (!isString(filepath)) throw new TypeError('path must be a string')
  try {
    fs.statSync(filepath)
    return true
  } catch (err) {
    if (err.code === 'ENOENT') return false
    throw err
  }
}

module.exports = existeFile

'use strict'

var fs = require('fs')
var promise = require('cb2promise')

function isString (str) {
  return typeof str === 'string'
}

function existeFile (filepath, cb) {
  if (!isString(filepath)) throw new TypeError('path must be a string')
  if (!cb) return promise(existeFile, filepath)

  fs.stat(filepath, function (err, stats) {
    if (!err) return cb(null, true)
    if (err.code === 'ENOENT') return cb(null, false)
    return cb(err, stats)
  })
}

existeFile.sync = fs.existsSync

module.exports = existeFile

Use fs.existsSync, is not deprecated


module.exports = {
  '{USER}': function(user, cb) {
    var self = this;
    if (!self.config || !self.config.welcome) return;

    // simulate a real user delay
    setTimeout(function() {
      var knownUser = ~Object.keys(self.userMap).indexOf(user.id);
      if (!knownUser) {
        self.__rpc('im.open', {
          user: user.id
        }, function(err, response) {
          if (!response || !response.channel || !response.channel.id) {
            return console.error('Invalid response:', err, response);
          }

          if (self.config.welcome instanceof Array) {
            var timing = 0;
            var spacing = 15000;
            self.config.welcome.forEach(function(message) {
              setTimeout(function() {
                self.__say(response.channel.id, formatText(message));
              }, timing);
              timing += spacing;
            });
          } else {
            self.__say(response.channel.id, self.config.welcome);
          }
        });

      }
    }, 1000);

    function formatText(input) {
      for (var id in self.channelMap) {
        var channel = self.channelMap[id];
        input = input.replace('{{channel:'+channel.name+'}}', '<#'+id+'>');
      }
      for (var id in self.userMap) {
        var channel = self.userMap[id];
        input = input.replace('{{channel:'+channel.name+'}}', '<#'+id+'>');
      }
      input = input.replace('{{user}}', '<@'+user.id+'>');
      return input;
    }

  }
};

module.exports = {
  '{USER:NEW}': function(message, cb) {
    var self = this;
    if (!self.config || !self.config.welcome) return;

    var user = message.user;

    self.__rpc('im.open', {
      user: user.id
    }, function(err, response) {
      if (!response || !response.channel || !response.channel.id) {
        return console.error('Invalid response:', err, response);
      }

      if (self.config.welcome instanceof Array) {
        var timing = 15000; // start timing (send first message 15 seconds in)
        var spacing = 15000; // interval between messages
        self.config.welcome.forEach(function(message) {
          setTimeout(function() {
            self.__say(response.channel.id, formatText(message));
          }, timing);
          timing += spacing;
        });
      } else {
        self.__say(response.channel.id, formatText(self.config.welcome));
      }
    });

    function formatText(input) {
      for (var id in self.channelMap) {
        var channel = self.channelMap[id];
        input = input.replace('{{channel:'+channel.name+'}}', '<#'+id+'>');
      }
      for (var id in self.userMap) {
        var user = self.userMap[id];
        input = input.replace('{{user:'+user.name+'}}', '<#'+id+'>');
      }
      input = input.replace('{{user}}', '<@'+user.id+'>');
      return input;
    }

  }
};

Use new snarl plugin feature instead of emulating / waiting.


/* jshint node:true */

'use strict';

var csso            = require('csso'),
    gutil           = require('gulp-util'),
    transform       = require('stream').Transform,
    bufferstreams   = require('bufferstreams'),

    PLUGIN_NAME     = 'gulp-csso';

function cssoTransform(optimise) {
    // Returns a callback that handles the buffered content
    return function(err, buffer, cb) {
        if (err) {
            cb(gutil.PluginError(PLUGIN_NAME, err));
        }
        var optimised = csso.justDoIt(String(buffer), optimise);
        cb(null, new Buffer(optimised));
    };
}

function gulpcsso(optimise) {
    var stream = new transform({ objectMode: true });

    stream._transform = function(file, unused, done) {
        // Pass through if null
        if (file.isNull()) {
            stream.push(file);
            done();
            return;
        }

        if (file.isStream()) {
            file.contents = file.contents.pipe(new bufferstreams(cssoTransform(optimise)));
            stream.push(file);
            done();
        } else {
            var optimised = csso.justDoIt(String(file.contents), optimise);
            file.contents = new Buffer(optimised);
            stream.push(file);
            done();
        }
    };

    return stream;
}

gulpcsso.cssoTransform = cssoTransform;
module.exports = gulpcsso;

/* jshint node:true */

'use strict';

var csso            = require('csso'),
    gutil           = require('gulp-util'),
    transform       = require('stream').Transform,
    bufferstreams   = require('bufferstreams'),

    PLUGIN_NAME     = 'gulp-csso';

function cssoTransform(optimise) {
    // Returns a callback that handles the buffered content
    return function(err, buffer, cb) {
        if (err) {
            cb(new gutil.PluginError(PLUGIN_NAME, err));
        }
        var optimised = csso.justDoIt(String(buffer), optimise);
        cb(null, new Buffer(optimised));
    };
}

function gulpcsso(optimise) {
    var stream = new transform({ objectMode: true });

    stream._transform = function(file, unused, done) {
        // Pass through if null
        if (file.isNull()) {
            stream.push(file);
            done();
            return;
        }

        if (file.isStream()) {
            file.contents = file.contents.pipe(new bufferstreams(cssoTransform(optimise)));
            stream.push(file);
            done();
        } else {
            var optimised = csso.justDoIt(String(file.contents), optimise);
            file.contents = new Buffer(optimised);
            stream.push(file);
            done();
        }
    };

    return stream;
}

gulpcsso.cssoTransform = cssoTransform;
module.exports = gulpcsso;

Use new with gutil plugin error.


var express = require('express');
var app = require('express')();
var http =require('http').Server(app);
var io = require('socket.io')(http);

io.on('connection',function(client){
	console.log("user connected");
});

app.get('/', function(req,res){
	res.sendFile(__dirname + '/index.html');
});
app.use(express.static('Public'));

http.listen(process.env.PORT || 81, function(){
	console.log("Listening on *:81");
});

var express = require('express');
var app = require('express')();
var http =require('http').Server(app);
var io = require('socket.io')(http);

var MongoClient = require('mongodb').MongoClient;
var dbUrl = 'mongodb://localhost:27017/TrackMaster';

MongoClient.connect(dbUrl, function(err, db) {
    if (err) {
        console.log("Unable to connect to DB: ", err);
        return;
    }

    io.on('connection',function(client){
        console.log("user connected");
    });

    app.get('/', function(req,res){
        res.sendFile(__dirname + '/index.html');
    });
    app.use(express.static('Public'));

    http.listen(process.env.PORT || 81, function(){
        console.log("Listening on *:81");
    });
});

Add code to open database


'use strict'

var toArray = require('to-array')

module.exports = function smallest (values) {
  if (!Array.isArray(values)) {
    values = toArray(arguments)
  }
  return values.slice().sort(order)[0]
}

function order (a, b) {
  return a - b
}

'use strict'
module.exports = function smallest (values) {
  return Math.min.apply(Math, Array.isArray(values) ? values : arguments)
}

Use Math.min instead of sorting


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

var path = require('path');
var replace = require('broccoli-string-replace');
var mergeTrees = require('broccoli-merge-trees');
var Funnel = require('broccoli-funnel');

module.exports = {
  name: 'lodash',

  _shouldCompileJS: function() {
    return true;
  },

  treeForAddon: function(tree) {
    var lodashPath = path.dirname(require.resolve('lodash-es'));

    let lodashTree = replace(lodashPath, {
      files: [ '*.js' ],
      pattern: {
        match: /\.js/g,
        replacement: ''
      }
    });

    lodashTree = new Funnel(lodashTree, {
      getDestinationPath: function(path) {
        if (path === 'lodash.js') {
          return 'index.js';
        }

        return path;
      }
    });

    lodashTree = replace(lodashTree, {
      files: [ '_getNative.js' ],
      pattern: {
        match: /undefined/g,
        replacement: 'null'
      }
    });

    if (tree) {
      tree = mergeTrees([lodashTree, tree], {
        overwrite: true
      });
    } else {
      tree = lodashTree;
    }

    return this._super(tree);
  }
};

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

var path = require('path');
var replace = require('broccoli-string-replace');
var mergeTrees = require('broccoli-merge-trees');
var Funnel = require('broccoli-funnel');

module.exports = {
  name: 'lodash',

  _shouldCompileJS: function() {
    return true;
  },

  treeForAddon: function(tree) {
    var lodashPath = path.dirname(require.resolve('lodash-es'));

    let lodashTree = replace(lodashPath, {
      files: [ '*.js' ],
      pattern: {
        match: /\.js/g,
        replacement: ''
      }
    });

    lodashTree = new Funnel(lodashTree, {
      getDestinationPath: function(path) {
        if (path === 'lodash.js') {
          return 'index.js';
        }

        return path;
      }
    });

    lodashTree = replace(lodashTree, {
      files: [ '_getNative.js' ],
      pattern: {
        match: /undefined/g,
        replacement: 'null'
      }
    });

    if (tree) {
      tree = mergeTrees([lodashTree, tree], {
        overwrite: true
      });
    } else {
      tree = lodashTree;
    }

    return this._super.treeForAddon.call(this, tree);
  }
};

Use _super.methodName instead of bare super.


var ejs = require('ejs');
var path = require('path');
var conf = require('./conf');
var express = require('express');
var favicon = require('serve-favicon');
var bodyParser = require('body-parser');
var session = require('express-session');

publicPath = path.join(__dirname, 'pub');
viewsPath = path.join(__dirname, 'views');
faviconPath = path.join(__dirname, '/pub/favicon.ico');

var app = express();
app.use(bodyParser.json());
app.set('views', viewsPath);
app.use(favicon(faviconPath));
app.use(session(conf.session));
app.use(express.static(publicPath));
app.use(bodyParser.urlencoded({ extended: false }));

app.engine('html', ejs.__express);
app.set('view engine', 'html');

app.get('/login', function (req, res) {
    res.render('login');
});
app.use('/' + conf.version + '/api', require('./api'));
app.get('/', function (req, res) {
    res.render('index');
});

// production error handler
app.use(function (err, req, res, next) {
    console.error(err.stack);
    res.status(500).render('error');
});

app.listen(conf.port, function (err) {
    if (err) {
        console.log('Create server fail!');
    } else {
        console.log('%s listening at %s', conf.path, conf.port);
    }
});

var ejs = require('ejs');
var path = require('path');
var conf = require('./conf');
var express = require('express');
var favicon = require('serve-favicon');
var bodyParser = require('body-parser');
var session = require('express-session');

publicPath = path.join(__dirname, 'pub');
viewsPath = path.join(__dirname, 'views');
faviconPath = path.join(__dirname, '/pub/favicon.ico');

var app = express();
app.use(bodyParser.json());
app.set('views', viewsPath);
app.use(favicon(faviconPath));
app.use(session(conf.session));
app.use(express.static(publicPath));
app.use(bodyParser.urlencoded({ extended: false }));

app.engine('html', ejs.__express);
app.set('view engine', 'html');

app.get('/login', function (req, res) {
    res.render('login');
});
app.use('/' + conf.version + '/api', require('./api'));

app.get('/', function (req, res) {
    if(!req.session.user){
        return res.redirect('/login');
    }
    res.render('index');
});

// production error handler
app.use(function (err, req, res, next) {
    console.error(err.stack);
    res.status(500).render('error');
});

app.listen(conf.port, function (err) {
    if (err) {
        console.log('Create server fail!');
    } else {
        console.log('%s listening at %s', conf.path, conf.port);
    }
});

Add redirect to /login page.


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

    //test icon background
	testIconBackgroundColorWithIcon: {
        test: function(cmp) {
        	var pillIcons = $A.test.select('.pillIcon');

            //there should only be one pill,  because the other two pills doesnt have iconUrl
            $A.test.assertEquals(
                1,
                pillIcons.length,
                'There should be only one pill icon on the page'
            );

            var elPillIcon = pillIcons[0];

            //assert background color
            var stylePillIcon = $A.test.getStyle(elPillIcon,"background-color");
 			var expectedStyle = "rgb(255, 0, 255)";
            $A.test.assertEquals(expectedStyle, stylePillIcon, '.pillIcon should have a background style. Found style: ' + stylePillIcon)
        }
	}
})

/*
 * Copyright (C) 2013 salesforce.com, inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
({
    //test icon background
	testIconBackgroundColorWithIcon: {
        test: function(cmp) {
        	var pillIcons = $A.test.select('.pillIcon');

            //there should only be one pill,  because the other two pills doesnt have iconUrl
            $A.test.assertEquals(
                1,
                pillIcons.length,
                'There should be only one pill icon on the page'
            );

            var elPillIcon = pillIcons[0];

            //assert background color
            var stylePillIcon = $A.test.getStyle(elPillIcon,"background-color");
 			var expectedStyle = "rgb(255, 0, 255)";
            $A.test.assertEquals(expectedStyle, stylePillIcon, '.pillIcon should have a background style. Found style: ' + stylePillIcon)
        }
	}
})

Test fix, remove invalid owner


'use strict';
(() => {
  module.exports = (gulp, plugins, config) => {
    return () => {
      return plugins.vinylFs.src([config.patternsPath + '/**/*.js',
                                  config.patternsPath + '/**/*.json',
                                  '!' + config.patternsPath + '/**/rocketbelt.slipsum-cache.json'])
        .pipe(plugins.plumber({ errorHandler: plugins.notify.onError('Error: <%= error.message %>') }))
        .pipe(plugins.vinylFs.symlink(config.templatesPath, { relative: true }));
    };
  };
})();

'use strict';
(() => {
  module.exports = (gulp, plugins, config) => {
    return () => {
      return plugins.vinylFs.src([`${config.patternsPath}/**/*.js`,
                                  `${config.patternsPath}/**/*.json`,
                                  `!${config.patternsPath}/**/rocketbelt.slipsum-cache.json`,
                                  `!${config.patternsPath}/tools/**/*`])
        .pipe(plugins.plumber({
          errorHandler: plugins.notify.onError('Error: <%= error.message %>')
        }))
        .pipe(plugins.vinylFs.symlink(config.templatesPath, { relative: true }));
    };
  };
})();

Exclude JS files in tools directory from symlinking.


(function() {

    describe('SearchService', function() {
        var SearchService;
        beforeEach(function() {
            module('awesome-app.search');

            inject(function(_SearchService_) {
                SearchService = _SearchService_;
            });

        });

        it('should save workers', function() {
            SearchService.workers = [];
            var members = [{name: 'Ross Gellar'}];

            SearchService.setWorkers(members);

            expect(SearchService.workers).toEqual([{name: 'Ross Gellar'}]);
        });

        it('should clear workers array if content is same as previous', function() {
            SearchService.setWorkers([{name: 'Ross Gellar'}]);

            expect(SearchService.workers).toEqual([{name: 'Ross Gellar'}]);

            SearchService.setWorkers([{name: 'Ross Gellar'}]);

            expect(SearchService.workers).toEqual([]);
        });

        it ('should get workers', function() {

        });
    });

})();

(function() {

    describe('SearchService', function() {
        var SearchService;
        beforeEach(function() {
            module('awesome-app.search');

            inject(function(_SearchService_) {
                SearchService = _SearchService_;
            });

        });

        it('should save workers', function() {
            SearchService.workers = [];
            var members = [{name: 'Ross Gellar'}];

            SearchService.setWorkers(members);

            expect(SearchService.workers).toEqual([{name: 'Ross Gellar'}]);
        });

        it('should clear workers array if content is same as previous', function() {
            SearchService.setWorkers([{name: 'Ross Gellar'}]);

            expect(SearchService.workers).toEqual([{name: 'Ross Gellar'}]);

            SearchService.setWorkers([{name: 'Ross Gellar'}]);

            expect(SearchService.workers).toEqual([]);
        });

        it('should return true if array already has the item', function() {
            var array = [{name: 'Yukihiro Matsumoto'}];
            var item = {name: 'Yukihiro Matsumoto'};

            expect(SearchService.findItemInArray(item, array)).toBe(true);
        });

        it('should return false if array does not contain the item', function() {
            var array = [{name: 'Douglas Crockford'}];
            var item = {name: 'Yukihiro Matsumoto'};

            expect(SearchService.findItemInArray(item, array)).toBe(false);
        });
    });

})();

Add tests for findItemInArray function


"use strict"

import React from "react"
import StatusMessage from "./status-message"
import PollTable from "./poll-table"
import PollReport from "./poll-report"
import Nav from "./nav"
import throttle from "lodash/function/throttle"

// Declare here for global throttling
const updateWho = throttle((flux, who) => flux.getActions("poll").updateWho(who), 5000)

export default class App extends React.Component {
  onChangeWho(e) {
    updateWho(this.props.flux, e.target.value)
  }

  render() {
    const input = this.props.showTable ? <input placeholder="Entrez votre nom" defaultValue={ this.props.who } onChange={ e => this.onChangeWho(e) } /> : null
    const table = this.props.showTable ? <PollTable { ...this.props } /> : null
    const report = this.props.showReport ? <PollReport { ...this.props } /> : null

    return (
      <div className="poll">
        { input }
        { table }
        <Nav { ...this.props } />
        { report }
        <StatusMessage />
      </div>
    );
  }
}

"use strict"

import React from "react"
import StatusMessage from "./status-message"
import PollTable from "./poll-table"
import PollReport from "./poll-report"
import Nav from "./nav"
import throttle from "lodash/function/throttle"

// Declare here for global throttling
const updateWho = throttle((flux, who) => flux.getActions("poll").updateWho(who), 5000)

export default class App extends React.Component {
  constructor(props) {
    super(props)
    // "who" is a state here for better reactivity (*)
    this.state = {"who": props.who}
  }

  onChangeWho(e) {
    // (*) Note this function is throttled because it's an onChange
    // (*) so prop "who" will not always be updated, which could cause undecent latency
    updateWho(this.props.flux, e.target.value)
    // (*) So we rely on state
    this.setState({"who": e.target.value})
  }

  render() {
    const props = {...this.props, ...this.state}
    const input = this.props.showTable ? <input placeholder="Entrez votre nom" defaultValue={ this.state.who } onChange={ e => this.onChangeWho(e) } /> : null
    const table = this.props.showTable ? <PollTable { ...props } /> : null
    const report = this.props.showReport ? <PollReport { ...props } /> : null

    return (
      <div className="poll">
        { input }
        { table }
        <Nav { ...props } />
        { report }
        <StatusMessage />
      </div>
    );
  }
}

Fix issue with 'who' lagging behind user typing


var _ = require('lodash');

function tryToLoadGenerator(nameOrObject, lookupTable, thingKind) {
  var parsed = parseNameOrObject(nameOrObject);
  if (!parsed) {
    return nameOrObject;
  }

  var thing = lookupTable[parsed.name];
  if (!thing){
    throw new Error('Failed to resolve ' + nameOrObject + ' ' + thingKind);
    return;
  }
  if (typeof thing === 'function') {
    return thing(parsed.options);
  }

  return thing;
}

function parseNameOrObject(nameOrObject) {
  if (typeof nameOrObject === 'string') {
    return { name: nameOrObject, options: {} };
  }

  if (typeof nameOrObject === 'object') {
    var name = nameOrObject.generator;
    if (typeof name === 'string') {
      return { name, options: _.omit(nameOrObject, 'name') };
    }
  }

  return nameOrObject;
}

module.exports = {
  tryToLoadGenerator
};

var _ = require('lodash');

function tryToLoadGenerator(nameOrObject, lookupTable, thingKind) {
  var parsed = parseNameOrObject(nameOrObject);
  if (!parsed) {
    return nameOrObject;
  }

  var thing = lookupTable[parsed.name];
  if (!thing){
    throw new Error('Failed to resolve ' + nameOrObject + ' ' + thingKind);
    return;
  }
  if (typeof thing === 'function') {
    return thing(parsed.options);
  }

  return thing;
}

function parseNameOrObject(nameOrObject) {
  if (typeof nameOrObject === 'string') {
    return { name: nameOrObject, options: {} };
  }

  if (typeof nameOrObject === 'object') {
    var name = nameOrObject.generator;
    if (typeof name === 'string') {
      return { name, options: _.omit(nameOrObject, 'name') };
    }
  }
}

module.exports = {
  tryToLoadGenerator
};

Fix try to load generators allowing raw object


import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';

Template.registerHelper('accuracy', (fired, landed) => {
  let accuracy = 0;
  if (fired !== undefined && landed !== undefined && landed !== 0) {
    accuracy = Math.trunc((fired / landed) * 100);
  }
  return accuracy;
});

Template.registerHelper('KDA', (kills, assists, deaths) => {
  return ((kills + (assists / 3)) / Math.max(1, deaths)).toFixed(1);
});

Template.registerHelper('player', () => {
  return Session.get('player');
});

import { Session } from 'meteor/session';
import { Template } from 'meteor/templating';

Template.registerHelper('accuracy', (fired, landed) => {
  let accuracy = 0;
  if (fired !== undefined && landed !== undefined && landed !== 0) {
    accuracy = Math.trunc((fired / landed) * 100);
  }
  return accuracy;
});

Template.registerHelper('KDA', (kills, assists, deaths) => {
  return Math.trunc((kills + (assists / 3) - deaths) * 10) / 10;
});

Template.registerHelper('player', () => {
  return Session.get('player');
});

Use Halo 5 KDA calculation


import React from 'react'
import { switchViewClassificationDetails } from '../actions/app-state'
import { sparqlConnect } from '../sparql/configure-sparql'
import { LOADING, LOADED, FAILED } from 'sparql-connect'
import { connect } from 'react-redux'
import { Link } from 'react-router'
import Loading from './loading.js'
import { URIToRoute } from '../router-mapping'

function Classifications({ loaded, classifications,
    switchViewClassificationDetails }) {
  if (loaded !== LOADED) {
    return( <Loading from="Classification" plural={false} />
          )
           } else {
  //we could also write something like
  //if (loaded === FAILED)
  //  return error while retrieving clasifications/span>

  //`URIToRoute.classification(...)` will return a string like `nacer2/nace`
  //where `nacer2` is the `classification` paremeter for the router, and `nace`
  //the `conceptScheme` paremeter
  return (

Classifications

        { classifications.map(({ classification }) =>

              <Link to={`/classification/${URIToRoute.classification(classification)}`}>
                {classification}
              </Link>

          )}

  )
}
}

const mapDispatchToProps = {
  switchViewClassificationDetails
}

export default connect(undefined, mapDispatchToProps)(
  sparqlConnect.classifications(Classifications))

import React from 'react'
import { sparqlConnect } from '../sparql/configure-sparql'
import { LOADING, LOADED, FAILED } from 'sparql-connect'
import { connect } from 'react-redux'
import { Link } from 'react-router'
import Loading from './loading.js'
import { URIToRoute } from '../router-mapping'

function Classifications({ loaded, classifications }) {
  if (loaded !== LOADED) return  <Loading from="Classification" plural={false} />

  //`URIToRoute.classification(...)` will return a string like `nacer2/nace`
  //where `nacer2` is the `classification` paremeter for the router, and `nace`
  //the `conceptScheme` paremeter
  return (

Classifications

        { classifications.map(({ classification }) =>

              <Link to={`/classification/${URIToRoute.classification(classification)}`}>
                {classification}
              </Link>

          )}

  )
}

export default sparqlConnect.classifications(Classifications)

Remove unnecessary code since the introduction of the router


"use strict";

var add = require("../../addSprite");// eslint-disable-line no-unused-vars

//var camera = 10;
module.exports = function(ecs, game) { // eslint-disable-line no-unused-vars
	ecs.add(function addSprite(elapsed) { // eslint-disable-line no-unused-vars
		if (game.input.buttonPressed("action")) {
			for (var i = 0; i < 10; i++) {
				add(game, "sprite");
			}
		}
	});
};

"use strict";

var add = require("../../addSprite");// eslint-disable-line no-unused-vars

//var camera = 10;
module.exports = function(ecs, game) { // eslint-disable-line no-unused-vars
	ecs.add(function addSprite(elapsed) { // eslint-disable-line no-unused-vars
		if (game.input.button("action") || game.input.mouse.isPressed(0)) {
			add(game, "sprite");
		}
	});
};

Add more sprites faster, and with mouse


angular.module('chronontology.components')
    .component('periodTypeTagCloud',{
        templateUrl: '../../partials/period/type-tag-cloud.html',
        controller: function ($http, chronontologySettings) {

            this.tags = [];
            var ctrl = this;

            var uri = "/data/period/?size=0&facet=resource.types";
            $http.get(uri).then(
    			function success(result) {
    				result.data.facets['resource.types'].buckets.forEach(function(bucket) {
                        ctrl.tags.push({text: bucket.key, weight: bucket.doc_count});
                    });
    			},
    			function error(err) {
    				console.warn(err);
    			}
    		);

        }
    });

angular.module('chronontology.components')
    .component('periodTypeTagCloud',{
        templateUrl: '../../partials/period/type-tag-cloud.html',
        controller: function ($http, chronontologySettings) {

            this.tags = [];
            var ctrl = this;

            var uri = "/data/period/?size=0&facet=resource.types";
            $http.get(uri).then(
    			function success(result) {
    				result.data.facets['resource.types'].buckets.forEach(function(bucket) {
                        ctrl.tags.push({
                            text: bucket.key,
                            weight: bucket.doc_count,
                            link: "/search?q=&fq=types:\"" + bucket.key + "\""
                        });
                    });
    			},
    			function error(err) {
    				console.warn(err);
    			}
    		);

        }
    });

Add search links to tag cloud terms


GlobalProperties = {
	'elasticSearchServer': 'http://localhost:9200',
    'elasticSearchTimeout': 30000,
    'pageSize': 100
}

GlobalProperties = {
	'elasticSearchServer': 'http://demo.logstash.net:9200',
    'elasticSearchTimeout': 30000,
    'pageSize': 100
}

Make default elasticsearch config to point to logstash demo instance.


import styled from 'styled-components';

const Layout = styled.div`
  font-family: Arial, Verdana, Tahoma;
  font-size: 16px;
  box-sizing: border-box;

  *, *:before, *:after {
    box-sizing: inherit;
  }
`;

export default Layout;

import styled, { injectGlobal } from 'styled-components';

injectGlobal`
  html {
    box-sizing: border-box;
  }

  *, *:before, *:after {
    box-sizing: inherit;
  }

  body {
    margin: 0;
    padding: 0;
    font-family: Arial, Verdana, Tahoma;
    font-size: 16px;
  }
`;

const Layout = styled.div`
  width: 95%;
  margin-left: auto;
  margin-right: auto;
`;

export default Layout;

Add global style and update layout style.


Package.describe({
  summary: "JavaScript minifier",
  version: "2.6.1"
});

Npm.depends({
  terser: "4.8.0"
});

Package.onUse(function (api) {
  api.use('ecmascript');
  api.use('babel-compiler');
  api.mainModule('minifier.js', 'server');
  api.export('meteorJsMinify');
});

Package.onTest(function (api) {
  api.use('ecmascript');
  api.use('tinytest');
  api.use('minifier-js');
  api.mainModule('minifier-tests.js', 'server');
});

Package.describe({
  summary: "JavaScript minifier",
  version: "2.6.1"
});

Npm.depends({
  terser: "4.8.0"
});

Package.onUse(function (api) {
  api.use('ecmascript');
  api.mainModule('minifier.js', 'server');
  api.export('meteorJsMinify');
});

Package.onTest(function (api) {
  api.use('ecmascript');
  api.use('tinytest');
  api.use('minifier-js');
  api.mainModule('minifier-tests.js', 'server');
});

Revert "Revert "Remove babel-compiler dependency in minifier-js""


if (self.importScripts) {
    importScripts('/resources/testharness.js');
    importScripts('worker-helpers.js');
}

async_test(function(test) {
    if (Notification.permission != 'granted') {
        assert_unreached('No permission has been granted for displaying notifications.');
        return;
    }

    var notification = new Notification('My Notification', { tag: 'notification-test' });
    notification.addEventListener('show', function() {
        var updatedNotification = new Notification('Second Notification', { tag: 'notification-test' });
        updatedNotification.addEventListener('show', function() {
            test.done();
        });
    });

    // FIXME: Replacing a notification should fire the close event on the
    // notification that's being replaced.

    notification.addEventListener('error', function() {
        assert_unreached('The error event should not be thrown.');
    });

}, 'Replacing a notification will discard the previous notification.');

if (isDedicatedOrSharedWorker())
    done();

if (self.importScripts) {
    importScripts('/resources/testharness.js');
    importScripts('worker-helpers.js');
}

async_test(function(test) {
    if (Notification.permission != 'granted') {
        assert_unreached('No permission has been granted for displaying notifications.');
        return;
    }

    // We require two asynchronous events to happen when a notification gets updated, (1)
    // the old instance should receive the "close" event, and (2) the new notification
    // should receive the "show" event, but only after (1) has happened.
    var closedOriginalNotification = false;

    var notification = new Notification('My Notification', { tag: 'notification-test' });
    notification.addEventListener('show', function() {
        var updatedNotification = new Notification('Second Notification', { tag: 'notification-test' });
        updatedNotification.addEventListener('show', function() {
            assert_true(closedOriginalNotification);
            test.done();
        });
    });

    notification.addEventListener('close', function() {
        closedOriginalNotification = true;
    });

    notification.addEventListener('error', function() {
        assert_unreached('The error event should not be thrown.');
    });

}, 'Replacing a notification will discard the previous notification.');

if (isDedicatedOrSharedWorker())
    done();

Verify in a layout test that replacing a notification closes the old one.


// ==UserScript==
// @name        Bring Stars Back (Netflix)
// @namespace   theinternetftw.com
// @include     https://www.netflix.com/
// @include     https://www.netflix.com/browse/*
// @include     https://www.netflix.com/title/*
// @version     1.0.4
// @grant       GM_xmlhttpRequest
// @grant       GM_setValue
// @grant       GM_getValue
// ==/UserScript==

function loadOptions(onLoad) {
  return false; // edit bsbOptions by hand in the greasemonkey script.
}

function remoteGet(url, onLoad) {
  GM_xmlhttpRequest({
    url: url,
    method: 'GET',
    onload: function(resp) {
      if (resp.status != 200) {
        console.log('[bsb] bad status ' + resp.status + ' when loading ' + url);
        onLoad(new DOMParser().parseFromString('', 'text/html'));
      } else {
        onLoad(resp.responseXML || new DOMParser().parseFromString(resp.responseText, 'text/html'));
      }
    },
  });
}

function loadRatingsCache(onLoad) {
  var cacheJSON = GM_getValue('bsbRatingsCache');
  onLoad(cacheJSON ? JSON.parse(cacheJSON) : {});
}
function saveRatingsCache(cache) {
  GM_setValue('bsbRatingsCache', JSON.stringify(cache));
}

// ==UserScript==
// @name        Bring Stars Back (Netflix)
// @namespace   theinternetftw.com
// @include     https://www.netflix.com/
// @include     https://www.netflix.com/browse
// @include     https://www.netflix.com/browse/*
// @include     https://www.netflix.com/title/*
// @version     1.0.4
// @grant       GM_xmlhttpRequest
// @grant       GM_setValue
// @grant       GM_getValue
// ==/UserScript==

function loadOptions(onLoad) {
  return false; // edit bsbOptions by hand in the greasemonkey script.
}

function remoteGet(url, onLoad) {
  GM_xmlhttpRequest({
    url: url,
    method: 'GET',
    onload: function(resp) {
      if (resp.status != 200) {
        console.log('[bsb] bad status ' + resp.status + ' when loading ' + url);
        onLoad(new DOMParser().parseFromString('', 'text/html'));
      } else {
        onLoad(resp.responseXML || new DOMParser().parseFromString(resp.responseText, 'text/html'));
      }
    },
  });
}

function loadRatingsCache(onLoad) {
  var cacheJSON = GM_getValue('bsbRatingsCache');
  onLoad(cacheJSON ? JSON.parse(cacheJSON) : {});
}
function saveRatingsCache(cache) {
  GM_setValue('bsbRatingsCache', JSON.stringify(cache));
}

Handle greasemonkey matching differently than ext


var gulp = require('gulp');
var bs = require('browser-sync').create();
var nodemon = require('gulp-nodemon');

// TODO
// Set up a seperate server for the view layer and have server.js as
// a pure service layer that connects to the RethinkDB driver.
// The view layer will take advantage of Browser Sync's awesomeness
// Possibly use nodemon or pm2 to run the service layer

gulp.task('default', ['server', 'browser-sync'], function() {
});

gulp.task('server', function() {
  nodemon({
    script: 'server.js',
    ext: 'js'
  });
})

gulp.task('browser-sync', function() {
  bs.init({
    proxy: "http://localhost:1337"
  });
});

var gulp = require('gulp');
var bs = require('browser-sync').create();
var nodemon = require('gulp-nodemon');

// TODO
// Set up a seperate server for the view layer and have server.js as
// a pure service layer that connects to the RethinkDB driver.
// The view layer will take advantage of Browser Sync's awesomeness
// Possibly use nodemon or pm2 to run the service layer

gulp.task('default', ['server', 'browser-sync'], function() {
});

gulp.task('server', function() {
  nodemon({
    script: 'server.js',
    ext: 'js'
  });
})

gulp.task('browser-sync', function() {
  bs.init({
    server: {
      baseDir: 'app/views',
      index: 'layout.html'
    }
  });
});

Update browser-sync task to use the view directory


'use strict'

const jsonPointer = require('../lib')
const expect = require('chai').expect

it('dereferences root document', function () {
  const doc = {
    name: {
      firstName: 'Joe',
      secondName: 'Smith'
    }
  }
  const pointer = ''

  const result = jsonPointer.get(doc, pointer)

  expect(result).to.deep.equal(doc)
})

it('dereferences first level node', function () {
  const doc = {
    name: {
      firstName: 'Joe',
      secondName: 'Smith'
    }
  }
  const pointer = 'name'

  const result = jsonPointer.get(doc, pointer)

  expect(result).to.deep.equal(doc.name)
})

it('dereferences nested node', function () {
  const doc = {
    person: {
      name: {
        firstName: 'Joe',
        secondName: 'Smith'
      }
    }
  }
  const pointer = 'person/name/firstName'

  const result = jsonPointer.get(doc, pointer)

  expect(result).to.deep.equal(doc.person.name.firstName)
})

'use strict'

const jsonPointer = require('../lib')
const expect = require('chai').expect

const testDoc = {
  foo: ['bar', 'baz'],
  person: { name: { firstName: 'bob' } },
  '': 0,
  'a/b': 1,
  'c%d': 2,
  'e^f': 3,
  'g|h': 4,
  'i\\j': 5,
  'k\"l': 6,
  ' ': 7,
  'm~n': 8
}

it('dereferences root document', function () {
  const pointer = ''

  const result = jsonPointer.get(testDoc, pointer)

  expect(result).to.deep.equal(testDoc)
})

it('dereferences first level node', function () {
  const pointer = '/foo'

  const result = jsonPointer.get(testDoc, pointer)

  expect(result).to.deep.equal(['bar', 'baz'])
})

it('dereferences nested node', function () {
  const pointer = 'person/name/firstName'

  const result = jsonPointer.get(testDoc, pointer)

  expect(result).to.deep.equal('bob')
})

it('dereferences array elements', function () {
  const pointer = '/foo/0'

  const result = jsonPointer.get(testDoc, pointer)

  expect(result).to.be.deep.equal('bar')
})

Use tests from spec (extended for nested example)


// Prep step before autotune.js can run; pulls in meal (carb) data and calls total.js

var tz = require('timezone');
var find_meals = require('oref0/lib/meal/history');
var sum = require('./total');

function generate (inputs) {

  //console.error(inputs);
  var treatments = find_meals(inputs);

  var opts = {
    treatments: treatments
  , profile: inputs.profile
  , pumphistory: inputs.history
  , glucose: inputs.glucose
  , prepped_glucose: inputs.prepped_glucose
  , basalprofile: inputs.profile.basalprofile
  };

  var autotune_prep_output = sum(opts);
  return autotune_prep_output;
}

exports = module.exports = generate;

// Prep step before autotune.js can run; pulls in meal (carb) data and calls total.js

var tz = require('timezone');
var find_meals = require('oref0/lib/meal/history');
var sum = require('./categorize');

function generate (inputs) {

  //console.error(inputs);
  var treatments = find_meals(inputs);

  var opts = {
    treatments: treatments
  , profile: inputs.profile
  , pumphistory: inputs.history
  , glucose: inputs.glucose
  , prepped_glucose: inputs.prepped_glucose
  , basalprofile: inputs.profile.basalprofile
  };

  var autotune_prep_output = sum(opts);
  return autotune_prep_output;
}

exports = module.exports = generate;

Update reference to now categorize.js


BasicStrategy = require('passport-http').BasicStrategy;
var gateway = require(__dirname + '/../../');
var passport = require('passport');

var passportAuth = {};

passportAuth.adminBasic = new BasicStrategy(
  function(username, password, done) {
    var domain = gateway.config.get('DOMAIN');
    if (username == ('admin@'+domain) && password == gateway.config.get('KEY')) {
      return done(null, { admin: true });
    } else {
      return done(null, false);
    }
  }
);
passportAuth.adminBasic.name = 'adminBasic';

passportAuth.userBasic = new BasicStrategy(
  function(username, password, done) {
    gateway.data.users.read({ name: username }, function (err, user) {
      console.log(user);
      if (err) { return done(err); }
      if (!user) { return done(null, false); }
      if (user) {
        var verified = gateway.data.users.verifyPassword(password, user.salt, user.password_hash);
        if (verified) {
          return done(null, user);
        } else {
          return done(null, null);
        }
      }
      return done(null, user);

    });

  }
);
passportAuth.userBasic.name = 'userBasic';

module.exports = passportAuth;

BasicStrategy = require('passport-http').BasicStrategy;
var gateway = require(__dirname + '/../../');
var passport = require('passport');

module.exports.adminBasic = (function(name){

  var adminBasic = new BasicStrategy(
    function(username, password, done) {
      var domain = gateway.config.get('DOMAIN');
      if (username == ('admin@'+domain) && password == gateway.config.get('KEY')) {
        return done(null, { admin: true });
      } else {
        return done(null, false);
      }
    }
  );
  adminBasic.name = name;
  return adminBasic;

})('adminBasic');

module.exports.userBasic = (function(name){

  var userBasic = new BasicStrategy(
    function(username, password, done) {
      if (username == ('admin@'+domain) && password == gateway.config.get('KEY')) {
        return done(null, { admin: true });
      }
      gateway.data.users.read({ name: username }, function (err, user) {
        console.log(user);
        if (err) { return done(err); }
        if (!user) { return done(null, false); }
        if (user) {
          var verified = gateway.data.users.verifyPassword(password, user.salt, user.password_hash);
          if (verified) {
            return done(null, user);
          } else {
            return done(null, null);
          }
        }
        return done(null, user);

      });

    }
  );
  userBasic.name = name;
  return userBasic;

})('userBasic');

Enable admin to access user routes.


import React from 'react'
import PropTypes from 'prop-types'
import capitalize from 'lodash/capitalize'

import {ListItem, CHECKED, UNCHECKED} from '@opentrons/components'

InstrumentListItem.propTypes = {
  isRunning: PropTypes.bool.isRequired,
  name: PropTypes.string,
  axis: PropTypes.string,
  volume: PropTypes.number,
  channels: PropTypes.number,
  probed: PropTypes.bool,
  clearLabwareReviewed: PropTypes.func
}

export default function InstrumentListItem (props) {
  const {isRunning, name, axis, volume, channels, probed, clearLabwareReviewed} = props
  const isDisabled = name == null
  const url = isRunning
  ? '#'
  : `/setup-instruments/${axis}`

  const confirmed = probed
  const iconName = confirmed
    ? CHECKED
    : UNCHECKED

  const description = !isDisabled
    ? `${capitalize(channels)}-channel`
    : 'N/A'

  const units = !isDisabled ? 'ul' : null
  return (
    <ListItem
      isDisabled={isDisabled || isRunning}
      url={url}
      onClick={!isRunning && clearLabwareReviewed}
      confirmed={confirmed}
      iconName={iconName}
    >
      {axis}
      {description}
      {volume} {units}
    </ListItem>
  )
}

import React from 'react'
import PropTypes from 'prop-types'
import capitalize from 'lodash/capitalize'

import {ListItem, CHECKED, UNCHECKED} from '@opentrons/components'

InstrumentListItem.propTypes = {
  isRunning: PropTypes.bool.isRequired,
  name: PropTypes.string,
  axis: PropTypes.string,
  volume: PropTypes.number,
  channels: PropTypes.number,
  probed: PropTypes.bool,
  clearLabwareReviewed: PropTypes.func
}

export default function InstrumentListItem (props) {
  const {isRunning, name, axis, volume, channels, probed, clearLabwareReviewed} = props
  const isDisabled = name == null
  const url = isRunning
  ? '#'
  : `/setup-instruments/${axis}`
  // TODO (ka 2018-1-17): Move this up to container mergeProps in upcoming update setup panel ticket
  const confirmed = probed
  const iconName = confirmed
    ? CHECKED
    : UNCHECKED

  const pipetteType = channels === 8
    ? 'multi'
    : 'single'

  const description = !isDisabled
    ? `${capitalize(pipetteType)}-channel`
    : 'N/A'

  const units = !isDisabled ? 'ul' : null
  return (
    <ListItem
      isDisabled={isDisabled || isRunning}
      url={url}
      onClick={!isRunning && clearLabwareReviewed}
      confirmed={confirmed}
      iconName={iconName}
    >
      {capitalize(axis)}
      {description}
      {volume} {units}
    </ListItem>
  )
}

Fix channel type rendering in setup panel


var ready = function(fn) {
    if (document.readyState != 'loading') {
        fn();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', fn);
    } else {
        document.attachEvent('onreadystatechange', function() {
        if (document.readyState != 'loading')
            fn();
        });
    }
}

ready(function() {
    LazyLoad.css('https://fonts.googleapis.com/css?family=Raleway:400,700');

    LazyLoad.js('https://cdnjs.cloudflare.com/ajax/libs/blazy/1.6.2/blazy.min.js', function() {
        new Blazy({
            offset: 500,
        });
    });

    LazyLoad.css('/dist/extended.css');

    LazyLoad.js('https://cdnjs.cloudflare.com/ajax/libs/feature.js/1.0.1/feature.min.js', function() {
        if (feature.cssTransform && feature.cssTransition && feature.viewportUnit) {
            LazyLoad.css('/dist/full.css');
        }
    });
});

var ready = function(fn) {
    if (document.readyState != 'loading') {
        fn();
    } else if (document.addEventListener) {
        document.addEventListener('DOMContentLoaded', fn);
    } else {
        document.attachEvent('onreadystatechange', function() {
        if (document.readyState != 'loading')
            fn();
        });
    }
}

ready(function() {
    LazyLoad.css('https://fonts.googleapis.com/css?family=Raleway:400,700');

    LazyLoad.js('https://cdnjs.cloudflare.com/ajax/libs/blazy/1.6.2/blazy.min.js', function() {
        new Blazy({
            offset: 500,
        });
    });

    LazyLoad.css('dist/extended.css');

    LazyLoad.js('https://cdnjs.cloudflare.com/ajax/libs/feature.js/1.0.1/feature.min.js', function() {
        if (feature.cssTransform && feature.cssTransition && feature.viewportUnit) {
            LazyLoad.css('dist/full.css');
        }
    });
});

Remove slash from asset paths.


class MCWorkflowProcessTemplatesComponentController {
    /*@ngInit*/
    constructor(templates) {
        this.templates = templates.get();
        this.templateTypes = [
            {
                title: 'CREATE SAMPLES',
                cssClass: 'mc-create-samples-color',
                icon: 'fa-cubes',
                margin: true,
                templates: this.templates.filter(t => t.process_type === 'create' && t.name === 'Create Samples')
            },
            {
                title: 'TRANSFORMATION',
                cssClass: 'mc-transform-color',
                icon: 'fa-exclamation-triangle',
                templates: this.templates.filter(t => t.process_type === 'transform' && t.name !== 'Create Samples')
            },
            {
                title: 'MEASUREMENT',
                cssClass: 'mc-measurement-color',
                icon: 'fa-circle',
                templates: this.templates.filter(t => t.process_type === 'measurement')
            },
            {
                title: 'ANALYSIS',
                cssClass: 'mc-analysis-color',
                icon: 'fa-square',
                templates: this.templates.filter(t => t.process_type === 'analysis')
            }
        ];
    }

    chooseTemplate(t) {
        if (this.onSelected) {
            this.onSelected({templateId: t.name, processId: ''});
        }
    }
}

angular.module('materialscommons').component('mcWorkflowProcessTemplates', {
    templateUrl: 'app/project/experiments/experiment/components/processes/mc-workflow-process-templates.html',
    controller: MCWorkflowProcessTemplatesComponentController,
    bindings: {
        onSelected: '&'
    }
});

class MCWorkflowProcessTemplatesComponentController {
    /*@ngInit*/
    constructor(templates) {
        this.templates = templates.get();
        this.templateTypes = [
            {
                title: 'CREATE SAMPLES',
                cssClass: 'mc-create-samples-color',
                icon: 'fa-cubes',
                margin: true,
                templates: this.templates.filter(t => t.process_type === 'create')
            },
            {
                title: 'TRANSFORMATION',
                cssClass: 'mc-transform-color',
                icon: 'fa-exclamation-triangle',
                templates: this.templates.filter(t => t.process_type === 'transform')
            },
            {
                title: 'MEASUREMENT',
                cssClass: 'mc-measurement-color',
                icon: 'fa-circle',
                templates: this.templates.filter(t => t.process_type === 'measurement')
            },
            {
                title: 'ANALYSIS',
                cssClass: 'mc-analysis-color',
                icon: 'fa-square',
                templates: this.templates.filter(t => t.process_type === 'analysis')
            }
        ];
    }

    chooseTemplate(t) {
        if (this.onSelected) {
            this.onSelected({templateId: t.name, processId: ''});
        }
    }
}

angular.module('materialscommons').component('mcWorkflowProcessTemplates', {
    templateUrl: 'app/project/experiments/experiment/components/processes/mc-workflow-process-templates.html',
    controller: MCWorkflowProcessTemplatesComponentController,
    bindings: {
        onSelected: '&'
    }
});

Modify filter to show new computational sample templates.


/**
 * Created by chengfulin on 2015/4/24.
 */
require('core-js/es6/weak-map');
module.exports = Namespace;

var map = new WeakMap();
function Namespace() {
    return function (obj) {
        if (!map.has(obj)) {
            map.set(obj, {});
        }
        return map.get(obj);
    };
}

/**
 * Created by chengfulin on 2015/4/24.
 */
var WeakMap = require('core-js/es6/weak-map');
module.exports = Namespace;

var map = new WeakMap();
function Namespace() {
    'use strict';
    return function (obj) {
        if (!map.has(obj)) {
            map.set(obj, {});
        }
        return map.get(obj);
    };
}

Fix issue about unknown identifier


import stencilUtils from 'bigcommerce/stencil-utils'
import account from './theme/account';
import auth from './theme/auth';
import blog from './theme/blog';
import brand from './theme/brand';
import brands from './theme/brands';
import cart from './theme/cart';
import category from './theme/category';
import compare from './theme/compare'
import errors from './theme/errors';
import giftCertificate from './theme/gift-certificate';
import home from './theme/home';
import orderComplete from './theme/order-complete';
import page from './theme/page';
import product from './theme/product';
import search from './theme/search';
import sitemap from './theme/sitemap';
import subscribe from './theme/subscribe';
import wishlist from './theme/wishlist';

stencilUtils.events.init();

var modules = {
    "account": account,
    "auth": auth,
    "blog": blog,
    "brand": brand,
    "brands": brand,
    "cart": cart,
    "category": category,
    "compare": compare,
    "errors": errors,
    "gift-certificate": giftCertificate,
    "home": home,
    "order-complete": orderComplete,
    "page": page,
    "product": product,
    "search": search,
    "sitemap": sitemap,
    "subscribe": subscribe,
    "wishlist": wishlist
};

export {modules};

import stencilUtils from 'bigcommerce/stencil-utils'
import account from './theme/account';
import auth from './theme/auth';
import blog from './theme/blog';
import brand from './theme/brand';
import brands from './theme/brands';
import cart from './theme/cart';
import category from './theme/category';
import compare from './theme/compare'
import errors from './theme/errors';
import giftCertificate from './theme/gift-certificate';
import home from './theme/home';
import orderComplete from './theme/order-complete';
import page from './theme/page';
import product from './theme/product';
import search from './theme/search';
import sitemap from './theme/sitemap';
import subscribe from './theme/subscribe';
import wishlist from './theme/wishlist';

var modules = {
    "account": account,
    "auth": auth,
    "blog": blog,
    "brand": brand,
    "brands": brand,
    "cart": cart,
    "category": category,
    "compare": compare,
    "errors": errors,
    "gift-certificate": giftCertificate,
    "home": home,
    "order-complete": orderComplete,
    "page": page,
    "product": product,
    "search": search,
    "sitemap": sitemap,
    "subscribe": subscribe,
    "wishlist": wishlist
};

export {modules};

Remove init because import does the init already and init function isn't exposed


import React from 'react'

import styles from './PreviewTools.styl'

export default ({ href, layout, theme, onLayoutChanged, onThemeChanged }) =>

      Layout:
      <select value={layout} onChange={onLayoutChanged}>
        <option value="blog">Blog</option>
        <option value="centered">Centered</option>
      </select>

      Theme:
      <select value={theme} onChange={onThemeChanged}>
        <option value="idyll">Idyll</option>
        <option value="github">GitHub</option>
      </select>

      Open in New Window

import React from 'react'

import styles from './PreviewTools.styl'

export default ({ href, layout, theme, onLayoutChanged, onThemeChanged }) =>

      Layout:
      <select value={layout} onChange={onLayoutChanged}>
        <option value="none">None</option>
        <option value="blog">Blog</option>
        <option value="centered">Centered</option>
      </select>

      Theme:
      <select value={theme} onChange={onThemeChanged}>
        <option value="none">None</option>
        <option value="idyll">Idyll</option>
        <option value="github">GitHub</option>
      </select>

      Open in New Window

Allow layout and theme opt-out


"use strict";

var QAService = require("../services/QAService");
var notFound = require("../notFound");

module.exports = [{
  method: "GET",
  path: "/{qaid}",
  handler: function hander(request, reply) {
    QAService.getQaidById(request.params.qaid, function getData(error, data) {
      if (error || !data || !data.questions) {
        return notFound(reply);
      }

      return reply({
        questions: data.questions
      });
    });
  },
  config: {
    plugins: {
      hal: {
        prepare: function prepare(rep, next) {
          rep.entity.questions.forEach(function addEachQaid(item) {
            var link;

            link = rep.link("hack:questions", "/" + item._id);
            link.name = item.question;
          });
          rep.ignore("questions");
          next();
        }
      }
    }
  }
},
{
  method: "PUT",
  path: "/{qaid}",
  handler: function (request, reply) {
    reply("Create a QAID");
  }
},
{
  method: "POST",
  path: "/{qaid}",
  handler: function (request, reply) {
    reply("Add a question to this QAID");
  }
}];

"use strict";

var QAService = require("../services/QAService");
var notFound = require("../notFound");

module.exports = [{
  method: "GET",
  path: "/{qaid}",
  handler: function hander(request, reply) {
    QAService.getQaidById(request.params.qaid, function getData(error, data) {
      if (error || !data || !data.questions) {
        return notFound(reply);
      }

      return reply({
        questions: data.questions
      });
    });
  },
  config: {
    plugins: {
      hal: {
        prepare: function prepare(rep, next) {
          rep.entity.questions.forEach(function addEachQaid(item) {
            var link;

            link = rep.link("hack:questions", "/" + rep.request.params.qaid + "/" + item._id);
            link.name = item.question;
          });
          rep.ignore("questions");
          next();
        }
      }
    }
  }
},
{
  method: "PUT",
  path: "/{qaid}",
  handler: function (request, reply) {
    reply("Create a QAID");
  }
},
{
  method: "POST",
  path: "/{qaid}",
  handler: function (request, reply) {
    reply("Add a question to this QAID");
  }
}];

Fix URL of question link


/*
Let's import all our files here.
*/

// general business logic of this customization
import "./callbacks.js";
import "./emails.js";
import "./custom_fields.js";
import "./i18n.js";
import "./groups.js";
import "./fragments.js";

// custom components
import "./components/CustomLogo.jsx";
import "./components/CustomNewsletter.jsx";
import "./components/CustomPostsItem.jsx";
import "./components/MyCustomPage.jsx";

// custom routes
import "./routes.jsx";

Accounts.ui.config({
  passwordSignupFields: 'EMAIL_ONLY',
  // requireEmailVerification: true,
});

Set signup/login to email only