const Boom = require('boom');

exports.register = function (server, options, next) {
    if (!options) options = {};
    const policies = options.policies || [];

    // General check function
    check = async(user, action, target) => {
        if (!user || !action) return false;

        try {
            // Resolve check function
            let check_fn = action;
            if (!(check_fn instanceof Function)) check_fn = policies[action];
            if (!(check_fn instanceof Function)) {
                server.log(['warning', 'authorize'], {message: 'no policy defined for ' + action});
                return false
            }

            // Test against check_fn
            let result = check_fn(user, target);

            // Support async policies
            if (result instanceof Promise) result = await result;

            // ensure result is true or false only
            return !!result;

        } catch (error) {
            // Log and reject unhandled errors
            server.log(['error', 'authorize'], {action, target, error});
            return false;
        }
    };

    // Adds request.can() decorator
    function can(action, target) {
        return check(this.auth.credentials, action, target);
    }

    server.decorate('request', 'can', can);

    // Adds request.authorize() decorator
    async function authorize(action, target) {
        let result = await check(this.auth.credentials, action, target);
        if (result !== true) throw Boom.unauthorized(action);
        return true;
    }

    server.decorate('request', 'authorize', authorize);

    next();
};

exports.register.attributes = {
    name: 'bak-policy-authorize'
};

const Boom = require('boom');

exports.register = function (server, options, next) {
    if (!options) options = {};
    const policies = options.policies || [];

    // General check function
    check = async(user, action, target) => {
        if (!user || !action) return false;

        try {
            // Resolve check function
            let check_fn = action;
            if (!(check_fn instanceof Function)) check_fn = policies[action];
            if (!(check_fn instanceof Function)) {
                server.log(['warning', 'authorize'], {message: 'no policy defined for ' + action});
                return false
            }

            // Test against check_fn
            let result = check_fn(user, target);

            // Support async policies
            if (result instanceof Promise) result = await result;

            // ensure result is true or false only
            return !!result;

        } catch (error) {
            // Log and reject unhandled errors
            server.log(['error', 'authorize'], {action, target, error});
            return false;
        }
    };

    // Adds request.can() decorator
    function can(action, target) {
        return check(this.auth.credentials && this.auth.credentials.user, action, target);
    }

    server.decorate('request', 'can', can);

    // Adds request.authorize() decorator
    async function authorize(action, target) {
        let result = await check(this.auth.credentials && this.auth.credentials.user, action, target);
        if (result !== true) throw Boom.unauthorized(action);
        return true;
    }

    server.decorate('request', 'authorize', authorize);

    next();
};

exports.register.attributes = {
    name: 'bak-policy-authorize'
};

Use auth.credentials.user for policy checks


function render(world) {
  var rendering = '';
  for (var y = world.boundaries()['y']['min']; y <= world.boundaries()['y']['max']; y++) {
    for (var x = world.boundaries()['x']['min']; x <= world.boundaries()['x']['max']; x++) {
      var cell = world.cell_at(x, y);
      rendering += (cell ? cell.to_char() : ' ').replace(' ', ' ');
    }
    rendering += "
"
  }
  return rendering;
}

$(document).ready(function() {

  var world = new World;
  for (var x = 0; x <= 150; x++) {
    for (var y = 0; y <= 40; y++) {
      world.add_cell(x, y, (Math.random() > 0.2));
    }
  }

  var body = $('body');
  body.html(render(world));

  setInterval(function() {
    var tick_start = new Date();
    world._tick();
    var tick_finish = new Date();
    var tick_time = ((tick_finish-tick_start)/1000).toFixed(3);

    var render_start = new Date();
    var rendered = render(world);
    var render_finish = new Date();
    var render_time = ((render_finish-render_start)/1000).toFixed(3);

    var output = "#"+world.tick;
    output += " - World tick took "+tick_time;
    output += " - Rendering took "+render_time;
    output += "
"+rendered;
    body.html(output);
  });

});

function render(world) {
  var rendering = '';
  for (var y = world.boundaries()['y']['min']; y <= world.boundaries()['y']['max']; y++) {
    for (var x = world.boundaries()['x']['min']; x <= world.boundaries()['x']['max']; x++) {
      var cell = world.cell_at(x, y);
      rendering += (cell ? cell.to_char() : ' ').replace(' ', ' ');
    }
    rendering += "
"
  }
  return rendering;
}

$(document).ready(function() {

  var world = new World;
  for (var x = 0; x <= 150; x++) {
    for (var y = 0; y <= 40; y++) {
      world.add_cell(x, y, (Math.random() > 0.2));
    }
  }

  var body = $('body');
  body.html(render(world));

  setInterval(function() {
    var tick_start = new Date();
    world._tick();
    var tick_finish = new Date();
    var tick_time = ((tick_finish-tick_start)/1000).toFixed(3);

    var render_start = new Date();
    var rendered = render(world);
    var render_finish = new Date();
    var render_time = ((render_finish-render_start)/1000).toFixed(3);

    var output = "#"+world.tick;
    output += " - World tick took "+tick_time;
    output += " - Rendering took "+render_time;
    output += "
"+rendered;
    body.html(output);
  }, 0);

});

Fix implementation for SpiderMonkey (firefox)


import WrapperBuilder from './wrapper';
import { shallow, mount } from 'enzyme';
import React from 'react';

const CheckedFixture = () => (
  <input type="checkbox" defaultChecked value="coffee" />
);

// const NotCheckedFixture = () => (
//   <input type="checkbox" value="coffee" />
// );

describe('Checkbox', () => {
  const methodNames = ['shallow', 'mount'];
  [shallow, mount].forEach((renderMethod, i) => {
    let checkedInput;
     // notCheckedInput;
    before(() => {
      checkedInput = WrapperBuilder(renderMethod(<CheckedFixture />));
      // notCheckedInput = WrapperBuilder(renderMethod(<NotCheckedFixture />));
    });

    context(methodNames[i], () => {
      it(`should be checked`, () => {
        checkedInput.checked().should.be.true();
      });
    });

  });
});

import WrapperBuilder from './wrapper';
import { shallow, mount } from 'enzyme';
import React from 'react';

const CheckedFixture = () => (
  <input type="checkbox" defaultChecked value="coffee" />
);

const NotCheckedFixture = () => (
  <input type="checkbox" value="coffee" />
);

describe('Checkbox', () => {
  const methodNames = ['shallow', 'mount'];
  [shallow, mount].forEach((renderMethod, i) => {
    let checkedInput, notCheckedInput;
    before(() => {
      checkedInput = WrapperBuilder(renderMethod(<CheckedFixture />));
      notCheckedInput = WrapperBuilder(renderMethod(<NotCheckedFixture />));
    });

    context(methodNames[i], () => {
      it(`should be checked`, () => {
        checkedInput.checked().should.be.true();
      });

      it(`should NOT be checked`, () => {
        notCheckedInput.checked().should.be.false();
      });
    });

  });
});

Check if checkbox is not checked.


import mongodb from 'mongodb'
import { config } from './config'

const MongoClient = mongodb.MongoClient

const db = null

// WIP: TODO: Find better way to connect to mongoDB
const getDB = async () => {
  if (db) {
    return db
  }

  try {
    const client = await MongoClient.connect(config.mongo.url)
    return client.db()
  } catch (err) {
    if (err) throw Error(err)
    return
  }
}

exports.extractPayloadIntoChunks = async (resource) => {
  try {
    const db = await getDB()

    const bucket = new mongodb.GridFSBucket(db)

    const stream = bucket.openUploadStream()

    stream.on('error', (err) => {
      throw Error(err)
    })
    .on('finish', (doc) => {
      if (!doc) {
        throw new Error('GridFS create failed')
      }

      return doc._id
    })
    stream.end(resource)
  } catch (err) {
    if (err) {
      console.log('error: ', err)
    }
  }
}

import mongodb from 'mongodb'
import { connectionDefault } from './config'

exports.extractPayloadIntoChunks = (resource) => {
  return new Promise((resolve, reject) => {
    const bucket = new mongodb.GridFSBucket(connectionDefault.client.db())
    const stream = bucket.openUploadStream()

    stream.on('error', (err) => {
      return reject(err)
    })
    .on('finish', (doc) => {
      if (!doc) {
        return reject('GridFS create failed')
      }

      return resolve(doc._id)
    })
    stream.end(resource)
  })
}

Refactor function to return a promise instead of a callback


import React from 'react';
import { storiesOf } from '@storybook/react';
import withReadme from 'storybook-readme/with-readme';
import Readme from './readme.md';

import Accordion from './Accordion';

storiesOf('Accordion', module)
  .addDecorator(withReadme(Readme))
  .add('with defaults', () => (
    <Accordion label="Hello">
      Content
    </Accordion>
  ));

import React from 'react';
import { storiesOf } from '@storybook/react'; // eslint-disable-line import/no-extraneous-dependencies
import withReadme from 'storybook-readme/with-readme'; // eslint-disable-line import/no-extraneous-dependencies
import Readme from './readme.md';

import Accordion from './Accordion';

storiesOf('Accordion', module)
  .addDecorator(withReadme(Readme))
  .add('with defaults', () => (
    <Accordion label="Hello">
      Content
    </Accordion>
  ));

Fix storybook story lint errors


'use strict';

/**
 * Module dependencies.
 */
var cron = require('cron'),
	pingdom = require('pingdom-api');

exports.init = function(){
	console.log('initttttttt');
};

'use strict';

/**
 * Module dependencies.
 */
var CronJob = require('cron').CronJob,
	pingdom = require('pingdom-api');

exports.init = function(){

	var job = new CronJob({
	  cronTime: '0 */1 * * * *',
	  onTick: function() {
	    console.log('Tick!');
	  },
	  start: false,
	  timeZone: 'Europe/Amsterdam'
	});
 	// job.start();
};

Add a cronjob that runs every minute but dont start it yet


var $ = require('wetfish-basic');

var animate =
{
    status: false,

    init: function()
    {

    },

    start: function()
    {
        $('.workspace').addClass('highlight-content');
    },

    stop: function()
    {
        $('.workspace').removeClass('highlight-content');
    }
};

module.exports = animate;

var $ = require('wetfish-basic');
var storage = require('../app/storage');

var animate =
{
    active: false,
    element: false,

    init: function()
    {
        // Save the default element notification text
        animate.defaultText = $('.menu .animate .element').el[0].textContent;

        $('body').on('click', '.workspace .content, .workspace .content *', function()
        {
            var element = this;

            if(!$(element).hasClass('content'))
            {
                element = $(this).parents('.content').el[0];
            }

            if(animate.active)
            {
                animate.element = element;
                animate.populate();
                animate.menu();
            }
        });
    },

    // Populate data from saved object
    populate: function()
    {
        var id = $(animate.element).attr('id');
        var object = storage.getObject(id);

        var  desc = object.desc || 'untitled ' + object.type;
        $('.menu .animate .element').text(desc);
    },

    // Display menu options based on the current animation state
    menu: function()
    {
        if(animate.element)
        {
            $('.element-selected').removeClass('hidden');
        }
        else
        {
            $('.element-selected').addClass('hidden');
        }
    },

    start: function()
    {
        $('.workspace').addClass('highlight-content');
        animate.active = true;
    },

    stop: function()
    {
        $('.workspace').removeClass('highlight-content');
        animate.active = false;
        animate.element = false;

        $('.menu .animate .element').text(animate.defaultText);
    }
};

module.exports = animate;

Allow selecting elements for animation


var _ = require('lodash');

/**
 * Sets options
 * @param {Object} [options]
 * @param {String[]} [options.ignoreAttributes]
 * @param {String[]} [options.compareAttributesAsJSON]
 * @param {Boolean} [options.ignoreWhitespaces=true]
 * @param {Boolean} [options.ignoreComments=true]
 * @param {Boolean} [options.ignoreClosingTags=false]
 * @param {Boolean} [options.ignoreDuplicateAttributes=false]
 * returns {Object}
 */
 module.exports = function (options) {
    if (typeof options === 'string') {
        if (options === 'bem') {
            options = {
                // ignore generated attributes
                ignoreAttributes: ['id', 'for', 'aria-labelledby', 'aria-describedby'],
                compareAttributesAsJSON: [
                    'data-bem',
                    { name: 'onclick', isFunction: true },
                    { name: 'ondblclick', isFunction: true }
                ]
            };
        } else {
            console.error(options.bold.red + ' is an invalid preset name. Use ' + 'bem'.bold.green + ' instead.');
            process.exit(1);
        }
    }

    return _.defaults(options || {}, {
        ignoreAttributes: [],
        compareAttributesAsJSON: [],

        ignoreWhitespaces: true,
        ignoreComments: true,

        ignoreEndTags: false,
        ignoreDuplicateAttributes: false
    });
};

var _ = require('lodash');

/**
 * Sets options
 * @param {Object} [options]
 * @param {String[]} [options.ignoreAttributes]
 * @param {String[]} [options.compareAttributesAsJSON]
 * @param {Boolean} [options.ignoreWhitespaces=true]
 * @param {Boolean} [options.ignoreComments=true]
 * @param {Boolean} [options.ignoreClosingTags=false]
 * @param {Boolean} [options.ignoreDuplicateAttributes=false]
 * returns {Object}
 */
 module.exports = function (options) {
    if (typeof options === 'string') {
        if (options === 'bem') {
            options = {
                // ignore generated attributes
                ignoreAttributes: ['id', 'for', 'aria-labelledby', 'aria-describedby'],
                compareAttributesAsJSON: [
                    'data-bem',
                    { name: 'onclick', isFunction: true },
                    { name: 'ondblclick', isFunction: true }
                ],
                ignoreComments: false
            };
        } else {
            console.error(options.bold.red + ' is an invalid preset name. Use ' + 'bem'.bold.green + ' instead.');
            process.exit(1);
        }
    }

    return _.defaults(options || {}, {
        ignoreAttributes: [],
        compareAttributesAsJSON: [],

        ignoreWhitespaces: true,
        ignoreComments: true,

        ignoreEndTags: false,
        ignoreDuplicateAttributes: false
    });
};

Fix BEM preset; ignoreComments --> false


module.exports = [
  {
    collection: 'attachments',
    spec: { key: 1 },
    options: { unique: true }
  },
  {
    collection: 'entries',
    spec: { locationId: 1 },
    options: {}
  },
  {
    collection: 'events',
    spec: { time: 1 },
    options: {}
  },
  {
    collection: 'events',
    spec: { locationId: 1 },
    options: {}
  },
  {
    collection: 'locations',
    spec: { geom: '2dsphere' },
    options: {}
  },
  {
    collection: 'locations',
    spec: { layer: 1 },
    options: {}
  },
  {
    collection: 'locations',
    spec: { status: 1, type: 1 },
    options: {}
  },
  {
    // Text index
    collection: 'locations',
    spec: {
      text1: 'text', // primary
      text2: 'text' //  secondary
    },
    options: {
      weights: {
        text1: 3,
        text2: 1
      },
      name: 'TextIndex'
    }
  },
  {
    collection: 'users',
    spec: { email: 1 },
    options: { unique: true }
  },
  {
    collection: 'users',
    spec: { name: 1 },
    options: { unique: true }
  }
]

module.exports = [
  {
    collection: 'attachments',
    spec: { key: 1 },
    options: { unique: true }
  },
  {
    // Ensure same upload is not added twice
    collection: 'attachments',
    spec: { filepath: 1 },
    options: { unique: true }
  },
  {
    collection: 'entries',
    spec: { locationId: 1 },
    options: {}
  },
  {
    collection: 'events',
    spec: { time: 1 },
    options: {}
  },
  {
    collection: 'events',
    spec: { locationId: 1 },
    options: {}
  },
  {
    collection: 'locations',
    spec: { geom: '2dsphere' },
    options: {}
  },
  {
    collection: 'locations',
    spec: { layer: 1 },
    options: {}
  },
  {
    collection: 'locations',
    spec: { status: 1, type: 1 },
    options: {}
  },
  {
    // Text index
    collection: 'locations',
    spec: {
      text1: 'text', // primary
      text2: 'text' //  secondary
    },
    options: {
      weights: {
        text1: 3,
        text2: 1
      },
      name: 'TextIndex'
    }
  },
  {
    collection: 'users',
    spec: { email: 1 },
    options: { unique: true }
  },
  {
    collection: 'users',
    spec: { name: 1 },
    options: { unique: true }
  }
]

Index for attachment filepath to prevent doubles


/**
 * DashboardController
 *
 * @description :: Server-side logic for managing Dashboards
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

module.exports = {
    index: function (req, res) {
        if(!req.user.hasPermission('system.dashboard.view')) {
            res.forbidden(req.__('Error.Authorization.NoRights'));
        } else {
            var widgetContents = [];

            sails.app.customWidgets.forEach(function(widget) {
                var controller = widget.controller;
                var action = widget.action;
                var result = sails.controllers[controller][action](req);
                if(result) {
                    result.owner = widget;
                    widgetContents.push(result);
                }
            });
            res.view({ widgets: widgetContents });
        }
    }
};

/**
 * DashboardController
 *
 * @description :: Server-side logic for managing Dashboards
 * @help        :: See http://links.sailsjs.org/docs/controllers
 */

module.exports = {
    index: function (req, res) {
        if(!req.user.hasPermission('system.dashboard.view')) {
            res.forbidden(req.__('Error.Authorization.NoRights'));
        } else {
            var widgetContents = [];

            sails.app.customWidgets.forEach(function(widget) {
                var controller = widget.controller.toLowerCase();
                var action = widget.action;
                var result = sails.controllers[controller][action](req);
                if(result) {
                    result.owner = widget;
                    widgetContents.push(result);
                }
            });
            res.view({ widgets: widgetContents });
        }
    }
};

Use identity instead of global id.


class TestBackend {
  constructor(manager) {
    this.actions = manager.getActions();
  }

  setup() {
    this.didCallSetup = true;
  }

  teardown() {
    this.didCallTeardown = true;
  }

  simulateBeginDrag(sourceIds, options) {
    this.actions.beginDrag(sourceIds, options);
  }

  simulatePublishDragSource() {
    this.actions.publishDragSource();
  }

  simulateHover(targetIds, options) {
    this.actions.hover(targetIds, options);
  }

  simulateDrop() {
    this.actions.drop();
  }

  simulateEndDrag() {
    this.actions.endDrag();
  }
}

export default function createBackend(manager) {
  return new TestBackend(manager);
}

import noop from 'lodash/utility/noop';

class TestBackend {
  constructor(manager) {
    this.actions = manager.getActions();
  }

  setup() {
    this.didCallSetup = true;
  }

  teardown() {
    this.didCallTeardown = true;
  }

  connectDragSource() {
    return noop;
  }

  connectDragPreview() {
    return noop;
  }

  connectDropTarget() {
    return noop;
  }

  simulateBeginDrag(sourceIds, options) {
    this.actions.beginDrag(sourceIds, options);
  }

  simulatePublishDragSource() {
    this.actions.publishDragSource();
  }

  simulateHover(targetIds, options) {
    this.actions.hover(targetIds, options);
  }

  simulateDrop() {
    this.actions.drop();
  }

  simulateEndDrag() {
    this.actions.endDrag();
  }
}

export default function createBackend(manager) {
  return new TestBackend(manager);
}

Add noop connect* methods to the test backend


export function textViewBuilder(node) {
  var view = document.createElement("div");
  var textView = document.createElement("div");
  textView.style.whiteSpace = "pre-wrap";

  view.appendChild(textView);

  if (node.value === null || node.value === undefined) {
    textView.textContent = "";
  } else {
    textView.textContent = node.value.toString();
  }

  view.lynxGetValue = function () {
    return textView.textContent;
  };

  return view;
}

export function textViewBuilder(node) {
  var view = document.createElement("div");
  var textView = document.createElement("pre");

  view.appendChild(textView);

  if (node.value === null || node.value === undefined) {
    textView.textContent = "";
  } else {
    textView.textContent = node.value.toString();
  }

  view.lynxGetValue = function () {
    return textView.textContent;
  };

  return view;
}

Revert text builder to 'pre'


'use strict';

import emptyFunction from '../utils/empty-function';

function initializeShopifyPlatform(context, currentConfig, hull) {

  const { customerId, accessToken, callbackUrl } = currentConfig.get();

  if (!customerId && hull.currentUser()) {
      hull.api('services/shopify/login', { return_to: document.location.href }).then(function(r) {
        // If the platform has multipass enabled and we are NOT inside the customizer
        // we can log the customer in without knowing his password.
        if (r.auth === 'multipass' && !(callbackUrl || "").match('__hull_proxy__')) {
          let l = 'https://' + document.location.host + '/account/login/multipass/' + r.token;
          window.location = l;
        } else {
          hull.logout();
        }
      });
  } else if (/^[0-9]+$/.test(customerId) && !accessToken) {
    hull.api('services/shopify/customers/' + customerId, 'put').then(function() {
      document.location.reload();
    });
  }

  Hull.on('hull.user.logout', function() {
    document.location = '/account/logout';
  });
}

function getPlatformInitializer(platform) {
  if (platform.type === 'platforms/shopify_shop') {
    return initializeShopifyPlatform;
  } else {
    return emptyFunction;
  }
}

function initializePlatform(context, currentConfig, hull) {
  const initializer = getPlatformInitializer(context.app);

  return initializer(context, currentConfig, hull);
}

export default initializePlatform;

'use strict';

import emptyFunction from '../utils/empty-function';

function initializeShopifyPlatform(context, currentConfig, hull) {

  const { customerId, accessToken, callbackUrl } = currentConfig.get();

  if (!customerId && hull.currentUser()) {
      hull.api('services/shopify/login', { return_to: document.location.href }).then(function(r) {
        // If the platform has multipass enabled and we are NOT inside the customizer
        // we can log the customer in without knowing his password.
        if (r.auth === 'multipass') {
          if (!(callbackUrl || "").match('__hull_proxy__')) {
            let l = 'https://' + document.location.host + '/account/login/multipass/' + r.token;
            window.location = l;
          }
        } else {
          hull.logout();
        }
      });
  } else if (/^[0-9]+$/.test(customerId) && !accessToken) {
    hull.api('services/shopify/customers/' + customerId, 'put').then(function() {
      document.location.reload();
    });
  }

  Hull.on('hull.user.logout', function() {
    document.location = '/account/logout';
  });
}

function getPlatformInitializer(platform) {
  if (platform.type === 'platforms/shopify_shop') {
    return initializeShopifyPlatform;
  } else {
    return emptyFunction;
  }
}

function initializePlatform(context, currentConfig, hull) {
  const initializer = getPlatformInitializer(context.app);

  return initializer(context, currentConfig, hull);
}

export default initializePlatform;

Fix prevent multipass inside customizer


const BasicCard = require('../BasicCard');

class Strike extends BasicCard {
	constructor(suit, number) {
		super('strike', suit, number);
	}
}

module.exports = Strike;

const BasicCard = require('../BasicCard');
const Phase = require('../../core/Player/Phase');

const DamageStruct = require('../../driver/DamageStruct');

class Strike extends BasicCard {
	constructor(suit, number) {
		super('strike', suit, number);
	}

	async isAvailable(source) {
		return source && source.getPhase() === Phase.Play;
	}

	async targetFilter(selected, target, source) {
		if (selected.length > 0 || !target) {
			return false;
		}

		const driver = target.getDriver();
		if (!driver) {
			return false;
		}

		if (!source) {
			return true;
		}

		if (source === target) {
			return false;
		}

		const inRange = await driver.isInAttackRange(source, target);
		return inRange;
	}

	async targetFeasible(selected) {
		return selected.length === 1;
	}

	async effect(driver, effect) {
		const damage = new DamageStruct(effect.from, effect.to, 1);
		driver.damage(damage);
	}
}

module.exports = Strike;

Add a simple version of strike


'use strict';

angular.module( 'ngynServerConnection' )
  .value( 'defaultResponseInterceptors', {
    jsonNetStripper: function( hubName, methodName, response ) {
      if ( response.$values ) {
        return response.$values;
      }

      return response;
    }
  } );

'use strict';

angular.module( 'ngynServerConnection' )
  .value( 'defaultResponseInterceptors', {
    jsonNetStripper: function( hubName, methodName, response ) {
      if ( response && response.$values ) {
        return response.$values;
      }

      return response;
    }
  } );

Fix issue dealing with empty responses in response interceptor


/**
 * Created by ronyadgar on 29/11/2015.
 */

var heapdump = require('heapdump');
var logger = require('./logger/logger')(module);
var fs = require('fs');
var config = require('./../common/Configuration');
var path = require('path');

module.exports = (function(){
    var timeInterval = config.get('heapDumpParams').timeInterval || '9000000';
    var windowSize = config.get('heapDumpParams').windowSize || '3';
    var rootFolderPath = config.get('rootFolderPath');
    var enabled = config.get('heapDumpParams').enabled;
    var listOfHeapDumpFiles = [];
    if (enabled) {
        setInterval(function () {
            var filename = Date.now() + '.heapsnapshot';
            heapdump.writeSnapshot(path.join(rootFolderPath, filename), function (err, filename) {
                if (err) {
                    logger.error("Failed to write snapshot in " + filename + ": " + err);
                }
                else {
                    if (listOfHeapDumpFiles.length === windowSize) {
                        var fileToDelete = listOfHeapDumpFiles.shift();
                        fs.unlink(fileToDelete, function (err) {
                            if (err) {
                                logger.error("Failed to delete " + fileToDelete + ": " + err);
                            }
                            else {
                                logger.info("Successfully deleted " + fileToDelete);
                            }
                        });

                    }
                    listOfHeapDumpFiles.push(filename);
                    logger.info("Successfully wrote snapshot to " + filename);
                }
            });
        }, timeInterval);
    }
})();

/**
 * Created by ronyadgar on 29/11/2015.
 */

var heapdump = require('heapdump');
var logger = require('./logger/logger')(module);
var fs = require('fs');
var config = require('./../common/Configuration');
var path = require('path');
var hostname = require('../common/utils/hostname');

module.exports = (function(){
    var timeInterval = config.get('heapDumpParams').timeInterval || '9000000';
    var windowSize = config.get('heapDumpParams').windowSize || '3';
    var rootFolderPath = config.get('rootFolderPath');
    var enabled = config.get('heapDumpParams').enabled;
    var listOfHeapDumpFiles = [];
    if (enabled) {
        setInterval(function () {
            var filename = Date.now() + '.heapsnapshot';
            heapdump.writeSnapshot(path.join(rootFolderPath, hostname + "_" + filename), function (err, filename) {
                if (err) {
                    logger.error("Failed to write snapshot in " + filename + ": " + err);
                }
                else {
                    if (listOfHeapDumpFiles.length === windowSize) {
                        var fileToDelete = listOfHeapDumpFiles.shift();
                        fs.unlink(fileToDelete, function (err) {
                            if (err) {
                                logger.error("Failed to delete " + fileToDelete + ": " + err);
                            }
                            else {
                                logger.info("Successfully deleted " + fileToDelete);
                            }
                        });

                    }
                    listOfHeapDumpFiles.push(filename);
                    logger.info("Successfully wrote snapshot to " + filename);
                }
            });
        }, timeInterval);
    }
})();

Add machine name to heap dump file name


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

/**
 * Responsible for quality control
 */
export class QualityControl {

   /**
    * Creates an quality control instance
    */
    constructor(context, blob) {
        this.context = context;
        this.blob = blob;
        this.audioBuffer;
    }

   /**
    * Checks if sound is of good quality: not too short or silent
    */
    async isQualitySound() {
        const blobArrayBuffer = await this.blob.arrayBuffer();
        this.audioBuffer = await this.context.decodeAudioData(blobArrayBuffer);

        const qualityResult = {
            success: true,
            errorMessage: '',
        };

        const audioResult = this.soundCheck();

        if (this.audioBuffer.duration < 2.0) {
            qualityResult.success = false;
            qualityResult.errorMessage += 'Audio recording failed: recording was too short. Try again';
        } else if (audioResult) {
            qualityResult.success = false;
            qualityResult.errorMessage += audioResult;
        }

        return qualityResult;
    }
}

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

/**
 * Responsible for quality control
 */
export class QualityControl {

   /**
    * Creates an quality control instance
    */
    constructor(context, blob) {
        this.context = context;
        this.blob = blob;
        this.audioBuffer;
    }

   /**
    * Checks if sound is of good quality: not too short or silent
    */
    async isQualitySound() {
        const blobArrayBuffer = await this.blob.arrayBuffer();
        this.audioBuffer = await this.context.decodeAudioData(blobArrayBuffer);

        const qualityResult = {
            success: true,
            errorMessage: '',
        };

        if (this.audioBuffer.duration < 2.0) {
            qualityResult.success = false;
            qualityResult.errorMessage += 'Audio recording failed: recording was too short. Try again';
        }

        return qualityResult;
    }
}

Move audio check code for another pull request


'use strict';

const { EventEmitter } = require('events');

const logger = require('./logger')('server-impl.js');
const migrator = require('../migrator');
const getApp = require('./app');

const { startMonitoring } = require('./metrics');
const { createStores } = require('./db');
const { createOptions } = require('./options');
const User = require('./user');
const AuthenticationRequired = require('./authentication-required');

function createApp(options) {
    // Database dependecies (statefull)
    const stores = createStores(options);
    const eventBus = new EventEmitter();

    const config = Object.assign(
        {
            stores,
            eventBus,
        },
        options
    );

    const app = getApp(config);
    startMonitoring(options.serverMetrics, eventBus);

    return new Promise(resolve => {
        const server = app.listen(
            { port: options.port, host: options.host },
            () => {
                logger.info(`Unleash started on port ${server.address().port}`);
                resolve({ app, server, eventBus });
            }
        );
    });
}

function start(opts) {
    const options = createOptions(opts);

    return migrator({ databaseUrl: options.databaseUrl })
        .catch(err => logger.error('failed to migrate db', err))
        .then(() => createApp(options))
        .catch(err => logger.error('failed creating app', err));
}

module.exports = {
    start,
    User,
    AuthenticationRequired,
};

'use strict';

const { EventEmitter } = require('events');

const logger = require('./logger')('server-impl.js');
const migrator = require('../migrator');
const getApp = require('./app');

const { startMonitoring } = require('./metrics');
const { createStores } = require('./db');
const { createOptions } = require('./options');
const User = require('./user');
const AuthenticationRequired = require('./authentication-required');

function createApp(options) {
    // Database dependecies (statefull)
    const stores = createStores(options);
    const eventBus = new EventEmitter();

    const config = Object.assign(
        {
            stores,
            eventBus,
        },
        options
    );

    const app = getApp(config);
    startMonitoring(options.serverMetrics, eventBus);

    const server = app.listen({ port: options.port, host: options.host }, () =>
        logger.info(`Unleash started on port ${server.address().port}`)
    );

    return new Promise((resolve, reject) => {
        server.on('listening', () => resolve({ app, server, eventBus }));
        server.on('error', reject);
    });
}

function start(opts) {
    const options = createOptions(opts);

    return migrator({ databaseUrl: options.databaseUrl })
        .catch(err => logger.error('failed to migrate db', err))
        .then(() => createApp(options));
}

module.exports = {
    start,
    User,
    AuthenticationRequired,
};

Clean up using servers listening and error events


import { createAction } from 'redux-actions'
import { createEvent as createAPI, showEvent as showAPI } from '../api/Event'
import Actions from '../constants/Actions'
import errorUrls from '../constants/ErrorUrls'
import ActionDispatch from '../utils/ActionDispatch'

export const createEvent = createAction(Actions.Event.createEvent, createAPI)

export const showEvent = (id) => {
  return ActionDispatch.executeApi(showAPI, id, createEvent, errorUrls.pageNotFound)
}

import { createAction } from 'redux-actions'
import { createEvent as createAPI, showEvent as showAPI } from '../api/Event'
import Actions from '../constants/Actions'
import errorUrls from '../constants/ErrorUrls'
import ActionDispatch from '../utils/ActionDispatch'

export const createEvent = createAction(Actions.Event.createEvent, createAPI)

export const showEvent = (id) => {
  return ActionDispatch.executeApi(showAPI, id, createAction(Actions.Event.createEvent), errorUrls.pageNotFound)
}

Fix called create API when show API success


module.exports = {
  borderWidth: 5,
  strokeWidth: 0.1,
  // in percentage of borderWidth
  outlineWidth: 0.2,
  outlineStyle: "#FFF",

  /**
   * Provide a custom stroke function that draws a fat white line THEN a
   * narrower colored line on top.
   */
  _stroke: function (ctx) {
    var myScale = this.scaleX;
    var outline = this._outlineWidth();
    function scale(x) {
      return Math.round(x) / myScale;
    }
    ctx.lineWidth = scale(this.borderWidth + outline);
    ctx.strokeStyle = this.outlineStyle;
    ctx.stroke();

    ctx.lineWidth = scale(this.borderWidth - outline);
    ctx.strokeStyle = this.stroke;
    ctx.stroke();
  },

  _outlineWidth: function () {
    return Math.max(1, Math.round(this.borderWidth * this.outlineWidth));
  },

  /**
   * This is primarily used to get a bounding rect for drawing borders and
   * doing a hit-test for mouse events. We extend the size by the borderWidth
   * cause rectangles and axis lines (horiz or vert) have half their
   * borderWidth outside the actual bounding rect of the shape.
   */
  _calculateCurrentDimensions: function (shouldTransform) {
    var p = this.callParent(shouldTransform);
    var b = this.borderWidth + this._outlineWidth();
    return { x: p.x + b, y: p.y + b };
  },
};

module.exports = {
  borderWidth: 5,
  strokeWidth: 0.1,
  // in percentage of borderWidth
  outlineWidth: 0.2,
  outlineStyle: "#FFF",

  /**
   * Provide a custom stroke function that draws a fat white line THEN a
   * narrower colored line on top.
   */
  _renderStroke: function (ctx) {
    var myScale = this.scaleX;
    var outline = this._outlineWidth();
    function scale(x) {
      return Math.round(x) / myScale;
    }
    ctx.lineWidth = scale(this.borderWidth + outline);
    ctx.strokeStyle = this.outlineStyle;
    ctx.stroke();

    ctx.lineWidth = scale(this.borderWidth - outline);
    ctx.strokeStyle = this.stroke;
    ctx.stroke();
  },

  _outlineWidth: function () {
    return Math.max(1, Math.round(this.borderWidth * this.outlineWidth));
  },

  /**
   * This is primarily used to get a bounding rect for drawing borders and
   * doing a hit-test for mouse events. We extend the size by the borderWidth
   * cause rectangles and axis lines (horiz or vert) have half their
   * borderWidth outside the actual bounding rect of the shape.
   */
  _calculateCurrentDimensions: function (shouldTransform) {
    var p = this.callParent(shouldTransform);
    var b = this.borderWidth + this._outlineWidth();
    return { x: p.x + b, y: p.y + b };
  },
};

Change custom stroke override method


var nullEvents = require('./nullEvents.js');

module.exports = createDocumentEvents();

function createDocumentEvents() {
  if (typeof window === undefined) {
    return nullEvents;
  }

  return {
    on: on,
    off: off
  };
}

function on(eventName, handler) {
  window.addEventListener(eventName, handler);
}

function off(eventName, handler) {
  window.removeEventListener(eventName, handler);
}

var nullEvents = require('./nullEvents.js');

module.exports = createDocumentEvents();

function createDocumentEvents() {
  if (typeof window === 'undefined') {
    return nullEvents;
  }

  return {
    on: on,
    off: off
  };
}

function on(eventName, handler) {
  window.addEventListener(eventName, handler);
}

function off(eventName, handler) {
  window.removeEventListener(eventName, handler);
}

Correct check for undefined variable


'use strict';

var assert       = require('assert')
var handlebars   = require('handlebars')
var cssInjector  = require('../wrappers/cssInjector')
var assetManager = require('./assetManager')

/**
 * Class to handle css and html template for a layers popup generation
 * Css is injected into the dom and a function is returned via 'present'
 * that can be used by the map on a per geosjon feature basis
 */
class PopupPresenter {

  /**
   * Creates a template function from config and injects given layer css
   * file into the dom
   */
  constructor(config) {
    assert.equal(typeof (config), 'object', '\'config\' arg must be an object')

    var templateContent = assetManager.assets.templates[config.template]
    this.template = handlebars.compile(templateContent)

    var css = assetManager.assets.css[config.css]
    cssInjector(css)
  }

  /**
   * Renders properties into a template string using template function
   * created in the constructor
   * @param {object} properties
   * @return {string}
   */
  present(properties) {
    assert.equal(typeof (properties), 'object', '\'properties\' arg must be an object')
    return this.template(properties)
  }
}

module.exports = (config) => new PopupPresenter(config)

'use strict';

var assert       = require('assert')
var handlebars   = require('handlebars')
var cssInjector  = require('../wrappers/cssInjector')
var assetManager = require('./assetManager')()

/**
 * Class to handle css and html template for a layers popup generation
 * Css is injected into the dom and a function is returned via 'present'
 * that can be used by the map on a per geosjon feature basis
 */
class PopupPresenter {

  /**
   * Creates a template function from config and injects given layer css
   * file into the dom
   */
  constructor(config) {
    assert.equal(typeof (config), 'object', '\'config\' arg must be an object')

    var templateContent = assetManager.assets.templates[config.template]
    this.template = handlebars.compile(templateContent)

    var css = assetManager.assets.css[config.css]
    cssInjector(css)
  }

  /**
   * Renders properties into a template string using template function
   * created in the constructor
   * @param {object} properties
   * @return {string}
   */
  present(properties) {
    assert.equal(typeof (properties), 'object', '\'properties\' arg must be an object')
    return this.template(properties)
  }
}

module.exports = (config) => new PopupPresenter(config)

Fix assetManager not being instantiated


document.addEventListener("turbolinks:load", function() {
  function inventoryButtonClickHandler(e) {
    e.preventDefault();
    let formInputs = document.getElementById('form-inputs');
    time = new Date().getTime()
    regexp = new RegExp(inventoryButton.dataset.id, 'g')
    formInputs.insertAdjacentHTML('beforebegin', inventoryButton.dataset.fields.replace(regexp, time))
  }
  let inventoryButton = document.getElementById('add-component-button');
  if (inventoryButton) {
    inventoryButton.addEventListener('click', inventoryButtonClickHandler, false);
  }
})

document.addEventListener("turbolinks:load", function() {
  function inventoryButtonClickHandler(e) {
    e.preventDefault();
    var formInputs = document.getElementById('form-inputs');
    time = new Date().getTime()
    regexp = new RegExp(inventoryButton.dataset.id, 'g')
    formInputs.insertAdjacentHTML('beforebegin', inventoryButton.dataset.fields.replace(regexp, time))
  }
  var inventoryButton = document.getElementById('add-component-button');
  if (inventoryButton) {
    inventoryButton.addEventListener('click', inventoryButtonClickHandler, false);
  }
})

Switch back to ES5 variable syntax.


import Ember from 'ember';
import md5 from 'md5';

export default Ember.Component.extend({
  tagName: 'img',
  attributeBindings: ['src', 'alt', 'title'],
  classNames: ['gravatar-image'],
  size: 250,
  email: '',
  title: '',
  defaultImage: '',
  secure: true,

  src: Ember.computed('email', 'size', 'default', function() {
    var email = this.get('email');
    var size = this.get('size');
    var def = this.get('defaultImage');
    var secure = this.get('secure');
    var protocol = secure ? 'https' : 'http';

    return protocol + '://www.gravatar.com/avatar/' + md5(email) + '?s=' + size + '&d=' + def;
  })
});

import Ember from 'ember';
import md5 from 'md5';

export default Ember.Component.extend({
  tagName: 'img',
  attributeBindings: ['src', 'alt', 'title'],
  classNames: ['gravatar-image'],
  size: 250,
  email: '',
  title: '',
  defaultImage: '',
  secure: true,
  retina: false,

  src: Ember.computed('email', 'imageSize', 'default', function() {
    var email = this.get('email');
    var imageSize = this.get('imageSize');
    var def = this.get('defaultImage');
    var secure = this.get('secure');
    var protocol = secure ? 'https' : 'http';

    return protocol + '://www.gravatar.com/avatar/' + md5(email) + '?s=' + imageSize + '&d=' + def;
  }),

  imageSize: Ember.computed('size', function() {
    var size = this.get('size');
    return this.get('retina') ? (size * 2) : size;
  })
});

Add support for retina images


module.exports.unit = {
  environment: 'node',
  rootPath: process.cwd(),
  sources: [
    'lib/**/*.js'
  ],
  tests: [
    'test/**/*.js'
  ],
  extensions: [
    require('buster-istanbul')
  ],
  'buster-istanbul': {
    outputDirectory: '.bob/report/coverage/buster-istanbul/'
  }
};

module.exports.unit = {
  environment: 'node',
  rootPath: process.cwd(),
  sources: [
    'lib/**/*.js'
  ],
  tests: [
    'test/**/*.js'
  ],
  extensions: [
    require('buster-istanbul')
  ],
  'buster-istanbul': {
    outputDirectory: '.bob/report/coverage/buster-istanbul/',
    formats: ['text', 'lcov']
  }
};

Add lcov report to buster-istanbul coverage.


import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { visit, currentURL } from '@ember/test-helpers';

import { setupPretender } from 'skylines/tests/helpers/setup-pretender';

module('Acceptance | index', function(hooks) {
  setupApplicationTest(hooks);
  setupPretender(hooks);

  hooks.beforeEach(async function(assert) {
    await visit('/');
    assert.equal(currentURL(), '/');
  });

  test('shows a welcome message', function(assert) {
    assert.dom('[data-test-welcome-message]').exists();
  });
});

import { module, test } from 'qunit';
import { setupApplicationTest } from 'ember-qunit';
import { visit, currentURL } from '@ember/test-helpers';

import { setupPolly } from 'skylines/tests/helpers/setup-polly';

module('Acceptance | index', function(hooks) {
  setupApplicationTest(hooks);
  setupPolly(hooks, { recordIfMissing: false });

  hooks.beforeEach(async function(assert) {
    await visit('/');
    assert.equal(currentURL(), '/');
  });

  test('shows a welcome message', function(assert) {
    assert.dom('[data-test-welcome-message]').exists();
  });
});

Use Polly.js instead of Pretender


module.exports = {
  extends: [
    'eslint-config-airbnb-base/rules/best-practices'
  ],
  rules: {
    // Enforce that class methods use `this`
    // http://eslint.org/docs/rules/class-methods-use-this
    'class-methods-use-this': 'off',

    // Enforce a maximum cyclomatic complexity allowed in a program
    // http://eslint.org/docs/rules/complexity
    complexity: 'off',

    // Enforce consistent brace style for all control statements
    // http://eslint.org/docs/rules/curly
    curly: ['error', 'all'],

    // Disallow shorthand type conversions
    // http://eslint.org/docs/rules/no-implicit-coercion
    'no-implicit-coercion': ['error', {
      boolean: false,
      number: false,
      string: true,
    }],

    // Disallow `var` and named `function` declarations in the global scope
    // http://eslint.org/docs/rules/no-implicit-globals
    'no-implicit-globals': 'error',

    // Disallow throwing literals as exceptions
    // http://eslint.org/docs/rules/no-throw-literal
    'no-throw-literal': 'off',

    // Disallow unmodified loop conditions
    // http://eslint.org/docs/rules/no-unmodified-loop-condition
    'no-unmodified-loop-condition': 'error',
  },
};

module.exports = {
  extends: [
    'eslint-config-airbnb-base/rules/best-practices'
  ],
  rules: {
    // Enforce that class methods use `this`
    // http://eslint.org/docs/rules/class-methods-use-this
    'class-methods-use-this': 'off',

    // Enforce a maximum cyclomatic complexity allowed in a program
    // http://eslint.org/docs/rules/complexity
    complexity: 'off',

    // Enforce consistent brace style for all control statements
    // http://eslint.org/docs/rules/curly
    curly: ['error', 'all'],

    // Disallow shorthand type conversions
    // http://eslint.org/docs/rules/no-implicit-coercion
    'no-implicit-coercion': ['error', {
      boolean: false,
      number: false,
      string: true,
    }],

    // Disallow `var` and named `function` declarations in the global scope
    // http://eslint.org/docs/rules/no-implicit-globals
    'no-implicit-globals': 'error',

    // Disallow throwing literals as exceptions
    // http://eslint.org/docs/rules/no-throw-literal
    'no-throw-literal': 'off',

    // Disallow unmodified loop conditions
    // http://eslint.org/docs/rules/no-unmodified-loop-condition
    'no-unmodified-loop-condition': 'error',

    // Disallow Unused Expressions
    // http://eslint.org/docs/rules/no-unused-expressions
    'no-unused-expressions': ['error', {
      allowShortCircuit: false,
      allowTernary: false,
      allowTaggedTemplates: true,
    }],
  },
};

Enable allowTaggedTemplates options in no-unused-expressions rule


/*
 * Mixin for resources that are children of a draft resource.
 *
 * This will ensure that the draft is in a proper state before operating
 * on the resource.
 */
RB.DraftResourceChildModelMixin = {
    /*
     * Calls a function when the object is ready to use.
     *
     * This will ensure the draft is created before ensuring the object
     * is ready.
     */
    ready: function(options, context) {
        this.get('parentObject').ensureCreated({
            success: _.bind(_.super(this).ready, this, options, context),
            error: options.error
        }, context);
    }
};

/*
 * Mixin for resources that are children of a draft resource.
 *
 * This will ensure that the draft is in a proper state before operating
 * on the resource.
 */
RB.DraftResourceChildModelMixin = {
    /*
     * Deletes the object's resource on the server.
     *
     * This will ensure the draft is created before deleting the object,
     * in order to record the deletion as part of the draft.
     */
    destroy: function(options, context) {
        options = options || {};

        this.get('parentObject').ensureCreated({
            success: _.bind(_.super(this).destroy, this, options, context),
            error: options.error
        }, context);
    },

    /*
     * Calls a function when the object is ready to use.
     *
     * This will ensure the draft is created before ensuring the object
     * is ready.
     */
    ready: function(options, context) {
        options = options || {};

        this.get('parentObject').ensureCreated({
            success: _.bind(_.super(this).ready, this, options, context),
            error: options.error
        }, context);
    }
};

Fix deleting file attachments without a draft.


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

const MediaDevicesControls = ({ snaps, areMultipleVideoDevices, handleVideoDeviceChange }) => (
  <div
    className="experiment__playground__content--media-devices__controls"
  >
    <div
      className="experiment__playground__content--media-devices__controls__strip"
    >
      {
        snaps && snaps.map((snap, index) => (
          <img
            className="experiment__playground__content--media-devices__controls__strip__item"
            alt={`Snap ${index}`}
            key={index}
            src={snap}
          />
        ))
      }
    </div>
    {areMultipleVideoDevices &&
      <button
        className="experiment__playground__content__button"
        onClick={handleVideoDeviceChange}
      >
        <Icon
          name="switch_camera"
        />
      </button>
    }
  </div>
);

export default MediaDevicesControls;

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

const MediaDevicesControls = ({ snaps, areMultipleVideoDevices, handleVideoDeviceChange }) => (
  <div
    className="experiment__playground__content--media-devices__controls"
  >
    <div
      className="experiment__playground__content--media-devices__controls__strip"
    >
      {
        snaps && snaps.map((snap, index) => (
          <img
            className="experiment__playground__content--media-devices__controls__strip__item"
            alt={`Snap ${index}`}
            key={index}
            src={snap}
          />
        ))
      }
    </div>
    {areMultipleVideoDevices &&
      <button
        className="experiment__playground__content__button"
        onClick={handleVideoDeviceChange}
      >
        <Icon
          name="switch_video"
        />
      </button>
    }
  </div>
);

export default MediaDevicesControls;

Use clearer icon for camera switching in MediaDevices experiment


import Ember from 'ember';

export default Ember.Component.extend({

  foundation: null,

  currentClassName: Ember.computed("className", function(){
    return this.get("className") ? `.${this.get('className')}` : document;
  }),

  click() {
    if($('.off-canvas-wrap.move-right')[0]) {
      $('html').css('overflow', 'auto');
    } else {
      $('html').css('overflow', 'hidden');
    }
  },

  didInsertElement() {
    var className = this.get("currentClassName");
    var _this = this;

    this._super();

    Ember.run.debounce(this, function(){
      var clientHeight = $( window ).height();
      $('.inner-wrap').css('min-height', clientHeight);
    }, 1000);

    Ember.run.scheduleOnce('afterRender', this, function(){
      var initFoundation = Ember.$(className).foundation({
        offcanvas: { close_on_click: true }
      });
      _this.set("foundation", initFoundation);
    });
  }

  // TODO: Breaks sometime on menu-bar
  // willDestroyElement() {
  //   this.get("foundation").foundation("destroy");
  // }

});

import Ember from 'ember';

export default Ember.Component.extend({

  foundation: null,

  currentClassName: Ember.computed("className", function(){
    return this.get("className") ? `.${this.get('className')}` : document;
  }),

  didInsertElement() {
    var className = this.get("currentClassName");
    var _this = this;

    this._super();

    Ember.run.debounce(this, function(){
      var clientHeight = $( window ).height();
      $('.inner-wrap').css('min-height', clientHeight);
    }, 1000);

    Ember.run.scheduleOnce('afterRender', this, function(){
      var initFoundation = Ember.$(className).foundation({
        offcanvas: { close_on_click: true }
      });
      _this.set("foundation", initFoundation);
    });
  }

  // TODO: Breaks sometime on menu-bar
  // willDestroyElement() {
  //   this.get("foundation").foundation("destroy");
  // }

});

Revert "GCW-1826 Disable off canvas scroll"


var extURL = chrome.extension.getURL("tabs.html");

function openMyPage() {
	browser.windows.getCurrent({}).then(function(window) {
		return browser.tabs.query({windowId: window.id});
	}).then(function(tabs) {
		//check for a tabist tab first
		for(let tab of tabs) {
			if(tab.title == "Tabist"){
				//open that tab
				chrome.tabs.update(tab.id, {active: true});
				return;
			}
		}

		//loop through again to see if there is an active new tab to replace
		for(let tab of tabs) {
			if(tab.title == "New Tab" && tab.active){
				chrome.tabs.update(tab.id, {"url": extURL});
				return;
			}
		}

		//fallback to making a new tabist tab
		chrome.tabs.create({
			"url": extURL
			//,"pinned": true // TODO: add pinned option
		});
		return;
	}).catch(e => {
		console.log(e.message);
	});
}

chrome.browserAction.onClicked.addListener(openMyPage);

var extURL = chrome.extension.getURL("tabs.html");

function openMyPage() {
	chrome.windows.getCurrent({}, function(window) {
		chrome.tabs.query({windowId: window.id}, function(tabs) {
			//check for a tabist tab first
			for(let tab of tabs) {
				if(tab.title == "Tabist"){
					//open that tab
					chrome.tabs.update(tab.id, {active: true});
					return;
				}
			}

			//loop through again to see if there is an active new tab to replace
			for(let tab of tabs) {
				if(tab.title == "New Tab" && tab.active){
					chrome.tabs.update(tab.id, {"url": extURL});
					return;
				}
			}

			//fallback to making a new tabist tab
			chrome.tabs.create({
				"url": extURL
				//,"pinned": true // TODO: add pinned option
			});
			return;
		})
	});
}

chrome.browserAction.onClicked.addListener(openMyPage);

Convert from a promises based callback scheme to a nested callback based scheme to support chrome.


import React, { Component } from 'react';
import * as d3 from 'd3';

class Drawing extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      drawing: null,
    };
  }

  componentDidMount() {
    this.setState({
      drawing: document.getElementById('drawing');
    });
  }

  render() {
    return (

    )
  }
}

export default Drawing;

import React, { Component } from 'react';
import * as d3 from 'd3';

class Drawing extends React.Component {
  constructor(props) {
    super(props);

    this.handleMouseDown = this.handleMouseDown(this);
    this.handleMouseUp = this.handleMouseUp(this);
    this.handleMouseMove = this.handleMouseMove(this);

    this.state = {
      drawing: null,
      line: null
    };
  }

  componentDidMount() {
    const drawing = d3.select('#drawing')
      .append('svg')
      .attr('width', 500)
      .attr('height', 500)
      .on('mousedown', this.handleMouseDown)
      .on('mouseup', this.handleMouseUp);

    this.setState({ drawing });
  }

  handleMouseDown(component) {
    return function () {
      const d = component.state.drawing;
      const m = d3.mouse(this);

      const line = d.append('line')
        .attr('x1', m[0])
        .attr('y1', m[1])
        .attr('x2', m[0])
        .attr('y2', m[1])
        .attr('stroke-width', 2)
        .attr('stroke', 'black');

      component.setState({ line });

      d.on('mousemove', component.handleMouseMove);
    };
  }

  handleMouseUp(component) {
    return function () {
      component.state.drawing
        .on('mousemove', null);
    };
  }

  handleMouseMove(component) {
    return function () {
      const m = d3.mouse(this);

      component.state.line
        .attr('x2', m[0])
        .attr('y2', m[1]);
    };
  }

  render() {
    return (
      <div id="drawing" style={{ height: '500px', width: '500px' }} />
    );
  }
}

export default Drawing;

Add initial implementation of lines


process.traceDeprecation = true;
const path = require('path');
const webpack = require('webpack');
const WebpackCommon = require('./webpack.common');
const BundleTracker = require('webpack-bundle-tracker');
var publicPath = 'http://kpi.kobo.local:3000/static/compiled/';

module.exports = WebpackCommon({
  mode: "development",
  entry: {
    app: ['react-hot-loader/patch', './jsapp/js/main.es6'],
    tests: path.resolve(__dirname, '../test/index.js')
  },
  output: {
    library: 'KPI',
    path: path.resolve(__dirname, '../jsapp/compiled/'),
    publicPath: publicPath,
    filename: "[name]-[hash].js"
  },
  devServer: {
    publicPath: publicPath,
    disableHostCheck: true,
    hot: true,
    headers: {'Access-Control-Allow-Origin': '*'},
    port: 3000,
    host: '0.0.0.0'
  },
  plugins: [
    new BundleTracker({path: __dirname, filename: '../webpack-stats.json'}),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ]
});

process.traceDeprecation = true;
const path = require('path');
const webpack = require('webpack');
const WebpackCommon = require('./webpack.common');
const BundleTracker = require('webpack-bundle-tracker');
var isPublicDomainDefined = process.env.KOBOFORM_PUBLIC_SUBDOMAIN &&
  process.env.PUBLIC_DOMAIN_NAME;
var publicDomain = isPublicDomainDefined ? process.env.KOBOFORM_PUBLIC_SUBDOMAIN
  + '.' + process.env.PUBLIC_DOMAIN_NAME : 'localhost';
var publicPath = 'http://' + publicDomain + ':3000/static/compiled/';

module.exports = WebpackCommon({
  mode: "development",
  entry: {
    app: ['react-hot-loader/patch', './jsapp/js/main.es6'],
    tests: path.resolve(__dirname, '../test/index.js')
  },
  output: {
    library: 'KPI',
    path: path.resolve(__dirname, '../jsapp/compiled/'),
    publicPath: publicPath,
    filename: "[name]-[hash].js"
  },
  devServer: {
    publicPath: publicPath,
    disableHostCheck: true,
    hot: true,
    headers: {'Access-Control-Allow-Origin': '*'},
    port: 3000,
    host: '0.0.0.0'
  },
  plugins: [
    new BundleTracker({path: __dirname, filename: '../webpack-stats.json'}),
    new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ]
});

Use domain name instead of localhost when it's available to make webpack works with local domain names


import { Platform, StyleSheet } from 'react-native';
import { colors } from '../../styles';

const styles = StyleSheet.create({
  root: {
    height: 1,
    backgroundColor: colors.grey,
    opacity: 0.5,
  },
  shadow: {
    backgroundColor: colors.greyOpacity,
    ...Platform.select({
      ios: {
        shadowOpacity: 0.9,
        shadowRadius: 4,
        shadowOffset: {
          height: 0,
          width: 0,
        },
      },
      android: {
        elevation: 0.3,
      },
    }),
  },
  opacity: {
    opacity: 0.3,
  },
});

export default styles;

import { Platform, StyleSheet } from 'react-native';
import { colors } from '../../styles';

const styles = StyleSheet.create({
  root: {
    height: 1,
    backgroundColor: colors.grey,
    opacity: 0.5,
  },
  shadow: {
    backgroundColor: colors.greyOpacity,
    ...Platform.select({
      ios: {
        shadowOpacity: 0.9,
        shadowRadius: 1,
        shadowOffset: {
          height: 0.5,
          width: 0,
        },
      },
      android: {
        elevation: 0.3,
      },
    }),
  },
  opacity: {
    opacity: 0.3,
  },
});

export default styles;

Change separator with shadow view on ios


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

const exec = require('child_process').exec;
const nodepath = process.env._;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec(nodepath+' --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

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

const exec = require('child_process').exec;
// this is from the env of npm, not node
const nodePath = process.env.NODE;
const version = process.versions.v8;
const tmpfile = path.join(__dirname, version+'.flags.json');

if (!fs.existsSync(tmpfile)) {
  exec(nodePath+' --v8-options', function (execErr, result) {
    var flags;
    if (execErr) {
      throw new Error(execErr);
    } else {
      flags = result.match(/\s\s--(\w+)/gm).map(function (match) {
        return match.substring(2);
      });
      fs.writeFile(tmpfile, JSON.stringify(flags), { encoding:'utf8' },
        function (writeErr) {
          if (writeErr) {
            throw new Error(writeErr);
          } else {
            console.log('flags for v8 '+version+' cached.');
          }
        }
      );
    }
  });
}

module.exports = require.bind(null, tmpfile);

Use process.env.NODE to find node executable


module.exports = function(multiLang){

  const MoviePoster = require('./movie-poster')(multiLang);

  function selectTemplate(templateName) {
    let template = null;

    switch (templateName) {
      case 'MoviePoster':
        template = new MoviePoster();
        break;
    }

    return template;
  }

  return {
    selectTemplate
  };
}

const MoviePoster = require('./movie-poster');

function selectTemplate(templateName, userLang) {
  let template = null;

  switch (templateName) {
    case 'MoviePoster':
      template = new MoviePoster(userLang);
      break;
  }

  return template;
}

module.exports.selectTemplate = selectTemplate;

Send language to templates class on constructor


var PassThrough = require('stream').PassThrough
var inherits = require('util').inherits

function SeriesStream () {
  PassThrough.apply(this, arguments)
  this._current = null
  this._queue = []
}
inherits(SeriesStream, PassThrough)

SeriesStream.prototype.on = function (ev, fn) {
  var res = PassThrough.prototype.on.call(this, ev, fn)

  if (ev === 'data' && !this._current) {
    this._next()
  }

  return res
}

SeriesStream.prototype.pipe = function (dest) {
  PassThrough.prototype.pipe.call(this, dest)
  if (!this._current) {
    this._next()
  }
}

SeriesStream.prototype.add = function (src) {
  this._queue.push(src)
}

SeriesStream.prototype._next = function () {
  this._current = null
  if (!this._queue.length) return
  var next = this._queue.shift()
  this._current = next
  next.once('end', this._next.bind(this))
  next.pipe(this)
}

SeriesStream.prototype.end = function () {
  if (this._current) return // Only end when all streams have ended
  PassThrough.prototype.end.apply(this, arguments)
}

module.exports = function (opts) {
  return new SeriesStream(opts)
}

module.exports.SeriesStream = SeriesStream

var PassThrough = require('stream').PassThrough
var inherits = require('util').inherits

function SeriesStream () {
  PassThrough.apply(this, arguments)
  this._current = null
  this._queue = []
}
inherits(SeriesStream, PassThrough)

SeriesStream.prototype.on = function (ev, fn) {
  var res = PassThrough.prototype.on.call(this, ev, fn)

  if (ev === 'data' && !this._current) {
    this._next()
  }

  return res
}

SeriesStream.prototype.pipe = function (dest) {
  PassThrough.prototype.pipe.call(this, dest)

  if (!this._current) {
    this._next()
  }

  return dest
}

SeriesStream.prototype.add = function (src) {
  this._queue.push(src)
  return this
}

SeriesStream.prototype._next = function () {
  this._current = null
  if (!this._queue.length) return
  var next = this._queue.shift()
  this._current = next
  next.once('end', this._next.bind(this))
  next.pipe(this)
}

SeriesStream.prototype.end = function () {
  if (this._current) return // Only end when all streams have ended
  return PassThrough.prototype.end.apply(this, arguments)
}

module.exports = function (opts) {
  return new SeriesStream(opts)
}

module.exports.SeriesStream = SeriesStream

Fix return dest stream from pipe


const Commando = require('discord.js-commando')

module.exports =
class Command extends Commando.Command {
    constructor(client, info) {
        info.group = 'rover';
        info.guildOnly = true;
        info.memberName = info.name;

        super(client, info);

        this.userPermissions = info.userPermissions || ['ADMINISTRATOR'];
        this.discordBot = this.client.discordBot;
    }

    hasPermission(msg) {
        return msg.member.hasPermission(this.userPermissions);
    }

    async run(msg, args, pattern) {
        this.server = await this.discordBot.getServer(msg.guild.id);
        return await this.fn(msg, args, pattern);
    }
}

const Commando = require('discord.js-commando')

module.exports =
class Command extends Commando.Command {
    constructor(client, info) {
        info.group = 'rover';
        info.guildOnly = true;
        info.memberName = info.name;

        super(client, info);

        this.userPermissions = info.userPermissions || ['MANAGE_GUILD'];
        this.discordBot = this.client.discordBot;
    }

    hasPermission(msg) {
        return msg.member.hasPermission(this.userPermissions);
    }

    async run(msg, args, pattern) {
        this.server = await this.discordBot.getServer(msg.guild.id);
        return await this.fn(msg, args, pattern);
    }
}

Change requirement to MANAGE SERVER


var opener = require('opener');
var http = require('http');
var fs = require('fs');
var url = require('url');
var exec = require('child_process').execSync;

var registry = exec('npm config get registry').toString().trim()

opener(registry + 'oauth/authorize');

fs.readFile('./index.html', function(err, html) {
  if (err) {
    throw err;
  }

  http.createServer(function(req, res) {
    var query = url.parse(req.url, true).query;
    var token = decodeURIComponent(query.token);

    var u = url.parse(registry);
    var keyBase = '//' + u.host + u.path + ':'
    exec('npm config set ' + keyBase + '_authToken "' + token + '"');
    exec('npm config set ' + keyBase + 'always-auth true');

    res.writeHeader(200, {"Content-Type": "text/html"});
    res.end(html, function() {
      process.exit(0);
    });

  }).listen(8239);
})

var opener = require('opener');
var http = require('http');
var fs = require('fs');
var url = require('url');
var exec = require('child_process').execSync;

var registry = exec('npm config get registry').toString().trim()

if (registry.indexOf('registry.npmjs.org') > -1) {
  console.log('It seems you are using the default npm repository.');
  console.log('Please update it to your sinopia url by running:');
  console.log('');
  console.log('npm config set registry <url>');
  process.exit(0);
}

opener(registry + 'oauth/authorize');

fs.readFile('./index.html', function(err, html) {
  if (err) {
    throw err;
  }

  http.createServer(function(req, res) {
    var query = url.parse(req.url, true).query;
    var token = decodeURIComponent(query.token);

    var u = url.parse(registry);
    var keyBase = '//' + u.host + u.path + ':'
    exec('npm config set ' + keyBase + '_authToken "' + token + '"');
    exec('npm config set ' + keyBase + 'always-auth true');

    res.writeHeader(200, {"Content-Type": "text/html"});
    res.end(html, function() {
      process.exit(0);
    });

  }).listen(8239);
})

Exit when using the default npm registry


module.exports = {
	init: function() {
		var client = this
		function isClient(name) {
			var agent = window.navigator.userAgent,
				index = agent.indexOf(name)
			if (index < 0) { return false }
			client.version = parseInt(agent.substr(index + name.length + 1))
			client.name = name
			return true
		}
		client.isIE = isClient('MSIE')
		client.isFirefox = isClient('Firefox')
		client.isWebkit = client.isWebKit = isClient('WebKit')
		client.isChrome = isClient('Chrome')
		client.isSafari = !client.isChrome && isClient('Safari')
	},

	isQuirksMode: function(doc) {
		// in IE, if compatMode is undefined (early ie) or explicitly set to BackCompat, we're in quirks
		return this.isIE && (!doc.compatMode || doc.compatMode == 'BackCompat')
	}
}

module.exports.init()

module.exports = {
	init: function() {
		var client = this
		function isClient(name) {
			var agent = window.navigator.userAgent,
				index = agent.indexOf(name)
			if (index < 0) { return false }
			client.version = parseInt(agent.substr(index + name.length + 1))
			client.name = name
			return true
		}
		client.isIE = isClient('MSIE')
		client.isFirefox = isClient('Firefox')
		client.isWebkit = client.isWebKit = isClient('WebKit')
		client.isChrome = isClient('Chrome')
		client.isSafari = !client.isChrome && isClient('Safari')
		client.isIPhone = isClient('iPhone')
		client.isIPad = isClient('iPad')
		client.isIPod = isClient('iPod')
	},

	isQuirksMode: function(doc) {
		// in IE, if compatMode is undefined (early ie) or explicitly set to BackCompat, we're in quirks
		return this.isIE && (!doc.compatMode || doc.compatMode == 'BackCompat')
	}
}

module.exports.init()

Check for iPhone, iPad and iPod


var bridge = require('vigour-native/lib/bridge')
var env = require('vigour-native/lib/env')
// var name = 'plugin'
var id = 'vigour-native-plugin'
var supportedPlatforms = [
  'android',
  'ios'
]
var supportedDevices = [
  'phone',
  'tablet'
]

module.exports = exports = {}

exports.usable = ~supportedDevices.indexOf(env.ua.device) &&
  ~supportedPlatforms.indexOf(env.ua.platform)

exports.act = function (opts, cb) {
  // var error
  if (!cb) {
    cb = opts
    opts = null
  }
  bridge.call(id, 'act', opts, cb)
}

var bridge = require('vigour-native/lib/bridge')
var pkg = require('./package.json')
var pluginId = pkg.vigour.plugin.id

module.exports = exports = {}

exports.bridgeCall = function (fn, opts, cb) {
  if (!cb) {
    cb = opts
    opts = null
  }
  bridge.call(pluginId, fn, opts, cb)
}

// TODO Everything above this line feels like boilerplate
// and should probably be moved to lib/bridge somehow

// If plugin requires initialization on the native side
exports.bridgeCall('init', function (err) {
  if (!err) {
    // Native part is ready
    exports.init()
  } else {
    throw err
  }
})

exports.init = function () {
  // Do something
}

exports.act = function (opts, cb) {
  exports.bridgeCall('act', opts, cb)
}

Call native initialization from js


'use strict'

var commentMarker = require('mdast-comment-marker')

module.exports = commentconfig

// Modify `processor` to read configuration from comments.
function commentconfig() {
  var proto = this.Parser && this.Parser.prototype
  var Compiler = this.Compiler
  var block = proto && proto.blockTokenizers
  var inline = proto && proto.inlineTokenizers
  var compiler = Compiler && Compiler.prototype && Compiler.prototype.visitors

  if (block && block.html) {
    block.html = factory(block.html)
  }

  if (inline && inline.html) {
    inline.html = factory(inline.html)
  }

  if (compiler && compiler.html) {
    compiler.html = factory(compiler.html)
  }
}

// Wrapper factory.
function factory(original) {
  replacement.locator = original.locator

  return replacement

  // Replacer for tokeniser or visitor.
  function replacement(node) {
    var self = this
    var result = original.apply(self, arguments)
    var marker = commentMarker(result && result.type ? result : node)

    if (marker && marker.name === 'remark') {
      try {
        self.setOptions(marker.parameters)
      } catch (error) {
        self.file.fail(error.message, marker.node)
      }
    }

    return result
  }
}

'use strict'

var commentMarker = require('mdast-comment-marker')

module.exports = commentconfig

var origin = 'remark-comment-config:invalid-options'

// Modify `processor` to read configuration from comments.
function commentconfig() {
  var proto = this.Parser && this.Parser.prototype
  var Compiler = this.Compiler
  var block = proto && proto.blockTokenizers
  var inline = proto && proto.inlineTokenizers
  var compiler = Compiler && Compiler.prototype && Compiler.prototype.visitors

  if (block && block.html) {
    block.html = factory(block.html)
  }

  if (inline && inline.html) {
    inline.html = factory(inline.html)
  }

  if (compiler && compiler.html) {
    compiler.html = factory(compiler.html)
  }
}

// Wrapper factory.
function factory(original) {
  replacement.locator = original.locator

  return replacement

  // Replacer for tokeniser or visitor.
  function replacement(node) {
    var self = this
    var result = original.apply(self, arguments)
    var marker = commentMarker(result && result.type ? result : node)

    if (marker && marker.name === 'remark') {
      try {
        self.setOptions(marker.parameters)
      } catch (error) {
        self.file.fail(error.message, marker.node, origin)
      }
    }

    return result
  }
}

Add origin to option setting failure


'use strict'

const standard = require('standard')
const format = require('util').format
const assign = require('object-assign')
const loaderUtils = require('loader-utils')

module.exports = function standardLoader (text) {
  const self = this
  const callback = this.async()

  const config = assign(
    this.options.standard || {},
    loaderUtils.parseQuery(this.query)
  )

  this.cacheable()

  standard.lintText(text, config, function (err, result) {
    if (err) return callback(err, text)
    if (result.errorCount === 0) return callback(err, text)

    const warnings = result.results.reduce(function (items, result) {
      return items.concat(result.messages.map(function (message) {
        return format(
          '%s:%d:%d: %s',
          result.filePath, message.line || 0, message.column || 0, message.message
        )
      }))
    }, [])

    self.emitWarning(warnings.join('\n'))
    callback(err, text)
  })
}

'use strict'

var standard = require('standard')
var format = require('util').format
var assign = require('object-assign')
var loaderUtils = require('loader-utils')

module.exports = function standardLoader (text) {
  var self = this
  var callback = this.async()

  var config = assign(
    this.options.standard || {},
    loaderUtils.parseQuery(this.query)
  )

  this.cacheable()

  standard.lintText(text, config, function (err, result) {
    if (err) return callback(err, text)
    if (result.errorCount === 0) return callback(err, text)

    var warnings = result.results.reduce(function (items, result) {
      return items.concat(result.messages.map(function (message) {
        return format(
          '%s:%d:%d: %s',
          result.filePath, message.line || 0, message.column || 0, message.message
        )
      }))
    }, [])

    self.emitWarning(warnings.join('\n'))
    callback(err, text)
  })
}

Remove const in strict-mode for 0.10.x.


var through2 = require('through2');
var File = require('vinyl');
var path = require('path');

module.exports = function (filename, baseDir) {
    var ins = through2()
    var out = false

    var opts = {
        contents: ins
    };
    if (filename) {
        opts.path = path.resolve(baseDir || __dirname, filename);
    }
    if (baseDir) {
        opts.base = baseDir;
    }
    console.log(opts);
    var file = new File(opts);

    return through2({
        objectMode: true
    }, function(chunk, enc, next) {
        if (!out) {
            this.push(file)
            out = true
        }

        ins.push(chunk)
        next()
    }, function() {
        ins.push(null)
        this.push(null)
    })
}

var through2 = require('through2')
var File = require('vinyl')
var path = require('path')

module.exports = function (filename, baseDir) {
  var ins = through2()
  var out = false

  var opts = {
    contents: ins
  };
  if (filename) {
    opts.path = path.resolve(baseDir || __dirname, filename)
  }
  if (baseDir) {
    opts.base = baseDir
  }
  var file = new File(opts)

  return through2({
    objectMode: true
  }, function(chunk, enc, next) {
    if (!out) {
      this.push(file)
      out = true
    }

    ins.push(chunk)
    next()
  }, function() {
    ins.push(null)
    this.push(null)
  })
}

Fix indention - Remove console.log()


var conf = require("./server/conf"),
    app  = require("./server/app"),
    log  = conf.log;

app.listen(conf.PORT, function() {
    log.info("Server_listening on port %s", conf.PORT);
});

var conf = require("./server/conf"),
    app  = require("./server/app"),
    log  = conf.log;

app.listen(conf.PORT, function() {
    log.info("Server_listening on port %s", conf.PORT)
});

Deploy shouldn't work if other tasks fail


var debug       = require( 'debug' )( 'wpcom-vip' );
var request     = require( './lib/util/request' );

// Modules

function WPCOM_VIP( token ) {
    this.req = new Request( this );

    this.auth = {};
}

WPCOM_VIP.prototype.API_VERSION = '1';
WPCOM_VIP.prototype.API_TIMEOUT = 10000;

WPCOM_VIP.prototype.get = function() {
    return this.req.get.apply( arguments );
};

WPCOM_VIP.prototype.post = function() {
    return this.req.post.apply( arguments );
};

WPCOM_VIP.prototype.put = function() {
    return this.req.get.apply( arguments );
};

WPCOM_VIP.prototype.delete = function() {
    return this.req.delete.apply( arguments );
};

module.exports = WPCOM_VIP;

var debug       = require( 'debug' )( 'wpcom-vip' );
var Request     = require( './lib/util/request' );

// Modules

function WPCOM_VIP( token ) {
    this.req = new Request( this );

    this.auth = {};
}

WPCOM_VIP.prototype.API_VERSION = '1';
WPCOM_VIP.prototype.API_TIMEOUT = 10000;

WPCOM_VIP.prototype.get = function() {
    return this.req.get.apply( arguments );
};

WPCOM_VIP.prototype.post = function() {
    return this.req.post.apply( arguments );
};

WPCOM_VIP.prototype.put = function() {
    return this.req.get.apply( arguments );
};

WPCOM_VIP.prototype.delete = function() {
    return this.req.delete.apply( arguments );
};

module.exports = WPCOM_VIP;

Fix capitalization of included Request module


#!/usr/bin/env node

'use strict';

console.log('Hello World!');

#!/usr/bin/env node

'use strict';

const program = require('commander');

program
    .option('-v, --version', 'Software Version')
    .option('-u, --uptime', 'Total Uptime')
    .option('-g, --gip', 'Gateway IP')
    .option('-i, --ip', 'IP Address')
    .option('-d, --dns', 'DNS Servers')
    .option('-a, --all', 'Display all stats')
    .parse(process.argv);

// If no option passed, show help
if (!process.argv.slice(2).length) {
    program.help();
}

Add cli options using commander


exports.encode = exports.stringify = function (value) {
  var values = [value];
  var table = [];

  for (var v = 0; v < values.length; ++v) {
    value = values[v];
    if (value && typeof value === "object") {
      var copy = table[v] = Array.isArray(value) ? [] : {};
      Object.keys(value).forEach(function (key) {
        var child = value[key];
        var index = values.indexOf(child);
        if (index < 0) {
          index = values.push(child) - 1;
        }
        copy[key] = index;
      });
    } else {
      table[v] = value;
    }
  }

  return JSON.stringify(table);
};

exports.decode = exports.parse = function (encoding) {
  var table = JSON.parse(encoding);

  table.forEach(function (entry) {
    if (entry && typeof entry === "object") {
      Object.keys(entry).forEach(function (key) {
        entry[key] = table[entry[key]];
      });
    }
  });

  return table[0];
};

function encode(value) {
  return JSON.stringify(tabulate(value));
}

function tabulate(value) {
  var values = [];
  var table = [];
  var indexMap = typeof Map === "function" && new Map;

  function getIndex(value) {
    var index;

    if (indexMap) {
      // If we have Map, use it instead of values.indexOf to accelerate
      // object lookups.
      index = indexMap.get(value);
      if (typeof index === "undefined") {
        index = values.push(value) - 1;
        indexMap.set(value, index);
      }
    } else {
      index = values.indexOf(value);
      if (index < 0) {
        index = values.push(value) - 1;
      }
    }

    return index;
  }

  // Assign the root value to values[0].
  getIndex(value);

  for (var v = 0; v < values.length; ++v) {
    value = values[v];

    if (value && typeof value === "object") {
      var copy = table[v] = Array.isArray(value) ? [] : {};
      Object.keys(value).forEach(function (key) {
        copy[key] = getIndex(value[key]);
      });
    } else {
      table[v] = value;
    }
  }

  return table;
}

function decode(encoding) {
  var table = JSON.parse(encoding);

  table.forEach(function (entry) {
    if (entry && typeof entry === "object") {
      Object.keys(entry).forEach(function (key) {
        entry[key] = table[entry[key]];
      });
    }
  });

  return table[0];
}

exports.encode = exports.stringify = encode;
exports.decode = exports.parse = decode;

Use a Map to accelerate seen object lookups.


import {
  AppRegistry,
  StatusBar,
} from 'react-native';

import Finance from './Finance';

StatusBar.setBarStyle('light-content', true);

AppRegistry.registerComponent('Finance', () => Finance);

import {
  AppRegistry,
  StatusBar,
} from 'react-native';

import Finance from './Finance';

console.disableYellowBox = true;
StatusBar.setBarStyle('light-content', true);

AppRegistry.registerComponent('Finance', () => Finance);

Disable new yellow componentWillMount() lifecycle warnings


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

var imagemin = require('broccoli-imagemin');

module.exports = {
  name: 'ember-cli-imagemin',

  included: function(app) {
    this.app = app;

    var defaultOptions = {
      enabled: this.app.env === 'production'
    };

    if (this.app.options.imagemin === false) {
      this.options = this.app.options.imagemin = { enabled: false };
    } else {
      this.options = this.app.options.imagemin = this.app.options.imagemin || {};
    }

    for (var option in defaultOptions) {
      if (!this.options.hasOwnProperty(option)) {
        this.options[option] = defaultOptions[option];
      }
    }
  },

  postprocessTree: function(type, tree) {
    if (this.options.enabled) {
      tree = imagemin(tree, this.options);
    }

    return tree;
  }
};

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

var imagemin = require('broccoli-imagemin');

module.exports = {
  name: 'ember-cli-imagemin',

  included: function() {
    this._super.included.apply(this, arguments);

    // Default options
    var defaultOptions = {
      enabled: this.app.env === 'production'
    };

    // If the imagemin options key is set to `false` instead of
    // an options object, disable the addon
    if (this.app.options.imagemin === false) {
      this.options = this.app.options.imagemin = { enabled: false };
    } else {
      this.options = this.app.options.imagemin = this.app.options.imagemin || {};
    }

    // Merge the default options with the passed in options
    for (var option in defaultOptions) {
      if (!this.options.hasOwnProperty(option)) {
        this.options[option] = defaultOptions[option];
      }
    }
  },

  postprocessTree: function(type, tree) {
    if (this.options.enabled) {
      tree = imagemin(tree, this.options);
    }

    return tree;
  }
};

Add comments and call _super


var fs = require('fs');
var rest = require(__dirname + "/lib/rest");
var unzip = require("unzip2");

module.exports = {
  hello: function() {
	  return "Hi!"
  }
}

var fs = require('fs');
var rest = require(__dirname + "/lib/rest");
var unzip = require("unzip2");

//Globalish
var contract = 	{
		cc: {
			read: read,
			write: write,
			remove: remove,
			deploy: deploy,
			readNames: readNames,
			details:{
						host: "",
						port: 80,
						path: "",
						url: "",
						name: {},
						func: [],
						vars: []
			}
		}
	};

module.exports = {
  hello: function() {
	  return "Hi!";
  },
  network = function(arrayPeers){
		if(arrayPeers.constructor !== Array){
			console.log('[obc-js] Error - network arg should be array of peer objects');
		}
		else{
			for(var i in arrayPeers){
				var pos = arrayPeers[i].id.indexOf('_') + 1;
				arrayPeers[i].name = arrayPeers[i].id.substring(pos) + '-' + arrayPeers[i].api_host + ':' + arrayPeers[i].api_port;
				console.log(arrayPeers[i].name);
			}
			var ssl = true;
			contract.cc.details.host = arrayPeers[0].api_host;
			contract.cc.details.port = arrayPeers[0].api_port;
			contract.cc.details.peers = arrayPeers;
			if(arrayPeers[0].api_url.indexOf('https') == -1) ssl = false;				//not https, no tls

			rest.init({																	//load default values for rest call to peer
						host: contract.cc.details.host,
						port: contract.cc.details.port,
						headers: {
									"Content-Type": "application/json",
									"Accept": "application/json",
								},
						ssl: ssl,
						quiet: true
			});
		}
	}
}

Bring in the first function.


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

function findFile(cwd, pattern, cb) {
  fs.readdir(cwd, function(err, files){
    if(err) {
      console.log("Error in reading dir");
      cb(err, null);
    } else {
      var regex = new RegExp('^' + pattern + "$");
      cb(null, files.filter(file => regex.test(file)));
    }
  })
};

module.exports = findFile;

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

function recursiveSearch(cwd, regex, depth) {
    if ( depth-- > 0) {
        var matchingFiles = [];
        var files = fs.readdirSync(cwd)
        files.forEach(file => {
            var fsStat = fs.statSync(path.join(cwd, file));
            if (fsStat.isFile() && regex.test(file)) {
                matchingFiles.push({
                    dir: cwd,
                    file: file
                })
            } else if (fsStat.isDirectory()) {
                matchingFiles = matchingFiles.concat(recursiveSearch(path.join(cwd, file), regex, depth));
            }
        })

        return matchingFiles;
    } else {
        return [];
    }
}

function findFile(cwd, pattern, recursive, depth, cb) {

    if (recursive.constructor == Function) {
        cb = recursive;
        recursive = false;
        depth = 100;
    } else if (depth.constructor == Function) {
        cb = depth;
        depth = 100;
    }

    var regex = new RegExp('^' + pattern + "$");

    if (recursive) {
        cb(null, recursiveSearch(cwd, regex, depth));

    } else {
        fs.readdir(cwd, function(err, files) {
            if (err) {
                cb(err, null);
            } else {
                cb(null, files.filter(file => regex.test(file)));
            }
        })
    }
}

module.exports = findFile;

Support for recursion and depth


"use strict";
const pattern = /^\s*(\d+)(?:\s*;(?:\s*url\s*=)?\s*(.+)?)?$/i;

const parseMetaRefresh = content =>
{
	const result = { timeout:null, url:null };
	content = pattern.exec(content);

	if (content !== null)
	{
		if (content[1] !== undefined)
		{
			result.timeout = parseInt(content[1], 10);
		}

		if (content[2] !== undefined)
		{
			let url = content[2].trim();

			const firstChar = url[0];
			const lastChar  = url[ url.length-1 ];

			// Remove a single level of encapsulating quotes
			if (firstChar==="'" && lastChar==="'" || firstChar==='"' && lastChar==='"')
			{
				if (url.length > 2)
				{
					url = url.substr(1, url.length-2).trim();
				}
				else
				{
					url = "";
				}

				if (url === "")
				{
					url = null;
				}
			}

			result.url = url;
		}
	}

	return result;
};

module.exports = parseMetaRefresh;

"use strict";
const pattern = /^\s*(\d+)(?:\s*;(?:\s*url\s*=)?\s*(?:("|')\s*(.+?)?\s*\2|(.+?))?)?\s*$/i;

const parseMetaRefresh = content =>
{
	const result = { timeout:null, url:null };
	content = pattern.exec(content);

	if (content !== null)
	{
		// pattern gaurantees first matching group
		result.timeout = parseInt( content[1] );

		result.url = content[3] || content[4] || null;
	}

	return result;
};

module.exports = parseMetaRefresh;

Refactor to use a regex pattern that trims the URL and recognizes enclosing single/double quotes.


'use strict';

const os = require('os');
const toarray = require('lodash/toArray');
const defaults = require('lodash/defaults');
const map = require('lodash/map');
const debug = require('debug')('asset-resolver');
const Bluebird = require('bluebird');
const resolver = require('./lib/resolver');

module.exports.getResource = function(file, opts) {
  opts = defaults(opts || {}, {
    base: [process.cwd()],
    filter() {
      return true;
    }
  });

  if (typeof opts.base === 'string') {
    opts.base = [opts.base];
  }

  opts.base = resolver.glob(toarray(opts.base));

  return Bluebird.any(
    map(opts.base, base => {
      return resolver.getResource(base, file, opts);
    })
  ).catch(Bluebird.AggregateError, errs => {
    const msg = [
      'The file "' + file + '" could not be resolved because of:'
    ].concat(map(errs, 'message'));
    debug(msg);
    return Bluebird.reject(new Error(msg.join(os.EOL)));
  });
};

'use strict';

const os = require('os');
const defaults = require('lodash/defaults');
const map = require('lodash/map');
const debug = require('debug')('asset-resolver');
const Bluebird = require('bluebird');
const resolver = require('./lib/resolver');

module.exports.getResource = function(file, opts) {
  opts = defaults(opts || {}, {
    base: [process.cwd()],
    filter() {
      return true;
    }
  });

  if (typeof opts.base === 'string') {
    opts.base = [opts.base];
  }

  opts.base = resolver.glob([...opts.base]);

  return Bluebird.any(
    map(opts.base, base => {
      return resolver.getResource(base, file, opts);
    })
  ).catch(Bluebird.AggregateError, errs => {
    const msg = [
      'The file "' + file + '" could not be resolved because of:'
    ].concat(map(errs, 'message'));
    debug(msg);
    return Bluebird.reject(new Error(msg.join(os.EOL)));
  });
};

Use the spread operator instead of lodash/toArray.


'use strict'

const tokens = require('../database/tokens')
const config = require('../utils/config')
const KnownError = require('../utils/KnownError')
const ignoreCookie = require('../utils/ignoreCookie')

const response = (entry) => ({
	id: entry.id,
	created: entry.created,
	updated: entry.updated,
})

module.exports = {
	Mutation: {
		createToken: async (parent, { input }, { setCookies }) => {
			const { username, password } = input

			if (config.username == null) throw new KnownError('Ackee username missing in environment')
			if (config.password == null) throw new KnownError('Ackee username missing in environment')

			if (username !== config.username) throw new KnownError('Username or password incorrect')
			if (password !== config.password) throw new KnownError('Username or password incorrect')

			const entry = await tokens.add()

			// Set cookie to avoid reporting your own visits
			setCookies.push(ignoreCookie.on)

			return {
				success: true,
				payload: response(entry),
			}
		},
		deleteToken: async (parent, { id }, { setCookies }) => {
			await tokens.del(id)

			// Remove cookie to report your own visits, again
			setCookies.push(ignoreCookie.off)

			return {
				success: true,
			}
		},
	},
}

'use strict'

const tokens = require('../database/tokens')
const config = require('../utils/config')
const KnownError = require('../utils/KnownError')
const ignoreCookie = require('../utils/ignoreCookie')

const response = (entry) => ({
	id: entry.id,
	created: entry.created,
	updated: entry.updated,
})

module.exports = {
	Mutation: {
		createToken: async (parent, { input }, { setCookies }) => {
			const { username, password } = input

			if (config.username == null) throw new KnownError('Ackee username missing in environment')
			if (config.password == null) throw new KnownError('Ackee password missing in environment')

			if (username !== config.username) throw new KnownError('Username or password incorrect')
			if (password !== config.password) throw new KnownError('Username or password incorrect')

			const entry = await tokens.add()

			// Set cookie to avoid reporting your own visits
			setCookies.push(ignoreCookie.on)

			return {
				success: true,
				payload: response(entry),
			}
		},
		deleteToken: async (parent, { id }, { setCookies }) => {
			await tokens.del(id)

			// Remove cookie to report your own visits, again
			setCookies.push(ignoreCookie.off)

			return {
				success: true,
			}
		},
	},
}

Fix error when password is missing


#! /usr/bin/env node
let program = require('commander')
let configResolver = require('./src/configResolver')
let configWriter = require('./src/configWriter')
let interpolationResolver = require('./src/interpolationResolver')

let configElement = '_default'

// Set up and parse program arguments.
// We only really care about the first positional argument
// giving use the correct config to use
program
  .arguments('[configElement]')
  .action(_configElement => {
    configElement = _configElement
  })
  .option('-s, --scan', 'Automatically detect interpolatinos from content')
  .parse(process.argv)

// Merge regular config file and folder config
let config = Object.assign(
  {},
  configResolver.resolve(),
  configResolver.resolveFolderConfig()
)

// Does it exist?
if (!config[configElement]) {
  console.error('Found no recipe named \'' + configElement + '\' in resolved config')
  process.exit(1)
}

let resolvedElement = config[configElement]

if (program.scan) {
  interpolationResolver.scan(resolvedElement, (result) => {
    resolvedElement.__interpolations__ = (resolvedElement.__interpolations__ || []).concat(result)
    configWriter.write(resolvedElement)
  })
} else {
  configWriter.write(resolvedElement)
}

#! /usr/bin/env node
const program = require('commander')
const colors = require('colors')
const configResolver = require('./src/configResolver')
const configWriter = require('./src/configWriter')
const interpolationResolver = require('./src/interpolationResolver')

let configElement = '_default'

// Set up and parse program arguments.
// We only really care about the first positional argument
// giving use the correct config to use
program
  .arguments('[configElement]')
  .action(_configElement => {
    configElement = _configElement
  })
  .option('-s, --scan', 'Automatically detect interpolatinos from content')
  .option('-l, --list', 'List available typical recipes recipes')
  .parse(process.argv)

// Merge regular config file and folder config
let config = Object.assign(
  {},
  configResolver.resolve(),
  configResolver.resolveFolderConfig()
)

// If list is true, we simply list the available recipes
if (program.list) {
  console.log(colors.green('Available typical recipes:'))
  Object.keys(config).forEach(element => {
    console.log(colors.gray(' + ' + element.toString()))
  })
  process.exit(1)
}

// Does it exist?
if (!config[configElement]) {
  console.error('Found no recipe named \'' + configElement + '\' in resolved config')
  process.exit(1)
}

let resolvedElement = config[configElement]

if (program.scan) {
  interpolationResolver.scan(resolvedElement, (result) => {
    resolvedElement.__interpolations__ = (resolvedElement.__interpolations__ || []).concat(result)
    configWriter.write(resolvedElement)
  })
} else {
  configWriter.write(resolvedElement)
}

Add --list option to typical