define(['backbone.marionette', 'underscore'],
  function(Marionette, _) {

    return Marionette.LayoutView.extend( {

      template: _.template(
        "

" +
        "

"),

      regions: {
        container: "#detail-container",
        footer: "#detail-footer"
      }

    });

  });

Remove z-depth from detail subregions.


'use strict'
const passport = require('../../utils/passportService')
const router = require('express').Router()
const secretController = require('./secretController')
router.get('/', passport.authenticate('jwt', { session: false }), secretController)

module.exports = router

'use strict'
const passport = require('../../utils/passportService')
const router = require('express').Router()
const secretController = require('./secretController')
const { authenticate } = require('../../config/middleware')

router.get('/', authenticate, secretController)

module.exports = router

Use the middleware to authenticate in place of passport


const mongoose = require('mongoose')

const userSchema = new mongoose.Schema({
  id: { type: String, index: { unique: true } },
  twitter_id: String,
  twitter_credentials: mongoose.Schema.Types.Mixed,
  auth0_id: String,
  login_tokens: [ String ],
  profile_image_url: String,
  data: mongoose.Schema.Types.Mixed,
  created_at: Date,
  updated_at: Date,
  last_street_id: Number
})

userSchema.pre('save', function (next) {
  let now = new Date()
  this.updated_at = now
  this.created_at = this.created_at || now
  next()
})

userSchema.methods.asJson = function (options, cb) {
  options = options || {}

  let json = {
    id: this.id
  }

  if (options.auth) {
    json.data = this.data
    json.createdAt = this.created_at
    json.updatedAt = this.updated_at
  }

  cb(null, json)
}
module.exports = mongoose.model('User', userSchema)

const mongoose = require('mongoose')

const userSchema = new mongoose.Schema({
  id: { type: String, index: { unique: true } },
  twitter_id: String,
  twitter_credentials: mongoose.Schema.Types.Mixed,
  auth0_id: String,
  login_tokens: [ String ],
  profile_image_url: String,
  data: mongoose.Schema.Types.Mixed,
  created_at: Date,
  updated_at: Date,
  last_street_id: Number
})

userSchema.pre('save', function (next) {
  const now = new Date()
  this.updated_at = now
  this.created_at = this.created_at || now
  next()
})

userSchema.methods.asJson = function (options, cb) {
  options = options || {}

  let json = {
    id: this.id
  }

  if (options.auth) {
    json.data = this.data
    json.createdAt = this.created_at
    json.updatedAt = this.updated_at
  }

  cb(null, json)
}
module.exports = mongoose.model('User', userSchema)

Update constant varriables to using const


// Main Module for searchthedocs demo
define(function (require) {
  var _ = require('underscore'),
    $ = require('jquery'),
    SearchTheDocsView = require('searchthedocs/src/searchthedocs');

  var searchthedocs_main = function() {

    var search_options = {
      default_endpoint: 'sections',
      endpoints: {
        sections: {
          data_type: 'json',
          //default_params: {format: 'jsonp'},
          api_url: 'http://searchtd.dev:8000/api/v2/search/section/',
          record_url:
            'http://{{domain}}.readthedocs.org/en/'
            + '{{version}}/{{path}}.html#{{page_id}}',
          param_map: {
            search: 'q',
            domain: 'project'
          },
          result_format: {
            records_path: 'results.hits.hits',
            record_format: {
              // Fields used in sidebar display
              domain: 'fields.project',
              title: 'fields.title',
              // Fields used to build record_url
              version: 'fields.version',
              path: 'fields.path',
              page_id: 'fields.page_id'
            }
          },
      }
    }
  };

    window.searchtd = new SearchTheDocsView({
      brand: 'searchthedocs',
      brand_href: '#',
      search_options: search_options
    });

   $('#searchthedocs-container').append(searchtd.render().el);

  };

  return searchthedocs_main;

});

// Main Module for searchthedocs demo
define(function (require) {
  var _ = require('underscore'),
    $ = require('jquery'),
    SearchTheDocsView = require('searchthedocs/src/searchthedocs');

  var searchthedocs_main = function() {

    var search_options = {
      default_endpoint: 'sections',
      endpoints: {
        sections: {
          data_type: 'jsonp',
          default_params: {format: 'jsonp'},
          api_url: 'http://readthedocs.org/api/v2/search/section/',
          content_url_format:
            'http://{{domain}}.readthedocs.org/en/'
            + '{{version}}/{{path}}.html#{{page_id}}',
          param_map: {
            search: 'q',
            domain: 'project'
          },
          result_format: {
            records_path: 'results.hits.hits',
            record_format: {
              // Fields used in sidebar display
              domain: 'fields.project',
              title: 'fields.title',
              // Fields used to build record_url
              version: 'fields.version',
              path: 'fields.path',
              page_id: 'fields.page_id'
            }
          },
      }
    }
  };

    window.searchtd = new SearchTheDocsView({
      brand: 'searchthedocs',
      brand_href: '#',
      search_options: search_options
    });

   $('#searchthedocs-container').append(searchtd.render().el);

  };

  return searchthedocs_main;

});

Use real readthedocs API again


const path = require('path')

module.exports = ({ actions }) => {
  actions.setWebpackConfig({
    resolve: {
      alias: {
        '@components': path.resolve(__dirname, '../../components/'),
        '@icons': path.resolve(__dirname, '../../icons/'),
        '@styles': path.resolve(__dirname, '../../styles/'),
        '@utils': path.resolve(__dirname, '../../utils/'),
        '@types': path.resolve(__dirname, '../../types/'),
        '@assets': path.resolve(__dirname, '../../assets/'),
        '@sections': path.resolve(__dirname, '../../sections/'),
      },
      extensions: ['.js', '.json', '.ts', '.tsx'],
    },
  })
}

const path = require('path')

module.exports = ({ actions }) => {
  actions.setWebpackConfig({
    devtool: process.env.NODE_ENV !== 'production',
    resolve: {
      alias: {
        '@components': path.resolve(__dirname, '../../components/'),
        '@icons': path.resolve(__dirname, '../../icons/'),
        '@styles': path.resolve(__dirname, '../../styles/'),
        '@utils': path.resolve(__dirname, '../../utils/'),
        '@types': path.resolve(__dirname, '../../types/'),
        '@assets': path.resolve(__dirname, '../../assets/'),
        '@sections': path.resolve(__dirname, '../../sections/'),
      },
      extensions: ['.js', '.json', '.ts', '.tsx'],
    },
  })
}

Set webpack devtool to false in production


angular.module('OpenMining', ['ngRoute'])
.value('API_URL', '/process.json?')

.controller('Process',
  function($scope, $http, $location, API_URL) {
    for (var key in $location.search()){
      API_URL += key + "=" + $location.search()[key] + "&";
    }
    console.log(API_URL)
    $scope.loading = true;
    $http({method: 'POST', url: API_URL}).
      success(function(data, status, headers, config) {
        console.log(data)
        $scope.process = data.json;
        $scope.columns = data.columns;
        $scope.predicate = "-id_cliente";
        $scope.loading = false;
      });
});

angular.module('OpenMining', [])
.value('API_URL', '/process.json?')

.controller('Process',
  function($scope, $http, $location, API_URL) {
    for (var key in $location.search()){
      API_URL += key + "=" + $location.search()[key] + "&";
    }
    console.log(API_URL)
    $scope.loading = true;
    $http({method: 'POST', url: API_URL}).
      success(function(data, status, headers, config) {
        console.log(data)
        $scope.process = data.json;
        $scope.columns = data.columns;
        $scope.predicate = "-id_cliente";
        $scope.loading = false;
      });
});

Remove pendence ngRoute on OpenMining module


const SecretsManager = require("./secretsmanager");

class Secrets {
    constructor(options) {
        this.options = options;
        if(!options.isDev) {
           if(!options.region || !options.secretName) {
              throw new Error("Need both region and secretName in options");
           }
           this.manager = new SecretsManager(this.options.region);
        }
    }

    async googleKey() {
        if(this.options.isDev) {
            return this.options.googleKey;
        }
        return this.getSecretsKey("GOOGLE_KEY_VALUE");
    }

    async recaptchaPrivateKey() {
        if(this.options.isDev) {
            return this.options.recaptchaPrivateKey;
        }
        return this.getSecretsKey("RECAPTCHA_PRIVATE_KEY");
    }

    async getSecretsKey(name) {
        let secrets = await this.manager.getSecretValue(this.config.secretName);
        return secrets[name];
    }
}

module.exports = Secrets;

const SecretsManager = require("./secretsmanager");

class Secrets {
    constructor(options) {
        this.options = options;
        if(!options.isDev) {
           if(!options.region || !options.secretName) {
              throw new Error("Need both region and secretName in options");
           }
           this.manager = new SecretsManager(this.options.region);
        }
    }

    async googleKey() {
        if(this.options.isDev) {
            return this.options.googleKey;
        }
        return this.getSecretsKey("GOOGLE_KEY_VALUE");
    }

    async recaptchaPrivateKey() {
        if(this.options.isDev) {
            return this.options.recaptchaPrivateKey;
        }
        return this.getSecretsKey("RECAPTCHA_PRIVATE_KEY");
    }

    async getSecretsKey(name) {
        let secrets = await this.manager.getSecretValue(name);
        return secrets[name];
    }
}

module.exports = Secrets;

Fix secretName error while getting secret


#!/usr/bin/gjs
// Runs a task in a separate process.

const path = /^.*?@(.*):/.exec(new Error().stack)[1];
const dirname = imports.gi.Gio.File.new_for_path(path).get_parent().get_parent().get_path();
imports.searchPath.push(dirname);
new imports.src.app.Gjs.Require.Require().require();
new imports.src.app.Gjs.GtkDom.GtkDom().require();

const { Worker } = require("../src/app/Gio/Worker");
const worker = new Worker(JSON.parse(ARGV[0]), (action) => {
  print(JSON.stringify(action));
});
worker.run();

#!/usr/bin/gjs
// Runs a task in a separate process.

const path = /^.*?@(.*):/.exec(new Error().stack)[1];
const modules = imports.gi.Gio.File.new_for_path(path).get_parent().get_parent().get_parent().get_path();
imports.searchPath.push(modules);
const dirname = imports.gi.Gio.File.new_for_path(path).get_parent().get_parent().get_path();
imports.searchPath.push(dirname);
new imports.src.app.Gjs.Require.Require().require();
new imports.src.app.Gjs.GtkDom.GtkDom().require();

const { Worker } = require("../src/app/Gio/Worker");
const worker = new Worker(JSON.parse(ARGV[0]), (action) => {
  print(JSON.stringify(action));
});
worker.run();

Fix run from global install


const staticModule = require('static-module')
const through      = require('through2')
const glslify      = require('glslify')
const nodeResolve  = require('resolve')
const path         = require('path')

module.exports = glslifyPromiseTransform

function glslifyPromiseTransform(filename, opts) {
  if (path.extname(filename) === '.json') return through()

  const transformer = staticModule({
    'glslify-promise': glslifyReplace
  }, {
    vars: {
      __dirname: path.dirname(filename),
      __filename: filename,
      require: {
        resolve: nodeResolve
      }
    }
  })

  return transformer

  function glslifyReplace(glslFile, opts) {
    const origin = './' + path.relative(path.dirname(filename), __dirname)
    const stream = through()

    opts = opts || {}
    opts.basedir = opts.basedir || path.dirname(filename)

    glslify.bundle(glslFile, opts, function(err, source) {
      if (err) return transformer.emit('error', err)

      stream.push('require("'+origin+'/wrapper")(')
      stream.push(JSON.stringify(source))
      stream.push(')')
      stream.push(null)

    }).on('file', function(file) {
      transformer.emit('file', file)
    })

    return stream
  }
}

const staticModule = require('static-module')
const through      = require('through2')
const glslify      = require('glslify')
const nodeResolve  = require('resolve')
const path         = require('path')

module.exports = glslifyPromiseTransform

function glslifyPromiseTransform(filename, opts) {
  if (path.extname(filename) === '.json') return through()

  const transformer = staticModule({
    'glslify-promise': glslifyReplace
  }, {
    vars: {
      __dirname: path.dirname(filename),
      __filename: filename,
      require: {
        resolve: nodeResolve
      }
    }
  })

  return transformer

  function glslifyReplace(glslFile, opts) {
    const origin = require.resolve('./wrapper')
    const stream = through()

    opts = opts || {}
    opts.basedir = opts.basedir || path.dirname(filename)

    glslify.bundle(glslFile, opts, function(err, source) {
      if (err) return transformer.emit('error', err)

      stream.push('require("'+origin+'")(')
      stream.push(JSON.stringify(source))
      stream.push(')')
      stream.push(null)

    }).on('file', function(file) {
      transformer.emit('file', file)
    })

    return stream
  }
}

Use an absolute path to resolve wrapper.js


import './Tooltip.css';
import './themes/default.css';
import './animations/zoom.css';
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import RcTooltip from 'rc-tooltip';

const validPlacements = ['top', 'right', 'bottom', 'left'];

class Tooltip extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        return shallowCompare(this, nextProps, nextState);
    }

    render() {
        const { overlayClassName, theme, animation, ...props } = this.props;
        const finalOverlayClassName = theme ? `${overlayClassName} tooltip-component-theme-${theme}` : overlayClassName;
        const finalAnimation = animation ? `animation-${animation}` : animation;

        if (props.placement && validPlacements.indexOf(props.placement) === -1) {
            throw new Error(`Invalid placement: ${props.placement}`);
        }

        return (
            <RcTooltip
                prefixCls="tooltip-component"
                overlayClassName={ finalOverlayClassName }
                animation={ finalAnimation }
                { ...props }>
                { this.props.children }
            </RcTooltip>

        );
    }
}

Tooltip.defaultProps = {
    animation: 'zoom',
    theme: 'default',
    mouseLeaveDelay: 0.1,
};

Tooltip.propTypes = {
    ...RcTooltip.propTypes,
    theme: PropTypes.string,
};

export default Tooltip;

import './Tooltip.css';
import './themes/default.css';
import './animations/zoom.css';
import React, { Component, PropTypes } from 'react';
import shallowCompare from 'react-addons-shallow-compare';
import RcTooltip from 'rc-tooltip';

const validPlacements = ['top', 'right', 'bottom', 'left'];

class Tooltip extends Component {
    shouldComponentUpdate(nextProps, nextState) {
        return shallowCompare(this, nextProps, nextState);
    }

    render() {
        const { overlayClassName, theme, animation, ...props } = this.props;
        const finalOverlayClassName = theme ? `${overlayClassName} tooltip-component-theme-${theme}` : overlayClassName;
        const finalAnimation = animation ? `animation-${animation}` : animation;

        if (props.placement && validPlacements.indexOf(props.placement) === -1) {
            throw new Error(`Invalid placement: ${props.placement}`);
        }

        return (
            <RcTooltip
                prefixCls="tooltip-component"
                overlayClassName={ finalOverlayClassName }
                animation={ finalAnimation }
                { ...props }>
                { this.props.children }
            </RcTooltip>

        );
    }
}

Tooltip.defaultProps = {
    animation: 'zoom',
    theme: 'default',
    mouseLeaveDelay: 0.1,
    trigger: ['hover', 'click'],
};

Tooltip.propTypes = {
    ...RcTooltip.propTypes,
    theme: PropTypes.string,
};

export default Tooltip;

Make tooltips work on mobile.


"use strict";

// Simplest way to subscribe. Start the subscription and don't listen to "error" events
// from the broker. This will cause the process to crash in case of errors.
// This of course requires a process manager such as "pm2" or "forever" in place
// to restart the process.

var init = require("exp-amqp-connection");

var amqpBehaviour = {
  url: "amqp://localhost",
  exchange: "my-excchange",
  ack: "true",
  prefetch: 10
};

var broker = init(amqpBehaviour);

broker.on("connected", function () {
  console.log("Connected to amqp server");
});

broker.on("subscribed", function (subscription) {
  console.log("Subscription started:", subscription);
});

function handleMessage(message, meta, notify) {
  console.log("Got message", message, "with routing key", meta.fields.routingKey);
  notify.ack();
}

broker.subscribe("some-routing-key", "some-queue", handleMessage);

setInterval(function () {
  broker.publish("some-routing-key", "Hello " + new Date());
}, 1000);

"use strict";

var init = require("exp-amqp-connection");

var amqpBehaviour = {
  url: "amqp://localhost",
  exchange: "my-excchange",
  ack: "true",
  prefetch: 10
};

var broker = init(amqpBehaviour);

broker.on("connected", function() {
  console.log("Connected to amqp server");
});

broker.on("subscribed", function(subscription) {
  console.log("Subscription started:", subscription);
});

// Simplest way to deal with errors: abort the process.
// Assuming of course that you have a scheduler or process manager (kubernetes,
// pm2, forever etc) in place to restart your process.
//
// NOTE: See the "subcribe-reconnect" example on how to handle errors without
// restarting the process.
broker.on("error", function(error) {
  console.error("Amqp error", error, ", aborting process.");
  process.exit(1);
});

function handleMessage(message, meta, notify) {
  console.log("Got message", message, "with routing key", meta.fields.routingKey);
  notify.ack();
}

broker.subscribe("some-routing-key", "some-queue", handleMessage);

setInterval(function() {
  broker.publish("some-routing-key", "Hello " + new Date());
}, 1000);

Update the examples to explicitly exit the process


// @see https://github.com/postcss/postcss-loader#configuration

// Standard lib.
import { join as joinPath } from 'path';

// Package modules.
import autoprefixer from 'autoprefixer';
import purgecss from '@fullhuman/postcss-purgecss';
import reporter from 'postcss-reporter';
import stylelint from 'stylelint';

// Local modules.
import { config } from './package.json';

// Constants.
const INPUT_DIRECTORY = config.input;
// const INTERMEDIATE_DIRECTORY = config.intermediate;
// const OUTPUT_DIRECTORY = config.output;
const PRODUCTION = process.env.NODE_ENV === 'production';

// Helpers.
const isTruthy = x => !!x;

// Exports.
export default {
    plugins: [
        stylelint(),
        PRODUCTION && purgecss({
            content: [ joinPath(INPUT_DIRECTORY, '**/*.njk') ],
            fontFace: true,
            keyframes: true
        }),
        autoprefixer(),
        reporter({ clearReportedMessages: true })
    ].filter(isTruthy)
};

// @see https://github.com/postcss/postcss-loader#configuration

// Standard lib.
import { join as joinPath } from 'path';

// Package modules.
import autoprefixer from 'autoprefixer';
import purgecss from '@fullhuman/postcss-purgecss';
import reporter from 'postcss-reporter';
import stylelint from 'stylelint';

// Local modules.
import { config } from './package.json';

// Constants.
const INPUT_DIRECTORY = config.input;
// const INTERMEDIATE_DIRECTORY = config.intermediate;
// const OUTPUT_DIRECTORY = config.output;
const PRODUCTION = process.env.NODE_ENV === 'production';

// @see https://www.11ty.io/docs/languages/
const ELEVENTY_TEMPLATE_LANGUAGES = [
    'html', 'md', '11ty.js', 'liquid', 'njk', 'hbs', 'mustache', 'ejs', 'haml', 'pug', 'jstl'
].join(',');

// Helpers.
const isTruthy = x => !!x;

// Exports.
export default {
    plugins: [
        stylelint(),
        PRODUCTION && purgecss({
            // Purge using templates rather than the full output.
            content: [ joinPath(INPUT_DIRECTORY, `**/*.{${ELEVENTY_TEMPLATE_LANGUAGES}}`) ],
            fontFace: true,
            keyframes: true
        }),
        autoprefixer(),
        reporter({ clearReportedMessages: true })
    ].filter(isTruthy)
};

Purge from all 11ty template languages.


/*
 * grunt-broccoli-build
 * https://github.com/ericf/grunt-broccoli-build
 *
 * Copyright 2014 Yahoo! Inc.
 * Licensed under the Yahoo! Inc. BSD license.
 */

'use strict';

module.exports = function (grunt) {
    grunt.registerMultiTask('broccoli_build', 'Runs a Broccoli build.', function () {
        var broccoli = require('broccoli'),
            ncp      = require('ncp');

        var done = this.async(),
            dest = this.data.dest;

        var tree    = broccoli.helpers.loadBrocfile(),
            builder = new broccoli.Builder(tree);

        grunt.log.write('Broccoli building to "' + dest + '"...');

        builder.build().then(function (dir) {
            if (grunt.file.isDir(dest)) {
                throw new Error('Directory "' + dest + '" already exists.');
            }

            ncp(dir, dest, function (err) {
                if (err) { throw err; }
                grunt.log.ok();
                done();
            });
        }).catch(done);
    });
};

/*
 * grunt-broccoli-build
 * https://github.com/ericf/grunt-broccoli-build
 *
 * Copyright 2014 Yahoo! Inc.
 * Licensed under the Yahoo! Inc. BSD license.
 */

'use strict';

module.exports = function (grunt) {
    grunt.registerMultiTask('broccoli_build', 'Runs a Broccoli build.', function () {
        var broccoli = require('broccoli'),
            ncp      = require('ncp');

        // Deal with differences in Broccoli versions.
        var loadBrocfile = typeof broccoli.loadBrocfile === 'function' ?
                broccoli.loadBrocfile :
                broccoli.helpers.loadBrocfile;

        var done = this.async(),
            dest = this.data.dest;

        if (typeof dest !== 'string') {
            grunt.fatal('Target must be configured with a `dest` dir path.');
        }

        var tree    = loadBrocfile(),
            builder = new broccoli.Builder(tree);

        grunt.log.write('Broccoli building to "' + dest + '"...');

        builder.build().then(function (dir) {
            if (grunt.file.isDir(dest)) {
                throw new Error('Directory "' + dest + '" already exists.');
            }

            ncp(dir, dest, function (err) {
                if (err) { throw err; }
                grunt.log.ok();
                done();
            });
        }).catch(done);
    });
};

Fix to work with Broccoli 0.4.x and thow error when `dest` is undefined


(function() {
    'use strict';

    angular
        .module('lecturer')
        .factory('lecturerFactory', lecturerFactory);

    /* @ngInject */
    function lecturerFactory(lecturerService) {
        var username = '';
        var observerCallbacks = [];
        var Login = false;

        var service = {
            login: login,
            checkUserToken: checkUserToken,
            logout: logout,
            registerObserverCallback: registerObserverCallback
        };

        return service;

        function login(credentials) {
            if (!Login) {
                Login = lecturerService.login;
            }

            var SHA256 = new Hashes.SHA256();
            SHA256.setUTF8(true);

            // Prevent binding the hashed password into the input.
            var form = {
                email: credentials.email,
                passsword: SHA256.hex(credentials.password)
            };

            Login.save(form, loginSuccess, logoutSuccess);
        }

        function checkUserToken(onError) {
            if (!Login) {
                Login = lectureService.login;
            }

            Login.get(loginSuccess, function() {
                logoutSuccess();
                onError();
            });
        }

        function logout() {
            lectureService.logout
                .save(success);

            function success() {
                logoutSuccess();
                $location.path('/');
            }
        }

        function registerObserverCallback(callback) {
            observerCallbacks.push(callback);
        }

        function loginSuccess(response) {
            angular
                .forEach(observerCallbacks, function(callback) {
                    callback(true, response.username);
                });
        }

        function logoutSuccess() {
            angular
                .forEach(observerCallbacks, function(callback) {
                    callback(false);
                });
        }
    }
})();

(function() {
    'use strict';

    angular
        .module('lecturer')
        .factory('lecturerFactory', lecturerFactory);

    /* @ngInject */
    function lecturerFactory(lecturerService, $location) {
        var username = '';
        var observerCallbacks = [];
        var Login = false;

        var service = {
            login: login,
            checkUserToken: checkUserToken,
            logout: logout,
            registerObserverCallback: registerObserverCallback
        };

        return service;

        function login(credentials) {
            if (!Login) {
                Login = lecturerService.login;
            }

            var SHA256 = new Hashes.SHA256();
            SHA256.setUTF8(true);

            // Prevent binding the hashed password into the input.
            var form = {
                email: credentials.email,
                passsword: SHA256.hex(credentials.password)
            };

            Login.save(form, loginSuccess, logoutSuccess);
        }

        function checkUserToken(onError) {
            if (!Login) {
                Login = lectureService.login;
            }

            Login.get(loginSuccess, function() {
                logoutSuccess();
                onError();
            });
        }

        function logout() {
            lectureService.logout
                .save(success);

            function success() {
                logoutSuccess();
                $location.path('/');
            }
        }

        function registerObserverCallback(callback) {
            observerCallbacks.push(callback);
        }

        function loginSuccess(response) {
            angular
                .forEach(observerCallbacks, function(callback) {
                    callback(true, response.username);
                });
        }

        function logoutSuccess() {
            angular
                .forEach(observerCallbacks, function(callback) {
                    callback(false);
                });
        }
    }
})();

Fix missing service in lecturerFactory


const zlib = require('zlib'),
      R = require('ramda');

const gunzip = (data) => zlib.gunzipSync(data);
const gzip = (data) => zlib.gzipSync(data);

const decode = R.cond([
  [ R.pathSatisfies(R.equals('gzip'), [ 'properties', 'headers', 'Content-Encoding' ]), R.over(R.lensProp('content'), R.pipe(gunzip, R.toString)) ],
  [ R.T, R.over(R.lensProp('content'), R.toString) ]
]);

const encode = R.cond([
  [ R.pathSatisfies(R.equals('gzip'), [ 'properties', 'headers', 'Content-Encoding' ]), R.over(R.lensProp('content'), R.pipe(R.curryN(1, Buffer.from), gzip)) ],
  [ R.T, Buffer.from ]
]);

module.exports = { decode, encode };

const zlib = require('zlib'),
      R = require('ramda');

const gunzip = (data) => zlib.gunzipSync(data);
const gzip = (data) => zlib.gzipSync(data);

const decode = R.cond([
  [ R.pathSatisfies(R.equals('gzip'), [ 'properties', 'headers', 'Content-Encoding' ]), R.over(R.lensProp('content'), R.pipe(gunzip, R.toString)) ],
  [ R.T, R.over(R.lensProp('content'), R.toString) ]
]);

const encode = R.cond([
  [ R.pathSatisfies(R.equals('gzip'), [ 'properties', 'headers', 'Content-Encoding' ]), R.over(R.lensProp('content'), R.pipe(R.curryN(1, Buffer.from), gzip)) ],
  [ R.T, R.over(R.lensProp('content'), R.curryN(1, Buffer.from)) ]
]);

module.exports = { decode, encode };

Fix for reading non encoded messages


/*global Mocha, window*/
/*
 * mocaccino.js
 *
 * Copyright (c) 2014 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

require('brout');
require('mocha/mocha');

Mocha.reporters.Base.window.width = JSON.parse('{{WINDOW_WIDTH}}');
Mocha.reporters.Base.symbols.dot = '.';

var mocha = new Mocha();
mocha.reporter('{{REPORTER}}');
mocha.suite.emit('pre-require', window, '', mocha);
var t = new Date().getTime();
var y = Number('{{YIELDS}}');
mocha.suite.afterEach(function (done) {
  var now = new Date().getTime();
  if (now - t > y) {
    t = now;
    setTimeout(done, 1);
  } else {
    done();
  }
});

setTimeout(function () {
  Mocha.process.stdout = process.stdout;
  mocha.run(function (errs) {
    process.exit(errs ? 1 : 0);
  });
}, 1);

/*global Mocha, window*/
/*
 * mocaccino.js
 *
 * Copyright (c) 2014 Maximilian Antoni <mail@maxantoni.de>
 *
 * @license MIT
 */
'use strict';

require('brout');
require('mocha/mocha');

Mocha.reporters.Base.window.width = JSON.parse('{{WINDOW_WIDTH}}');
Mocha.reporters.Base.symbols.dot = '.';

var mocha = new Mocha();
mocha.reporter('{{REPORTER}}');
mocha.suite.emit('pre-require', window, '', mocha);
var t = new Date().getTime();
var y = Number('{{YIELDS}}');
mocha.suite.afterEach(function (done) {
  var now = new Date().getTime();
  if (now - t > y) {
    t = now;
    process.nextTick(done);
  } else {
    done();
  }
});

setTimeout(function () {
  Mocha.process.stdout = process.stdout;
  mocha.run(function (errs) {
    process.exit(errs ? 1 : 0);
  });
}, 1);

Use `process.nextTick` to yield instead of `setTimeout`


var slice = [].slice

function Vestibule () {
    this._waiting = []
    this.occupied = false
    this.open = null
}

Vestibule.prototype.enter = function (timeout, callback) {
    if (callback == null) {
        callback = timeout
        timeout = null
    }
    if (this.open == null) {
        if (timeout != null) {
            timeout = setTimeout(this.notify.bind(this), timeout)
        }
        var cookie = {}
        this.occupied = true
        this._waiting.push({
            cookie: cookie,
            callback: callback,
            timeout: timeout
        })
        return cookie
    }
    callback.apply(null, this.open)
    return null
}

Vestibule.prototype.leave = function (cookie) {
    var left = null
    for (var i = 0, I = this._waiting.length; i < I; i++) {
        if (this._waiting[i].cookie === cookie) {
            left = this._waiting.splice(i, 1).shift()
            break
        }
    }
    this.occupied = this._waiting.length != 0
    return left
}

Vestibule.prototype.notify = function () {
    var vargs = slice.call(arguments)
    this.occupied = false
    this._waiting.splice(0, this._waiting.length).forEach(function (waiting) {
        if (waiting.timeout) {
            clearTimeout(waiting.timeout)
        }
        waiting.callback.apply(null, vargs)
    })
}

module.exports = Vestibule

var slice = [].slice

function Vestibule () {
    this._waiting = []
    this.occupied = false
    this.open = null
}

Vestibule.prototype.enter = function (timeout, callback) {
    if (callback == null) {
        callback = timeout
        timeout = null
    }
    if (this.open == null) {
        if (timeout != null) {
            timeout = setTimeout(this.notify.bind(this), timeout)
        }
        var cookie = {}
        this.occupied = true
        this._waiting.push({
            cookie: cookie,
            callback: callback,
            timeout: timeout
        })
        return cookie
    }
    callback.apply(null, this.open)
    return null
}

Vestibule.prototype.leave = function (cookie) {
    var left = null
    for (var i = 0, I = this._waiting.length; i < I; i++) {
        if (this._waiting[i].cookie === cookie) {
            left = this._waiting.splice(i, 1).shift().callback
            break
        }
    }
    this.occupied = this._waiting.length != 0
    return left
}

Vestibule.prototype.notify = function () {
    var vargs = slice.call(arguments)
    this.occupied = false
    this._waiting.splice(0, this._waiting.length).forEach(function (waiting) {
        if (waiting.timeout) {
            clearTimeout(waiting.timeout)
        }
        waiting.callback.apply(null, vargs)
    })
}

module.exports = Vestibule

Fix leave that returns callback.


exports.up = (knex, Promise) => Promise.all([
    knex.schema.createTable('users', table => {
        table.uuid('id')
            .primary()
            .defaultTo(knex.raw('uuid_generate_v4()'));
        table.string('username', 20)
            .unique();
        table.string('password');
        table.float('saldo')
            .defaultTo('0.0');
    }),

    knex.schema.createTable('transactionTypes', table => {
        table.increments('id')
            .primary();
        table.string('typename');
    }),

    knex.schema.createTable('transactions', table => {
        table.increments('id')
            .primary();
        table.integer('typeId')
            .unsigned()
            .references('id')
            .inTable('transactionTypes')
            .onDelete('SET NULL');
        table.float('amount');
        table.uuid('userId')
            .references('id')
            .inTable('users')
            .onDelete('SET NULL');
        table.string('comment');
    })
]);

exports.down = (knex, Promise) => Promise.all([
    knex.schema.dropTable('transactions'),
    knex.schema.dropTable('users'),
    knex.schema.dropTable('transactionTypes')
]);

exports.up = (knex, Promise) => Promise.all([
    knex.schema.createTable('users', table => {
        table.uuid('id')
            .primary()
            .defaultTo(knex.raw('uuid_generate_v4()'));
        table.string('username', 20)
            .unique();
        table.string('password');
        table.float('saldo')
            .defaultTo(0);
    }),

    knex.schema.createTable('transactionTypes', table => {
        table.increments('id')
            .primary();
        table.string('typename');
    }),

    knex.schema.createTable('transactions', table => {
        table.increments('id')
            .primary();
        table.integer('typeId')
            .unsigned()
            .references('id')
            .inTable('transactionTypes')
            .onDelete('SET NULL');
        table.uuid('userId')
            .references('id')
            .inTable('users')
            .onDelete('SET NULL');
        table.timestamp('timestamp')
            .defaultTo(knex.raw('now()'));
        table.float('oldSaldo');
        table.float('newSaldo');
        table.string('comment');
    })
]);

exports.down = (knex, Promise) => Promise.all([
    knex.schema.dropTable('transactions'),
    knex.schema.dropTable('users'),
    knex.schema.dropTable('transactionTypes')
]);

Save old and new saldo in transaction instead of amount


/*
 * grunt-perl-tidy
 * https://github.com/rabrooks/grunt-perl-tidy
 *
 * Copyright (c) 2014 Aaron Brooks
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('perl_tidy', 'Run perl tidy on perl files.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      punctuation: '.',
      separator: ', '
    });

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      // Concat specified files.
      var src = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          return true;
        }
      }).map(function(filepath) {
        // Read file source.
        return grunt.file.read(filepath);
      }).join(grunt.util.normalizelf(options.separator));

      // Handle options.
      src += options.punctuation;

      // Write the destination file.
      grunt.file.write(f.dest, src);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" is now all tidy.');
    });
  });

};

/*
 * grunt-perl-tidy
 * https://github.com/rabrooks/grunt-perl-tidy
 *
 * Copyright (c) 2014 Aaron Brooks
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Please see the Grunt documentation for more information regarding task
  // creation: http://gruntjs.com/creating-tasks

  grunt.registerMultiTask('perl_tidy', 'Run perl tidy on perl files.', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      punctuation: '.',
      separator: ', '
    });

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {
      // Concat specified files.
      var src = f.src.filter(function(filepath) {
        // Warn on and remove invalid source files (if nonull was set).
        if (!grunt.file.exists(filepath)) {
          grunt.log.warn('Source file "' + filepath + '" not found.');
          return false;
        } else {
          // Use this to preform logic on each file that is in the group
          conosle.log (filepath);
          return true;
        }
      }).map(function(filepath) {
        // Read file source.
        return grunt.file.read(filepath);
      }).join(grunt.util.normalizelf(options.separator));

      // Handle options.
      src += options.punctuation;

      // Write the destination file.
      grunt.file.write(f.dest, src);

      // Print a success message.
      grunt.log.writeln('File "' + f.dest + '" is now all tidy.');
    });
  });

};

Set up test directory for js testing


var moment = require('moment');
var userCache = {};
var cacheTimeInMilliseconds = 1000 * 60 * 15;

/**
 * Every time a user posts a message, we update their slack profile so we can stay up to date on their profile
 * @param  {Object} bot
 * @param  {Object} message
 * @param  {Object} controller
 */
module.exports = function updateSlackProfile(bot, message, controller) {
    // This can come in as undefined, so we will just ignore those requests
    if (!message.user) {
        return;
    }

    // Cache the user updates for 15 minutes so we don't do too much stuff
    if (userCache[message.user]) {
        var userCacheExpiration = moment(userCache[message.user]);
        if (userCacheExpiration.diff(moment(), 'minutes') < 15) {
            return;
        }
    }

    controller.storage.users.get(message.user, function(err, user) {
        if (err) {
            return console.trace(err);
        }

        bot.api.users.info({user: message.user}, function(err, res) {
            if (err) {
                console.error('could not get info for user %s', message.user);
                return console.trace(err);
            }

            if (!user) {
                user = {
                    id: message.user,
                };
            }

            user.slackUser = res.user;
            controller.storage.users.save(user, function() {
                userCache[user.id] = new Date();
            });
        });
    });
};

var moment = require('moment');
var userCache = {};
var cacheTimeInMilliseconds = 1000 * 60 * 15;

/**
 * Every time a user posts a message, we update their slack profile so we can stay up to date on their profile
 * @param  {Object} bot
 * @param  {Object} message
 * @param  {Object} controller
 */
module.exports = function updateSlackProfile(bot, message, controller) {
    // This can come in as undefined, so we will just ignore those requests
    if (!message.user) {
        return;
    }

    // Cache the user updates for 15 minutes so we don't do too much stuff
    if (userCache[message.user]) {
        var userCacheExpiration = moment(userCache[message.user]);
        if (userCacheExpiration.diff(moment(), 'minutes') < 15) {
            return;
        }
    }

    controller.storage.users.get(message.user, function(err, user) {
        if (err) {
            return console.trace(err);
        }

        bot.api.users.info({user: message.user}, function(err, res) {
            if (err) {
                console.error('could not get info for user %s', message.user);
                console.dir(message.user);
                return console.trace(err);
            }

            if (!user) {
                user = {
                    id: message.user,
                };
            }

            user.slackUser = res.user;
            controller.storage.users.save(user, function() {
                userCache[user.id] = new Date();
            });
        });
    });
};

Add more logging to see what this strange user is


chrome.tabs.onActivated.addListener(function(info) {
	chrome.tabs.get(info.tabId, function(tab) {
		updateIcon(tab.url);
	});
});

chrome.tabs.onUpdated.addListener(function(tabID, changeInfo, tab) {
	if (changeInfo.active) {
		updateIcon(tab.url);
	}
});

function updateIcon(url) {
	chrome.storage.sync.get('sites', function(items) {
		sites = items['sites'];

		changeIcon(false, null);

		if (url.substring(url.length - 1) == '/') {
			url = url.substring(0, url.length - 1);
		}

		if (sites) {
			for (var i = 0; i < sites.length; i++) {
				if (sites[i].url == url) {
					changeIcon(true, null);
					break;
				}
			}
		}
	});
}

function changeIcon(colors, callback) {
	var details = {};

	if (colors) {
		details.path = '../icons/icon-bitty.png';
	} else {
		details.path = '../icons/icon-bitty-gray.png';
	}

	chrome.browserAction.setIcon(details, callback);
}

chrome.tabs.onActivated.addListener(function(info) {
	chrome.tabs.get(info.tabId, function(tab) {
		updateIcon(tab.url);
	});
});

chrome.tabs.onUpdated.addListener(function(tabID, changeInfo, tab) {
	if (tab.active) {
		updateIcon(tab.url);
	}
});

function updateIcon(url) {
	chrome.storage.sync.get('sites', function(items) {
		sites = items['sites'];

		changeIcon(false, null);

		if (url.substring(url.length - 1) == '/') {
			url = url.substring(0, url.length - 1);
		}

		if (sites) {
			for (var i = 0; i < sites.length; i++) {
				if (sites[i].url == url) {
					changeIcon(true, null);
					break;
				}
			}
		}
	});
}

function changeIcon(colors, callback) {
	var details = {};

	if (colors) {
		details.path = '../icons/icon-bitty.png';
	} else {
		details.path = '../icons/icon-bitty-gray.png';
	}

	chrome.browserAction.setIcon(details, callback);
}

Change object to retrieve if the tab is active or not for onUpdated.


// Generated by CoffeeScript 1.6.3
var Q, request;

Q = require('q');

request = require('request');

exports.parse = function(zip) {
  var deferred;
  deferred = Q.defer();
  request.get("http://zip.elevenbasetwo.com/v2/US/" + zip, function(err, res, body) {
    if (err) {
      return deferred.reject(new Error(err));
    } else {
      return deferred.resolve(JSON.parse(body));
    }
  });
  return deferred.promise;
};

'use strict';

var Promise = require('bluebird'),
    request = Promise.promisify(require('request')),
    _       = require('lodash');

var baseURL = 'http://zip.elevenbasetwo.com/v2';

var Ziptastic = {
	url: function(options) {
		return [baseURL, options.country, options.zip].join('/');
	},
	parse: Promise.method(function(options, callback) {
		options = _.defaults(options || {}, {
			country: 'US'
		});

		if (!options.zip) {
			throw new Error('A ZIP code must be supplied');
		}

		return request(this.url(options))
			.spread(function(response, body) {
				return body;
			})
			.nodeify(callback);
	})
};

module.exports = _.extend(Ziptastic.parse, Ziptastic);

Rewrite in plain JS and stop using deferreds


/**
 *
 * Docbase engine
 * Appbase
 * MIT license
 */

(function($, angular) {
    /*
     * Scrollspy.
     */
    $(function() {
        $("h2, h3").scrollagent(function(cid, pid, currentElement, previousElement) {
            if (pid) {
                $("[href*='#" + pid + "']").removeClass('active');
            }
            if (cid) {
                $("[href*='#" + cid + "']").addClass('active');
            }
        });
    });
})(window.jQuery, window.angular);

/**
 *
 * Docbase engine
 * Appbase
 * MIT license
 */

(function($, angular) {
    /*
     * Scrollspy.
     */
    $(function() {
        $("h2, h3").scrollagent(function(cid, pid, currentElement, previousElement) {
            if (pid) {
                $("[pref='#" + pid + "']").removeClass('active');
            }
            if (cid) {
                $("[pref='#" + cid + "']").addClass('active');
            }
        });
    });
})(window.jQuery, window.angular);

Fix left navigation selector issue


var debug = require("debug")("provider"); // eslint-disable-line no-unused-vars
var Web3 = require("web3");

var wrapper = require("./wrapper");

module.exports = {
  wrap: function(provider, options) {
    return wrapper.wrap(provider, options);
  },

  create: function(options) {
    var provider;

    if (options.provider && typeof options.provider == "function") {
      provider = options.provider();
    } else if (options.provider) {
      provider = options.provider;
    } else if (options.websockets) {
      provider = new Web3.providers.WebsocketProvider(
        "ws://" + options.host + ":" + options.port
      );
    } else {
      provider = new Web3.providers.HttpProvider(
        "http://" + options.host + ":" + options.port,
        { keepAlive: false }
      );
    }

    return this.wrap(provider, options);
  },

  test_connection: function(provider, callback) {
    var web3 = new Web3();
    var fail = new Error(
      "Could not connect to your RPC client. Please check your RPC configuration."
    );

    web3.setProvider(provider);

    web3.eth
      .getCoinbase()
      .then(coinbase => callback(null, coinbase))
      .catch(() => callback(fail, null));
  }
};

var debug = require("debug")("provider"); // eslint-disable-line no-unused-vars
var Web3 = require("web3");

var wrapper = require("./wrapper");

module.exports = {
  wrap: function(provider, options) {
    return wrapper.wrap(provider, options);
  },

  create: function(options) {
    var provider;

    if (options.provider && typeof options.provider === "function") {
      provider = options.provider();
    } else if (options.provider) {
      provider = options.provider;
    } else if (options.websockets) {
      provider = new Web3.providers.WebsocketProvider(
        "ws://" + options.host + ":" + options.port
      );
    } else {
      provider = new Web3.providers.HttpProvider(
        "http://" + options.host + ":" + options.port,
        { keepAlive: false }
      );
    }

    return this.wrap(provider, options);
  },

  test_connection: function(provider, callback) {
    var web3 = new Web3();
    var fail = new Error(
      "Could not connect to your RPC client. Please check your RPC configuration."
    );

    web3.setProvider(provider);

    web3.eth
      .getCoinbase()
      .then(coinbase => callback(null, coinbase))
      .catch(() => callback(fail, null));
  }
};

Convert Non-strict to strict equality checking Convert non-strict equality checking, using `==`, to the strict version, using `===`.


this.gts.datePicker = (function() {

  return function(input) {
    $(input).datepicker();
  };

}());

this.gts.datePicker = (function() {

  return function(input) {
    $(input).datepicker({ dateFormat: "yy-mm-dd" });
  };

}());

Fix date format in the datepicker


const User = require('./user');
const {Sequelize, db} = require('../connection');

const ClanModel = db.define('clan', {
  name: {
    type: Sequelize.STRING(64),
    allowNull: false,
    unique: true
  },
  tag: {
    type: Sequelize.STRING(8),
    allowNull: true,
  },
  avatar: {
    type: Sequelize.STRING(144),
    allowNull: true,
  },
  description: {
    type: Sequelize.STRING(144),
    allowNull: true,
  },
});

var Clan = {model: ClanModel};

Clan.findAll = function(query = {}) {
  return ClanModel.findAll({where: query});
};

/**
 * Clan crud methods.
 */
Clan.create = function({name, userId, tag, avatar, description}) {
  return ClanModel.find({where: {name}})
    .then(function(clan) {
      if (clan) {
        throw new Error('Clan already exists');
      }
      return ClanModel.create({name, userId, tag, avatar, description});
    });
};

Clan.read = Clan.find = function(query) {
  return ClanModel.findOne({where: query});
};

Clan.update = function(query, values) {
  return ClanModel.update(values, {where: query});
};

Clan.delete = function(query) {
  return ClanModel.destroy({where: query});
};

module.exports = Clan;

const User = require('./user');
const {Sequelize, db} = require('../connection');

const ClanModel = db.define('clan', {
  name: {
    type: Sequelize.STRING(64),
    allowNull: false,
    unique: true
  },
  tag: {
    type: Sequelize.STRING(8),
    allowNull: true,
  },
  avatar: {
    type: Sequelize.STRING(144),
    allowNull: true,
  },
  description: {
    type: Sequelize.STRING(144),
    allowNull: true,
  },
});

var Clan = {model: ClanModel};

Clan.findAll = function(query = {}) {
  return ClanModel.findAll({where: query});
};

/**
 * Clan crud methods.
 */
Clan.create = function({name, creatorId, tag, avatar, description}) {
  return ClanModel.find({where: {name}})
    .then(function(clan) {
      if (clan) {
        throw new Error('Clan already exists');
      }
      return ClanModel.create({name, creatorId, tag, avatar, description});
    });
};

Clan.read = Clan.find = function(query) {
  return ClanModel.findOne({where: query});
};

Clan.update = function(query, values) {
  return ClanModel.update(values, {where: query});
};

Clan.delete = function(query) {
  return ClanModel.destroy({where: query});
};

module.exports = Clan;

Update constructor to match aliased foreign key


'use strict';

/**
 * @ngdoc function
 * @name docker-registry-frontend.controller:RepositoryDetailController
 * @description
 * # RepositoryController
 * Controller of the docker-registry-frontend
 */
angular.module('repository-detail-controller', ['app-mode-services'])
  .controller('RepositoryDetailController', ['$scope', '$route', '$routeParams', '$location', 'AppMode',
  function($scope, $route, $routeParams, $location, AppMode){

    $scope.$route = $route;
    $scope.$location = $location;
    $scope.$routeParams = $routeParams;

    $scope.searchTerm = $route.current.params['searchTerm'];
    $scope.repositoryUser = $route.current.params['repositoryUser'];
    $scope.repositoryName = $route.current.params['repositoryName'];
    $scope.repository = $scope.repositoryUser + '/' + $scope.repositoryName;

    $scope.appMode = AppMode.query();
  }]);

'use strict';

/**
 * @ngdoc function
 * @name docker-registry-frontend.controller:RepositoryDetailController
 * @description
 * # RepositoryDetailController
 * Controller of the docker-registry-frontend
 */
angular.module('repository-detail-controller', ['app-mode-services'])
  .controller('RepositoryDetailController', ['$scope', '$route', '$routeParams', '$location', 'AppMode',
  function($scope, $route, $routeParams, $location, AppMode){
    $scope.appMode = AppMode.query();
  }]);

Adjust documentation and remove unnecessary code


define(['itemObjectModel', 'mac/roman'], function(itemOM, macRoman) {

  'use strict';

  function open(item) {
    function onAtom(item, byteSource) {
      return byteSource.slice(0, 8).getBytes().then(function(headerBytes) {
        var length = new DataView(headerBytes.buffer, headerBytes.byteOffset, 4).getUint32(0, false);
        var name = macRoman(headerBytes, 4, 4);
        var atomItem = itemOM.createItem(name);
        if (length > 8) {
          atomItem.byteSource = byteSource.slice(8, length);
        }
        item.addItem(atomItem);
        if (byteSource.byteLength > (length + 8)) {
          return onAtom(item, byteSource.slice(length));
        }
      });
    }
    return onAtom(item, item.byteSource);
  }

  return open;

});

define(['itemObjectModel', 'mac/roman'], function(itemOM, macRoman) {

  'use strict';

  function open(item) {
    function onAtom(item, byteSource) {
      return byteSource.slice(0, 8).getBytes().then(function(headerBytes) {
        var length = new DataView(headerBytes.buffer, headerBytes.byteOffset, 4).getUint32(0, false);
        var name = macRoman(headerBytes, 4, 4);
        var atomItem = itemOM.createItem(name);
        if (length > 8) {
          atomItem.byteSource = byteSource.slice(8, length);
        }
        item.addItem(atomItem);
        if (byteSource.byteLength >= (length + 8)) {
          return onAtom(item, byteSource.slice(length));
        }
      });
    }
    return onAtom(item, item.byteSource);
  }

  return open;

});

Allow for a zero-length atom at the end


'use strict';

var angular = require('angular');
var expect  = require('chai').use(require('chai-as-promised')).expect;
var sinon   = require('sinon');

describe('angular-q-promisify', function () {

  var $q, $timeout;
  beforeEach(angular.mock.module(require('../')));
  beforeEach(angular.mock.inject(function (_$q_, _$timeout_) {
    $q = _$q_;
    $timeout = _$timeout_;
  }));

  describe('#promisify', function () {

    it('promisifes a nodeback', function () {
      var nodeback = sinon.stub().yields(null);
      expect($q.promisify(nodeback)()).to.be.fulfilled;
      $timeout.flush();
    });

  });

});

'use strict';

var angular = require('angular');
var expect  = require('chai').use(require('chai-as-promised')).expect;
var sinon   = require('sinon');

describe('angular-q-promisify', function () {

  var $q, $timeout;
  beforeEach(angular.mock.module(require('../')));
  beforeEach(angular.mock.inject(function (_$q_, _$timeout_) {
    $q = _$q_;
    $timeout = _$timeout_;
  }));

  describe('#promisify', function () {

    it('promisifes a nodeback', function () {
      var nodeback = sinon.stub().yields(null);
      expect($q.promisify(nodeback)()).to.be.fulfilled;
      $timeout.flush();
    });

    it('fulfills with a value', function () {
      var nodeback = sinon.stub().yields(null, 'foo');
      expect($q.promisify(nodeback)()).to.eventually.equal('foo');
      $timeout.flush();
    });

    it('returns multiple values as an array', function () {
      var nodeback = sinon.stub().yields(null, 'foo', 'bar');
      expect($q.promisify(nodeback)()).to.eventually.deep.equal(['foo', 'bar']);
      $timeout.flush();
    });

    it('rejects with errors', function () {
      var err = new Error();
      var nodeback = sinon.stub().yields(err);
      expect($q.promisify(nodeback)()).to.be.rejectedWith(err);
      $timeout.flush();
    });

    it('rejects with errors thrown by the callback', function () {
      var err = new Error();
      var nodeback = sinon.stub().throws(err);
      expect($q.promisify(nodeback)()).to.be.rejectedWith(err);
      $timeout.flush();
    });

  });

});

Test resolution and rejection scenarios for promisification


process.env.NODE_ENV = 'test';
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin')

var webpackConfig = require(path.join(__dirname, './node_modules/react-scripts/config/webpack.config.dev.js'));
webpackConfig.devtool = 'inline-source-map';
webpackConfig.plugins.push(new DefinePlugin({
  DOMAIN: JSON.stringify('apiary.dev')
}));

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: ['src/**/iframe/**/**.test.js', 'src/**/JsAgent/**/**.test.js'],
    exclude: [],
    preprocessors: { 'src/**/**.test.js': ['webpack', 'sourcemap'] },
    webpack: webpackConfig,
    reporters: ['mocha', 'junit'],
    junitReporter: {
      outputDir: `${process.env.CIRCLE_TEST_REPORTS || '.'}/unit/iframe`,
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome', 'Firefox'],
    singleRun: true,
    concurrency: 1,
  });
}

process.env.NODE_ENV = 'test';
const path = require('path');
const DefinePlugin = require('webpack/lib/DefinePlugin')

var webpackConfig = require(path.join(__dirname, './node_modules/react-scripts/config/webpack.config.dev.js'));
webpackConfig.devtool = 'inline-source-map';
webpackConfig.plugins.push(new DefinePlugin({
  DOMAIN: JSON.stringify('apiary.dev')
}));
webpackConfig.module.preLoaders = [];

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],
    files: ['src/**/iframe/**/**.test.js', 'src/**/JsAgent/**/**.test.js'],
    exclude: [],
    preprocessors: { 'src/**/**.test.js': ['webpack', 'sourcemap'] },
    webpack: webpackConfig,
    reporters: ['mocha', 'junit'],
    junitReporter: {
      outputDir: `${process.env.CIRCLE_TEST_REPORTS || '.'}/unit/iframe`,
    },
    port: 9876,
    colors: true,
    logLevel: config.LOG_INFO,
    autoWatch: false,
    browsers: ['Chrome', 'Firefox'],
    singleRun: true,
    concurrency: 1,
  });
}

Remove EsLint preloader from tests


require('@maxdome/env');

const logging = require('@maxdome/logging')({
  level: process.env.LOG_LEVEL,
});
require('@maxdome/exception-handling')({ logging });
const appLogger = logging('app');
appLogger.info('initializing server');
const app = require('@maxdome/express')();
app.use(require('@maxdome/logging-middleware')({ logging }));

app.use('/docs', require('@maxdome/swagger')({ config: 'docs/swagger.yml' }));
app.get('/health', require('@maxdome/health').controller());
app.use('/info', require('@maxdome/info')());

app.use('/api', require('./api')());

app.use(require('@maxdome/logging-middleware').errorLogging({ logging }));
if (!module.parent) {
  const port = process.env.PORT || 3000;
  app.listen(port, () => {
    appLogger.info(`Server listening on ${port}`);
  });
}
module.exports = app;

module.exports = async () => {
  require('@maxdome/env');

  const logging = require('@maxdome/logging')({
    level: process.env.LOG_LEVEL,
  });
  require('@maxdome/exception-handling')({ logging });
  const appLogger = logging('app');
  appLogger.info('initializing server');
  const app = require('@maxdome/express')();
  app.use(require('@maxdome/logging-middleware')({ logging }));

  app.use('/docs', require('@maxdome/swagger')({ config: 'docs/swagger.yml' }));
  app.get('/health', require('@maxdome/health').controller());
  app.use('/info', require('@maxdome/info')());

  app.use('/api', require('./api')());

  app.use(require('@maxdome/logging-middleware').errorLogging({ logging }));

  return { app, logging };
};

if (!module.parent) {
  (async () => {
    const { app, logging } = await module.exports();
    const port = process.env.PORT || 3000;
    app.listen(port, () => {
      logging('app').info(`Server listening on ${port}`);
    });
  })();
}

Refactor the app startup to be async


import deepFreeze from 'deep-freeze';
import appReducer from './appReducer';
import { websocketConnected, websocketDisconnected } from './AppActions';

it('na začátku', () => {
  const stateBefore = undefined;

  const stateAfter = appReducer(stateBefore, {});
  expect(stateAfter).toMatchSnapshot();
});

it('websocket connected', () => {
  const stateBefore = { connected: false };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, websocketConnected());
  expect(stateAfter.connected).toEqual(true);
  expect(stateAfter).toMatchSnapshot();
});

it('websocket disconnected', () => {
  const stateBefore = { connected: true };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, websocketDisconnected());
  expect(stateAfter.connected).toEqual(false);
  expect(stateAfter).toMatchSnapshot();
});

import deepFreeze from 'deep-freeze';
import {
  fetchUcastniciRequest,
  fetchUcastniciSuccess
} from '../entities/ucastnici/ucastniciActions';
import appReducer from './appReducer';
import { websocketConnected, websocketDisconnected } from './AppActions';

it('na začátku', () => {
  const stateBefore = undefined;

  const stateAfter = appReducer(stateBefore, {});
  expect(stateAfter).toMatchSnapshot();
});

it('websocket connected', () => {
  const stateBefore = { connected: false };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, websocketConnected());
  expect(stateAfter.connected).toEqual(true);
  expect(stateAfter).toMatchSnapshot();
});

it('websocket disconnected', () => {
  const stateBefore = { connected: true };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, websocketDisconnected());
  expect(stateAfter.connected).toEqual(false);
  expect(stateAfter).toMatchSnapshot();
});

it('fetchUcastniciRequest()', () => {
  const stateBefore = { fetching: undefined };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, fetchUcastniciRequest());
  expect(stateAfter.fetching).toEqual('fetching');
});

it('fetchUcastniciSuccess()', () => {
  const stateBefore = { fetching: 'fetching' };
  deepFreeze(stateBefore);

  const stateAfter = appReducer(stateBefore, fetchUcastniciSuccess({ response: { }}));
  expect(stateAfter.fetching).toEqual('done');
});

Test fetching sub-state of appReducer.


/* global AFRAME */
AFRAME.registerComponent('camera-position', {
  schema: {
    mobile: {type: 'vec3', default: '0 1.6 3'},
    desktop: {type: 'vec3', default: '0 1.6 3'}
  },
  init: function () {
    this.onCameraSetActive = this.onCameraSetActive.bind(this);
    this.resetCamera = this.resetCamera.bind(this);
    this.el.addEventListener('camera-set-active', this.onCameraSetActive);
    this.el.addEventListener('exit-vr', this.onCameraSetActive);
    this.el.addEventListener('enter-vr', this.resetCamera);
  },

  onCameraSetActive: function () {
    var cameraEl = this.el.camera.el;
    var data = this.data;
    var isMobile = AFRAME.utils.device.isMobile();
    var position = isMobile ? data.mobile : data.desktop;
    var savedPose = cameraEl.components.camera.savedPose;
    if (savedPose) { savedPose.position.z = position.z; }
    this.el.camera.el.setAttribute('position', position);
  },

  resetCamera: function () {
    var cameraEl = this.el.camera.el;
    var position = cameraEl.getAttribute('position');
    cameraEl.setAttribute('position', {
      x: position.x,
      y: position.y,
      z: 0
    });
  }
});

/* global AFRAME */
AFRAME.registerComponent('camera-position', {
  schema: {
    mobile: {type: 'vec3', default: '0 1.6 3'},
    desktop: {type: 'vec3', default: '0 1.6 2'}
  },
  init: function () {
    this.onCameraSetActive = this.onCameraSetActive.bind(this);
    this.resetCamera = this.resetCamera.bind(this);
    if (this.el.camera) { this.onCameraSetActive(); }
    this.el.addEventListener('camera-set-active', this.onCameraSetActive);
    this.el.addEventListener('exit-vr', this.onCameraSetActive);
    this.el.addEventListener('enter-vr', this.resetCamera);
  },

  onCameraSetActive: function () {
    var cameraEl = this.el.camera.el;
    var data = this.data;
    var isMobile = AFRAME.utils.device.isMobile();
    var position = isMobile ? data.mobile : data.desktop;
    var savedPose = cameraEl.components.camera.savedPose;
    if (savedPose) { savedPose.position.z = position.z; }
    this.el.camera.el.setAttribute('position', position);
  },

  resetCamera: function () {
    var cameraEl = this.el.camera.el;
    var position = cameraEl.getAttribute('position');
    cameraEl.setAttribute('position', {
      x: position.x,
      y: position.y,
      z: 0
    });
  }
});

Fix tracked-controls example camera positioning


import { actions } from '../config/constants';
import { isOrgMember } from '../helpers/github';
import { ref, firebaseAuth } from '../config/constants'

export function logout() {
  return dispatch => {
    return firebaseAuth().signOut().then(() => {
      dispatch({ type: actions.SIGN_OUT });
    });
  }
}

export function login() {
  return dispatch => {
    const provider = new firebaseAuth.GithubAuthProvider();
    provider.addScope('read:org');

    return firebaseAuth().signInWithPopup(provider).then(payload => {
      const { user } = payload;
      ref.child(`users/${user.uid}`).set({
        accessToken: payload.credential.accessToken,
        displayName: user.displayName,
        email: user.email,
        uid: user.uid,
      });

      dispatch(verifyOrg(payload.credential.accessToken));
    });
  }
}

function verifyOrg(token, org) {
  return dispatch => {
    isOrgMember(token, org).then(isMember => {
      if (!isMember) {
        dispatch(logout());
        dispatch({
          type: actions.ERROR,
          payload: {
            type: 'auth',
            message: `Login failed. Make sure you are a member of the GitHub organization and have granted this app access to it.`,
          },
        });
      }
    });
  };
}

import { actions } from '../config/constants';
import { isOrgMember } from '../helpers/github';
import { ref, firebaseAuth } from '../config/constants'

export function logout() {
  return dispatch => {
    return firebaseAuth().signOut().then(() => {
      dispatch({ type: actions.SIGN_OUT });
    });
  }
}

export function login() {
  return dispatch => {
    const provider = new firebaseAuth.GithubAuthProvider();
    provider.addScope('read:org');

    return firebaseAuth().signInWithPopup(provider).then(payload => {
      const { user } = payload;
      ref.child(`users/${user.uid}/creds`).set({
        accessToken: payload.credential.accessToken,
        displayName: user.displayName,
        email: user.email,
        uid: user.uid,
      });

      dispatch(verifyOrg(payload.credential.accessToken));
    });
  }
}

function verifyOrg(token, org) {
  return dispatch => {
    isOrgMember(token, org).then(isMember => {
      if (!isMember) {
        dispatch(logout());
        dispatch({
          type: actions.ERROR,
          payload: {
            type: 'auth',
            message: `Login failed. Make sure you are a member of the GitHub organization and have granted this app access to it.`,
          },
        });
      }
    });
  };
}

Move user info to /creds


'use strict';

module.exports = function(config) {

    var files = [];

    [
        'jquery-1.8.2-min.js',
        'angular.js',
        'angular-resource.js',
        'angular-mocks.js',
        'angular-ui-states.js',
        'lodash.js'
    ].forEach(function(file) {
        files.push('app/vendor/' + file);
    });

    files.push('app/scripts/*.js');
    files.push('app/scripts/**/*.js');
    files.push('tmp/scripts/**/*.js');
    files.push('test/**/*.js');

    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: files,
        exclude: [],
        port: 7070,
        logLevel: config.LOG_INFO,
        autoWatch: false,

        // Start these browsers, currently available:
        // - Chrome
        // - ChromeCanary
        // - Firefox
        // - Opera
        // - Safari (only Mac)
        // - PhantomJS
        // - IE (only Windows)
        browsers: ['PhantomJS']
    });
};

'use strict';

module.exports = function(config) {

    var files = [];

    [
        'jquery-1.8.2-min.js',
        'angular.js',
        'angular-resource.js',
        'angular-mocks.js',
        'angular-ui-states.js',
        'lodash.js',
        'markdown/marked.js'
    ].forEach(function(file) {
        files.push('app/vendor/' + file);
    });

    files.push('app/scripts/*.js');
    files.push('app/scripts/**/*.js');
    files.push('tmp/scripts/**/*.js');
    files.push('test/**/*.js');

    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: files,
        exclude: [],
        port: 7070,
        logLevel: config.LOG_INFO,
        autoWatch: false,

        // Start these browsers, currently available:
        // - Chrome
        // - ChromeCanary
        // - Firefox
        // - Opera
        // - Safari (only Mac)
        // - PhantomJS
        // - IE (only Windows)
        browsers: ['PhantomJS']
    });
};

Replace markdown lib in test config


import Ember from 'ember';
import DS from 'ember-data';

export default DS.Model.extend({
  vendor: DS.belongsTo('vendor'),
  location: DS.attr('string'),
  manager: DS.belongsTo('account'),
  time: DS.attr('string'),
  money: DS.attr({ defaultValue: () => ({}) }),
  portions: DS.hasMany('portion'),
  active: DS.attr('boolean', { defaultValue: true }),

  isReady: Ember.computed('money.total', 'money.required', function() {
    return this.get('money.total') >= this.get('money.required');
  }),

  addPortion(portion) {
    const total = this.get('money.total');
    const cost = portion.get('cost');

    this.set('money.total', total + cost);
    this.get('portions').pushObject(portion);
  },

  removePortion(portion) {
    const available = this.get('money.available');
    const total = this.get('money.total');
    const cost = portion.get('cost');

    this.set('money.total', total - cost);
    if (portion.get('paid')) {
      this.set('money.available', available - cost);
    }

    this.get('portions').popObject(portion);
  }
});

import Ember from 'ember';
import DS from 'ember-data';

export default DS.Model.extend({
  vendor: DS.belongsTo('vendor'),
  location: DS.attr('string'),
  manager: DS.belongsTo('account'),
  time: DS.attr('string'),
  money: DS.attr({ defaultValue: () => ({}) }),
  portions: DS.hasMany('portion'),
  active: DS.attr('boolean', { defaultValue: true }),

  isReady: Ember.computed('money.total', 'money.required', function() {
    return this.get('money.total') >= this.get('money.required');
  }),

  addPortion(portion) {
    const total = this.get('money.total');
    const cost = portion.get('cost');

    this.set('money.total', total + cost);
    this.get('portions').pushObject(portion);
  },

  removePortion(portion) {
    const available = this.get('money.available');
    const total = this.get('money.total');
    const cost = portion.get('cost');

    this.set('money.total', total - cost);
    if (portion.get('paid')) {
      this.set('money.available', available - cost);
    }

    this.get('portions').removeObject(portion);
  }
});

Use removeObject instead of popObject


import { combineReducers }              from 'redux';
import settings                         from './settings';
import application                      from './application';
import assessment                       from './assessment';
import assessmentProgress               from './assessment_progress';
import jwt                              from './jwt';
import assessmentMeta                   from './assessment_meta';
import assessmentResults                from './assessment_results';

const rootReducer = combineReducers({
  settings,
  jwt,
  application,
  assessment,
  assessmentMeta,
  assessmentResults
});

export default rootReducer;

import { combineReducers }              from 'redux';
import settings                         from './settings';
import application                      from './application';
import assessment                       from './assessment';
import assessmentProgress               from './assessment_progress';
import jwt                              from './jwt';
import assessmentMeta                   from './assessment_meta';
import assessmentResults                from './assessment_results';

const rootReducer = combineReducers({
  settings,
  jwt,
  application,
  assessment,
  assessmentProgress,
  assessmentMeta,
  assessmentResults
});

export default rootReducer;

Add progress back into the reducer list


/* eslint comma-dangle: 0 */
import createCachedSelector from '../index';

let memoizedFunction;

beforeEach(() => {
  memoizedFunction = jest.fn();
});

describe('createCachedSelector', () => {
  it('Should use the same cached selector when resolver function returns the same string', () => {
    const cachedSelector = createCachedSelector(
        memoizedFunction,
    )(
        (arg1, arg2) => arg2,   // Resolver
    );
    const firstCall = cachedSelector('foo', 'bar');
    const secondCallWithSameResolver = cachedSelector('foo', 'bar');

    expect(memoizedFunction.mock.calls.length).toBe(1);
  });

  it('Should create 2 different selectors when resolver function returns different strings', () => {
    const cachedSelector = createCachedSelector(
        memoizedFunction,
    )(
        (arg1, arg2) => arg2,   // Resolver
    );
    const firstCallResult = cachedSelector('foo', 'bar');
    const secondCallWithDifferentResolver = cachedSelector('foo', 'moo');

    expect(memoizedFunction.mock.calls.length).toBe(2);
  });
});

/* eslint comma-dangle: 0 */
import createCachedSelector from '../index';

let memoizedFunction;

beforeEach(() => {
  memoizedFunction = jest.fn();
});

describe('createCachedSelector', () => {
  it('Should use the same cached selector when resolver function returns the same string', () => {
    const cachedSelector = createCachedSelector(
        memoizedFunction,
    )(
        (arg1, arg2) => arg2,   // Resolver
    );
    const firstCall = cachedSelector('foo', 'bar');
    const secondCallWithSameResolver = cachedSelector('foo', 'bar');

    expect(memoizedFunction.mock.calls.length).toBe(1);
  });

  it('Should create 2 different selectors when resolver function returns different strings', () => {
    const cachedSelector = createCachedSelector(
        memoizedFunction,
    )(
        (arg1, arg2) => arg2,   // Resolver
    );
    const firstCallResult = cachedSelector('foo', 'bar');
    const secondCallWithDifferentResolver = cachedSelector('foo', 'moo');

    expect(memoizedFunction.mock.calls.length).toBe(2);
  });

  it('Should return "undefined" if provided resolver does not return a string', () => {
    const cachedSelector = createCachedSelector(
        memoizedFunction,
    )(
        () => {},   // Resolver
    );
    const firstCallResult = cachedSelector('foo', 'bar');

    expect(memoizedFunction.mock.calls.length).toBe(0);
    expect(firstCallResult).toBe(undefined);
  });
});

Extend test cases to resolver function returning a non string


module.exports = {
  testPathIgnorePatterns: [
    '<rootDir>[/\\\\](dist|node_modules|sku)[/\\\\]'
  ],
  'moduleNameMapper': {
    '\\.(css|less)$': 'identity-obj-proxy'
  },
  transform: {
    '^.+\\.(js|jsx)$': require.resolve('./babelTransform.js')
  },
  transformIgnorePatterns: [
    '[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'
  ]
};

module.exports = {
  testPathIgnorePatterns: [
    '<rootDir>[/\\\\](dist|node_modules)[/\\\\]'
  ],
  'moduleNameMapper': {
    '\\.(css|less)$': 'identity-obj-proxy'
  },
  transform: {
    '^.+\\.(js|jsx)$': require.resolve('./babelTransform.js')
  },
  transformIgnorePatterns: [
    '[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'
  ]
};

Remove sku from ignored test paths


import React, { Component } from 'react';
import Icon from 'react-native-vector-icons/FontAwesome';

import styles from './styles';

/**
 * Thumbnail badge for displaying the video mute status of a participant.
 */
export class VideoMutedIndicator extends Component {
    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     */
    render() {
        // TODO: This should use video-camera-slash, but that doesn't exist in
        // the fontawesome icon set yet.
        return (
            <Icon
                name = 'eye-slash'
                style = { styles.thumbnailIndicator } />
        );
    }
}

import React, { Component } from 'react';

import { Icon } from '../../../base/font-icons';

import styles from './styles';

/**
 * Thumbnail badge for displaying the video mute status of a participant.
 */
export class VideoMutedIndicator extends Component {
    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     */
    render() {
        return (
            <Icon
                name = 'camera-disabled'
                style = { styles.thumbnailIndicator } />
        );
    }
}

Use same video mute indicator icon as on the web


'use strict';

/**
 * Module dependencies.
 */
var _ = require('lodash'),
	errorHandler = require('../errors.server.controller'),
	mongoose = require('mongoose'),
	passport = require('passport'),
	User = mongoose.model('User');

/**
 * View all users
 */
exports.all = function(req, res) {
  User.find({}, {displayName: 1}, function(err, docs) {
    return res.status(200).send(docs);
  });
};

'use strict';

/**
 * Module dependencies.
 */
var _ = require('lodash'),
	errorHandler = require('../errors.server.controller'),
	mongoose = require('mongoose'),
	passport = require('passport'),
	User = mongoose.model('User');

/**
 * View all users
 */
exports.all = function(req, res) {
  User.find({}, {displayName: 1, messages: 1}, function(err, docs) {
    return res.status(200).send(docs);
  });
};

Add messages field to server response


/*
 * itsjoke.js - It's Joke!.
 *
 * Contributed by Capuccino and Ovyerus.
 */

/* eslint-env node */

const fs = require('fs');
const files = fs.readdirSync(`${__baseDir}/res/itsjoke`);

exports.commands = [
    'mari'
];

exports.mari = {
    desc: "It's joke!",
    longDesc: "Send a random picture of the it's joke meme.",
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            ctx.channel.sendTyping();
            let fileName = files[Math.floor(Math.random() * files.length)];
            let file = fs.readFileSync(`${__baseDir}/assets/itsjoke/${fileName}`);
            ctx.createMessage('', {file, name: fileName}).then(resolve).catch(reject);
        });
    }
};

/*
 * itsjoke.js - It's Joke!.
 *
 * Contributed by Capuccino and Ovyerus.
 */

/* eslint-env node */

const fs = require('fs');
const files = fs.readdirSync(`${__baseDir}/assets/itsjoke`);

exports.commands = [
    'mari'
];

exports.mari = {
    desc: "It's joke!",
    longDesc: "Send a random picture of the it's joke meme.",
    main(bot, ctx) {
        return new Promise((resolve, reject) => {
            ctx.channel.sendTyping();
            let fileName = files[Math.floor(Math.random() * files.length)];
            let file = fs.readFileSync(`${__baseDir}/assets/itsjoke/${fileName}`);
            ctx.createMessage('', {file, name: fileName}).then(resolve).catch(reject);
        });
    }
};

Fix mari pointing to dead dir


/** @license MIT License (c) copyright 2010-2013 original author or authors */

/**
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author: Brian Cavalier
 * @author: John Hann
 */

(function(define) { 'use strict';
define(function(require) {

	var when, tests, run, input;

	when = require('../when');
	run = require('./run');

	tests = [
		{ name: 'map 100', fn: map(100), defer: true },
		{ name: 'map 1k', fn: map(1e3), defer: true }
	];

	run(tests);

	//
	// Benchmark tests
	//

	function map(n) {
		return function(deferred) {

			var input = [];
			for(var i = 0; i < n; i++) {
				input.push(when(i));
			}

			when.map(input, addOne).then(function(r) {
				deferred.resolve();
			});

		};
	}

	//
	// Promise helpers
	//

	function addOne(x) {
		return x + 1;
	}

});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));

/** @license MIT License (c) copyright 2010-2013 original author or authors */

/**
 * Licensed under the MIT License at:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * @author: Brian Cavalier
 * @author: John Hann
 */

(function(define) { 'use strict';
define(function(require) {

	var when, tests, run;

	when = require('../when');
	run = require('./run');

	tests = [
		{ name: 'map 100', fn: map(100), defer: true },
		{ name: 'map 1k', fn: map(1e3), defer: true }
	];

	run(tests);

	//
	// Benchmark tests
	//

	function map(n) {
		return function(deferred) {

			var input = [];
			for(var i = 0; i < n; i++) {
				input.push(when(i));
			}

			when.map(input, addOne).then(function() {
				deferred.resolve();
			});

		};
	}

	//
	// Promise helpers
	//

	function addOne(x) {
		return x + 1;
	}

});
}(typeof define === 'function' && define.amd ? define : function(factory) { module.exports = factory(require); }));

Fix jshint warnings in benchmark


// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//mm
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })

require('cypress-downloadfile/lib/downloadFileCommand')

Cypress.Commands.add('setYesNoRadioInput', (selector, value) => {
  const selectorValue = value === 'Yes' ? '0' : '1'
  cy.get(`#${selector}-${selectorValue}`).check();
})

Cypress.Commands.add('setTextInput', (selector, value) => {
  cy.get(`#${selector}`).type(value);
})

Cypress.Commands.add('setCheckboxInput', selector => {
  cy.get(`#${selector}`).check();
})
Cypress.Commands.add('setSelectInput', (selector, value) => {
  cy.get(`#${selector}`).select(value);
})

Cypress.Commands.add('setRadioInput', selector => {
  cy.get(`#${selector}`).check();
})

Cypress.Commands.add('savePage', fileName => {
  cy.url().then(url => {
    cy.downloadFile(url, '/home/circleci/project/cypress/pages', `${fileName}.html`)
  })
})

require('cypress-downloadfile/lib/downloadFileCommand')

Cypress.Commands.add('setYesNoRadioInput', (selector, value) => {
  const selectorValue = value === 'Yes' ? '0' : '1'
  cy.get(`#${selector}-${selectorValue}`).check();
})

Cypress.Commands.add('setTextInput', (selector, value) => {
  cy.get(`#${selector}`).type(value);
})

Cypress.Commands.add('setCheckboxInput', selector => {
  cy.get(`#${selector}`).check();
})
Cypress.Commands.add('setSelectInput', (selector, value) => {
  cy.get(`#${selector}`).select(value);
})

Cypress.Commands.add('setRadioInput', selector => {
  cy.get(`#${selector}`).check();
})

Cypress.Commands.add('savePage', fileName => {
  cy.url().then(url => {
    cy.downloadFile(url, 'cypress/pages' , `${fileName}.html`)
  })
})

Refactor to enable cypress to work locally or on circle


HB.OnboardingLibraryRoute = Ember.Route.extend({

  model: function() {
    return Ember.RSVP.hash({
      anime: this.store.find('anime', { 'sort_by': 'user_count', 'sort_reverse': true }),
      manga: this.store.find('manga', { 'sort_by': 'created_at', 'sort_reverse': true }),
      library_entry: this.store.find('library_entry', { 'user_id': this.get('currentUser.id') }),
      manga_library_entry: this.store.find('manga_library_entry', { 'user_id': this.get('currentUser.id') })
    });
  }

});

HB.OnboardingLibraryRoute = Ember.Route.extend({

  model: function() {
    return Ember.RSVP.hash({
      anime: this.store.find('anime', { 'sort_by': 'user_count', 'sort_reverse': true }),
      manga: this.store.find('manga', { 'sort_by': 'created_at', 'sort_reverse': true }),
      libraryEntries: this.store.find('library_entry', { 'user_id': this.get('currentUser.id') }),
      mangaLibraryEntries: this.store.find('manga_library_entry', { 'user_id': this.get('currentUser.id') })
    });
  }

});

Fix onboarding library route model keys


// goalService.getAllGoals();
//
angular.module('sparrowFit')
.service('goalService',function($http){

  this.getAllGoals= function (){
    var allGoals=$http.get('/api/get/goals');
    return allGoals;
  }
  this.getGoal=function(goalID){

    function goalMatchesParam(goal){
      return goal.id === Number(goalID);
    }
    // var requestedGoal= this.getAllGoals()
    // .filter(function(goal){
    //   return goalMatchesParam(goal)
    // }).join('');

    var requestedGoal= this.getAllGoals()
    .find(goalMatchesParam)

    return requestedGoal
  }

  this.addGoal=function(newGoal,callBack){
    // call end point here
    $http.post('/post/goals',newGoal);
    callBack(newGoal);
  };
})

// goalService.getAllGoals();
//
angular.module('sparrowFit')
.service('goalService',function($http){

  this.getAllGoals= function (){
    var allGoals=$http.get('/api/get/goals');
    console.log('allGoals in goalService',allGoals);
   return allGoals;
  }
  this.getGoal=function(goalID){

    function goalMatchesParam(goal){
      return goal.id === Number(goalID);
    }
    // var requestedGoal= this.getAllGoals()
    // .filter(function(goal){
    //   return goalMatchesParam(goal)
    // }).join('');

    var requestedGoal= this.getAllGoals()
    .find(goalMatchesParam)

    return requestedGoal
  }

  this.addGoal=function(newGoal,callBack){
    // call end point here
    $http.post('/post/goals',newGoal);
    callBack(newGoal);
  };
})

Revert Commit to Goals Service


import _ from 'lodash'
import {
  TASK__START,
  TASK__PROGRESS,
  TASK__ERROR,
  TASK__SUCCESS,
  TASK__CLEAR,
} from '../../actions'

const setTaskState = (state, { name, id, ...action }, status, omit) => {
  const currentTaskGroup = state[name] || {}
  const currentTask = currentTaskGroup[id]
  return {
    ...state,
    [name]: {
      ...currentTaskGroup,
      [id]: {
        ..._.omit(currentTask, omit),
        ...action,
        status,
      },
    },
  }
}

export default (state = {}, { type, ...action }) => {
  switch (type) {
    case TASK__START:
      return setTaskState(state, action, 'starting')
    case TASK__PROGRESS:
      return setTaskState(state, action, 'progress')
    case TASK__SUCCESS:
      return setTaskState(state, action, 'success', [
        'payload',
        'successActionType',
      ])
    case TASK__ERROR:
      return setTaskState(state, action, 'error')
    case TASK__CLEAR:
      return _.omit(state, `${action.name}.${action.id}`)
    default:
      return state
  }
}

import _ from 'lodash'
import {
  TASK__PROGRESS,
  TASK__ERROR,
  TASK__SUCCESS,
  TASK__CLEAR,
} from '../../actions'

const setTaskState = (state, { name, id, ...action }, status, omit) => {
  const currentTaskGroup = state[name] || {}
  const currentTask = currentTaskGroup[id]
  return {
    ...state,
    [name]: {
      ...currentTaskGroup,
      [id]: {
        ..._.omit(currentTask, omit),
        ...action,
        status,
      },
    },
  }
}

export default (state = {}, { type, ...action }) => {
  switch (type) {
    case TASK__PROGRESS:
      return setTaskState(state, action, 'progress')
    case TASK__SUCCESS:
      return setTaskState(state, action, 'success', [
        'payload',
        'successActionType',
      ])
    case TASK__ERROR:
      return setTaskState(state, action, 'error')
    case TASK__CLEAR:
      return _.omit(state, `${action.name}.${action.id}`)
    default:
      return state
  }
}

Fix a bug when you could start an already running task


import { ref } from 'config/constants'

function saveToDucks (duck) {
  const duckId = ref.child('ducks').push().key() // not pushing anything,
                                                // returns a reference to
                                                // specific endpoint
}

function saveToUsersDucks (duck, duckId) {}

function saveLikeCount (duckId) {}

function saveDuck (duck) {
  const { duckId, duckPromise } = saveToDucks(duck)

  return Promise.all([
    duckPromise,
    saveToUsersDucks(duck, duckId),
    saveLikeCount(duckId),
  ]).then(() => ({...duck, duckId}))
}

import { ref } from 'config/constants'

function saveToDucks (duck) {
  const duckId = ref.child('ducks').push().key() // not pushing anything,
                                                // returns a reference to
                                                // specific endpoint
    // spread operator creates a brand new obj
    // which has all of the properties of duck
    // as well as our new duckId on it.
    // So it adds duckId to the object.
  const duckPromise = ref.child(`ducks/${duckId}`).set({...duck, duckId})

  return {
    duckId,
    duckPromise
  }
}

function saveToUsersDucks (duck, duckId) {}

function saveLikeCount (duckId) {}

function saveDuck (duck) {
  const { duckId, duckPromise } = saveToDucks(duck)

  return Promise.all([
    duckPromise,
    saveToUsersDucks(duck, duckId),
    saveLikeCount(duckId),
  ]).then(() => ({...duck, duckId}))
}

Complete dependencies, get a hold of db obj


import {PureComponent as Component} from 'react'
import PropTypes from 'prop-types'
import {addEventListener, removeEventListener} from '@shopify/javascript-utilities/events'

const propTypes = {
  event: PropTypes.string,
  capture: PropTypes.bool,
  passive: PropTypes.bool,
  handler: PropTypes.func
}

// see https://github.com/oliviertassinari/react-event-listener/
class EventListener extends Component {
  constructor () {
    super()
    this.attachListener = this.attachListener.bind(this)
    this.detachListener = this.detachListener.bind(this)
  }

  componentDidMount () {
    this.attachListener()
  }

  componentWillUpdate () {
    this.detachListener()
  }

  componentDidUpdate () {
    this.attachListener()
  }

  componentWillUnmount () {
    this.detachListener()
  }

  attachListener () {
    const {event, handler, capture, passive} = this.props
    addEventListener(window, event, handler, {capture, passive})
  }

  detachListener () {
    const {event, handler, capture} = this.props
    removeEventListener(window, event, handler, capture)
  }

  render () {
    return null
  }
}

EventListener.propTypes = propTypes

export default EventListener

import {PureComponent as Component} from 'react'
import PropTypes from 'prop-types'
import {addEventListener, removeEventListener} from '@shopify/javascript-utilities/events'

const propTypes = {
  event: PropTypes.string,
  capture: PropTypes.bool,
  passive: PropTypes.bool,
  handler: PropTypes.func
}

// see https://github.com/oliviertassinari/react-event-listener/
class EventListener extends Component {
  constructor () {
    super()
    this.attachListener = this.attachListener.bind(this)
    this.detachListener = this.detachListener.bind(this)
  }

  componentDidMount () {
    this.attachListener()
  }

  /* istanbul ignore next */
  componentWillUpdate () {
    this.detachListener()
  }

  /* istanbul ignore next */
  componentDidUpdate () {
    this.attachListener()
  }

  componentWillUnmount () {
    this.detachListener()
  }

  attachListener () {
    const {event, handler, capture, passive} = this.props
    addEventListener(window, event, handler, {capture, passive})
  }

  detachListener () {
    const {event, handler, capture} = this.props
    removeEventListener(window, event, handler, capture)
  }

  render () {
    return null
  }
}

EventListener.propTypes = propTypes

export default EventListener

Add ignores for certain lifecycle hooks in EventListener component


"use strict";
var fs = require('fs');
var util = require('util');
var config = require('./config');
var log_path = config.logDir;
var log_name = new Date().toISOString();
var log_stdout = process.stdout;
var log_file;

try {
    log_file = fs.createWriteStream(util.format("%s/%s.log", log_path, log_name), {flags: 'w'}); //__dirname + '/debug.log'
} catch (e){
    process.stderr.write("Exception creating log file write stream: " + util.inspect(e));
}

var date = new Date();

console.log = function(d) {
    if(log_file){
        log_file.write(date.now().toISOString() + ": " + util.format(d) + '\n');
    }
    log_stdout.write(util.format(d) + '\n');
};

"use strict";
var fs = require('fs');
var util = require('util');
var path = require('path');
var config = require('./config');
var log_path = config.logDir;
var log_name = new Date().toISOString();
var log_stdout = process.stdout;
var log_file;

try {
    var log_file_name = util.format("%s/%s.log", log_path, log_name);
    ensureDirectoryExistence(log_file_name);
    log_file = fs.createWriteStream(log_file_name, {flags: 'w'}); //__dirname + '/debug.log'
} catch (e){
    process.stderr.write("Exception creating log file write stream: " + util.inspect(e));
}

var date = new Date();

console.log = function(d) {
    if(log_file){
        log_file.write(date.now().toISOString() + ": " + util.format(d) + '\n');
    }
    log_stdout.write(util.format(d) + '\n');
};

function ensureDirectoryExistence(filePath) {
    var dirname = path.dirname(filePath);
    if (directoryExists(dirname)) {
        return true;
    }
    ensureDirectoryExistence(dirname);
    fs.mkdirSync(dirname);
}

function directoryExists(path) {
    try {
        return fs.statSync(path).isDirectory();
    }
    catch (err) {
        return false;
    }
}

Check that the directory exists before creating log file.


import Realm from 'realm';
import {
  addLineToParent,
  generateUUID,
  getTotal,
} from '../utilities';

export class Transaction extends Realm.Object {
  get isFinalised() {
    return this.status === 'finalised';
  }

  get totalPrice() {
    return getTotal(this.items, 'totalPrice');
  }

  // Adds a TransactionLine, incorporating it into a matching TransactionItem
  addLine(database, transactionLine) {
    addLineToParent(transactionLine, this, () =>
      database.create('TransactionItem', {
        id: generateUUID(),
        item: transactionLine.itemLine.item,
        transaction: this,
      })
    );
  }

  finalise(database, user) {
    this.status = 'finalised';
    if (this.type === 'supplier_invoice') { // If a supplier invoice, add item lines to inventory
      this.enteredBy = user;
      this.items.forEach((transactionItem) => {
        transactionItem.lines.forEach((transactionLine) => {
          const itemLine = transactionLine.itemLine;
          itemLine.packSize = transactionLine.packSize;
          itemLine.numberOfPacks = transactionLine.numberOfPacks;
          itemLine.expiryDate = transactionLine.expiryDate;
          itemLine.batch = transactionLine.batch;
          itemLine.costPrice = transactionLine.costPrice;
          itemLine.sellPrice = transactionLine.sellPrice;
          database.save('ItemLine', itemLine);
          database.save('TransactionLine', transactionLine);
        });
      });
    }
  }
}

import Realm from 'realm';
import {
  addLineToParent,
  generateUUID,
  getTotal,
} from '../utilities';

export class Transaction extends Realm.Object {
  get isFinalised() {
    return this.status === 'finalised';
  }

  get isConfirmed() {
    return this.status === 'confirmed';
  }

  get totalPrice() {
    return getTotal(this.items, 'totalPrice');
  }

  // Adds a TransactionLine, incorporating it into a matching TransactionItem
  addLine(database, transactionLine) {
    addLineToParent(transactionLine, this, () =>
      database.create('TransactionItem', {
        id: generateUUID(),
        item: transactionLine.itemLine.item,
        transaction: this,
      })
    );
  }

  finalise(database, user) {
    if (this.type === 'supplier_invoice') { // If a supplier invoice, add item lines to inventory
      this.enteredBy = user;
      this.items.forEach((transactionItem) => {
        transactionItem.lines.forEach((transactionLine) => {
          const itemLine = transactionLine.itemLine;
          itemLine.packSize = transactionLine.packSize;
          itemLine.numberOfPacks = itemLine.numberOfPacks + transactionLine.numberOfPacks;
          itemLine.expiryDate = transactionLine.expiryDate;
          itemLine.batch = transactionLine.batch;
          itemLine.costPrice = transactionLine.costPrice;
          itemLine.sellPrice = transactionLine.sellPrice;
          database.save('ItemLine', itemLine);
          database.save('TransactionLine', transactionLine);
        });
      });
    }
    this.status = 'finalised';
  }
}

Deal with case that item lines already exist before SI finalised


import $ from 'jquery';
import * as Backbone from 'backbone';

class SearchResultsView extends Backbone.View {

  get el() { return '.content-area.search'; }

  initialize() {
    window.console.log('SearchResultsView initialized!');
  }

}

export default SearchResultsView;

import $ from 'jquery';
import * as Backbone from 'backbone';

class SearchResultsView extends Backbone.View {

  get className() { return 'results'; }

  initialize() {
    window.console.log('SearchResultsView initialized!');
  }

}

export default SearchResultsView;

Build search results view in new div