<commit_before>const chai = require('chai');
const Job = require('../constructors/Job.js');
const should = chai.should();
const expect = chai.expect;

const testJob = new Job([1, 2, 3], 3, 'project02');

describe('Jobs', () => {
  it('should be an object', () => {
    testJob.should.be.a('object');
  });
  it('should should have a JobId', () => {
    // testJob.to.include.keys('jobId');
    should.exist(testJob.jobId);
    expect(testJob.jobId).to.equal(3);
  });

  it('should have a projectId', () => {
    should.exist(testJob.projectId);
    expect(testJob.projectId).to.equal('project02');
  });
  it('should have a data field', () => {
    should.exist(testJob.data);
    expect(testJob.data).to.deep.equal([1, 2, 3]);
  });
  it('should not have a result value')
  it('should not have a mapData function')
});

<commit_msg>Tests on projects<commit_after>const chai = require('chai');
const Job = require('../constructors/Job.js');
const should = chai.should();
const expect = chai.expect;
const Worker = require('../constructors/Worker.js');

const testJob = new Job([1, 2, 3], 3, 'project01');

describe('Jobs', () => {
  it('should be an object', () => {
    testJob.should.be.a('object');
  });
  it('should should have a JobId', () => {
    // testJob.to.include.keys('jobId');
    should.exist(testJob.jobId);
    expect(testJob.jobId).to.equal(3);
  });
  it('should have a projectId', () => {
    should.exist(testJob.projectId);
    expect(testJob.projectId).to.equal('project01');
  });
  it('should have a data field', () => {
    should.exist(testJob.data);
    expect(testJob.data).to.deep.equal([1, 2, 3]);
  });
  it('should not have a result value', () => {
    should.not.exist(testJob.result);
  });
  it('should not have a mapData function', () => {
    should.not.exist(testJob.mapData);
  });
  it('should not have a workerId', () => {
    should.not.exist(testJob.workerId);
  });
  it('should not have a jobsLength', () => {
    should.not.exist(testJob.jobsLength);
  });
});

const testWorker = new Worker('project01', 'socket01');

describe('Workers', () => {
  it('should be an object', () => {
    expect(testWorker).to.be.a('object');
  });
  it('should have a project ID', () => {
    should.exist(testJob.projectId);
  });
  it('should have a worker ID', () => {
    expect(testJob.socketId).to.equal('socket01');
  });
});

const testProjectOptions = {
  title: 'test',
  projectType: 'testProject',
  dataSet: null,
  generateDataSet: () => {
    return [1, 2, 3, 4]
  },
  mapData: (data) => {
      return data * 2;
    });
  },
  reduceResults: (results) => {
    return results.reduce( (acc, next) => {
      return acc + next;
    });
  }
}

<|endoftext|>


<commit_before>'use strict';

// Stores an object in HTML storage in parts
// A single array for the keys, and separate objects for the values
// Means each can be edited without re-saving the entire object
// So is useful for larger structures.
// Object + keys is is the same instance for the lifetime of the StorageBackedObject
angular.module('storage-backed-object',['angularLocalStorage','angular-lo-dash'])
.factory('StorageBackedObject', function (storage, _) {

  var sbObjects = [];

  function StorageBackedObject(rootKey_, storage_) {
    /* Private properties */

    var rootKey = rootKey_;
    var storage = storage_;

    var keys = storage.get(rootKey) || [];
    var object = {};

    /* Private methods */

    var getStorageKeyForKey = function(key) {
      return rootKey + '---VALUES---' + key;
    };

    var saveKeys = function() {
      storage.set(rootKey, keys);
    };

    var saveItemToStorage = function(key, value) {
      var storageKey = getStorageKeyForKey(key);
      if (-1 === keys.indexOf(key)) {
        keys.push(key);
        saveKeys();
      }

      storage.set(storageKey, value);
    };

    var removeItemFromStorage = function(key) {
      var storageKey = getStorageKeyForKey(key);
      storage.remove(storageKey);
    };

    var getItemFromStorage = function(key) {
      var storageKey = getStorageKeyForKey(key);
      var item = storage.get(storageKey);
      return item;
    };

    var populateObject = function() {
      angular.forEach(keys, function(key) {
        object[key] = getItemFromStorage(key);
      });
    };

    var hasKey = function(key) {
      return object.hasOwnProperty(key);
    };

    /* Public Methods */

    this.set = function(key, value) {
      object[key] = value;
      saveItemToStorage(key, value);
      saveKeys();
    };

    this.remove = function(key) {
      delete object[key];
      var index = keys.indexOf(key);
      if (-1 != index) {
        keys.splice(index, 1);
        saveKeys();
      }
      removeItemFromStorage(key);
    };

    this.get = function(key, defaultValue) {
      if (hasKey(key)) {
        return object[key];
      }
      if (undefined != defaultValue) {
        this.set(key, defaultValue);
        return defaultValue;
      }
      throw 'StorageBackedObject ' + rootKey + ' does not have property ' + key;
    };

    /* Initialise by loading all items into memory */
    populateObject();
  };

  return function(rootKey) {
    return sbObjects[rootKey] || (sbObjects[rootKey] = new StorageBackedObject(rootKey, storage));
  };
});

<commit_msg>Can set falsy value as default for get<commit_after>'use strict';

// Stores an object in HTML storage in parts
// A single array for the keys, and separate objects for the values
// Means each can be edited without re-saving the entire object
// So is useful for larger structures.
// Object + keys is is the same instance for the lifetime of the StorageBackedObject
angular.module('storage-backed-object',['angularLocalStorage','angular-lo-dash'])
.factory('StorageBackedObject', function (storage, _) {

  var sbObjects = [];

  function StorageBackedObject(rootKey_, storage_) {
    /* Private properties */

    var rootKey = rootKey_;
    var storage = storage_;

    var keys = storage.get(rootKey) || [];
    var object = {};

    /* Private methods */

    var getStorageKeyForKey = function(key) {
      return rootKey + '---VALUES---' + key;
    };

    var saveKeys = function() {
      storage.set(rootKey, keys);
    };

    var saveItemToStorage = function(key, value) {
      var storageKey = getStorageKeyForKey(key);
      if (-1 === keys.indexOf(key)) {
        keys.push(key);
        saveKeys();
      }

      storage.set(storageKey, value);
    };

    var removeItemFromStorage = function(key) {
      var storageKey = getStorageKeyForKey(key);
      storage.remove(storageKey);
    };

    var getItemFromStorage = function(key) {
      var storageKey = getStorageKeyForKey(key);
      var item = storage.get(storageKey);
      return item;
    };

    var populateObject = function() {
      angular.forEach(keys, function(key) {
        object[key] = getItemFromStorage(key);
      });
    };

    var hasKey = function(key) {
      return object.hasOwnProperty(key);
    };

    /* Public Methods */

    this.set = function(key, value) {
      object[key] = value;
      saveItemToStorage(key, value);
      saveKeys();
    };

    this.remove = function(key) {
      delete object[key];
      var index = keys.indexOf(key);
      if (-1 != index) {
        keys.splice(index, 1);
        saveKeys();
      }
      removeItemFromStorage(key);
    };

    this.get = function(key, defaultValue) {
      if (hasKey(key)) {
        return object[key];
      }
      if (undefined !== defaultValue) {
        this.set(key, defaultValue);
        return defaultValue;
      }
      throw 'StorageBackedObject ' + rootKey + ' does not have property ' + key;
    };

    /* Initialise by loading all items into memory */
    populateObject();
  };

  return function(rootKey) {
    return sbObjects[rootKey] || (sbObjects[rootKey] = new StorageBackedObject(rootKey, storage));
  };
});

<|endoftext|>


<commit_before>define([
  'angular',
  'jquery',
  'lodash',
], function(angular, jquery, _) {
  'use strict';

  var module = angular.module('grafana.controllers');

  module.controller('SeriesOverridesCtrl', function($scope, $element, popoverSrv) {
    $scope.overrideMenu = [];
    $scope.currentOverrides = [];
    $scope.override = $scope.override || {};

    $scope.addOverrideOption = function(name, propertyName, values) {
      var option = {};
      option.text = name;
      option.propertyName = propertyName;
      option.index = $scope.overrideMenu.length;
      option.values = values;

      option.submenu = _.map(values, function(value) {
        return { text: String(value), value: value };
      });

      $scope.overrideMenu.push(option);
    };

    $scope.setOverride = function(item, subItem) {
      // handle color overrides
      if (item.propertyName === 'color') {
        $scope.openColorSelector();
        return;
      }

      $scope.override[item.propertyName] = subItem.value;

      // automatically disable lines for this series and the fill bellow to series
      // can be removed by the user if they still want lines
      if (item.propertyName === 'fillBelowTo') {
        $scope.override['lines'] = false;
        $scope.addSeriesOverride({ alias: subItem.value, lines: false });
      }

      $scope.updateCurrentOverrides();
      $scope.ctrl.render();
    };

    $scope.colorSelected = function(color) {
      $scope.override['color'] = color;
      $scope.updateCurrentOverrides();
      $scope.ctrl.render();
    };

    $scope.openColorSelector = function() {
      popoverSrv.show({
        element: $element.find(".dropdown")[0],
        position: 'top center',
        openOn: 'click',
        template: '<gf-color-picker></gf-color-picker>',
        model: {
          autoClose: true,
          colorSelected: $scope.colorSelected,
        },
        onClose: function() {
          $scope.ctrl.render();
        }
      });
    };

    $scope.removeOverride = function(option) {
      delete $scope.override[option.propertyName];
      $scope.updateCurrentOverrides();
      $scope.ctrl.refresh();
    };

    $scope.getSeriesNames = function() {
      return _.map($scope.ctrl.seriesList, function(series) {
        return series.alias;
      });
    };

    $scope.updateCurrentOverrides = function() {
      $scope.currentOverrides = [];
      _.each($scope.overrideMenu, function(option) {
        var value = $scope.override[option.propertyName];
        if (_.isUndefined(value)) { return; }
        $scope.currentOverrides.push({
          name: option.text,
          propertyName: option.propertyName,
          value: String(value)
        });
      });
    };

    $scope.addOverrideOption('Bars', 'bars', [true, false]);
    $scope.addOverrideOption('Lines', 'lines', [true, false]);
    $scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Null point mode', 'nullPointMode', ['connected', 'null', 'null as zero']);
    $scope.addOverrideOption('Fill below to', 'fillBelowTo', $scope.getSeriesNames());
    $scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
    $scope.addOverrideOption('Points', 'points', [true, false]);
    $scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
    $scope.addOverrideOption('Stack', 'stack', [true, false, 'A', 'B', 'C', 'D']);
    $scope.addOverrideOption('Color', 'color', ['change']);
    $scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
    $scope.addOverrideOption('Z-index', 'zindex', [-3,-2,-1,0,1,2,3]);
    $scope.addOverrideOption('Transform', 'transform', ['negative-Y']);
    $scope.addOverrideOption('Legend', 'legend', [true, false]);
    $scope.updateCurrentOverrides();
  });
});
<commit_msg>fix: graph and fill below to issue, fixes #7916<commit_after>define([
  'angular',
  'jquery',
  'lodash',
], function(angular, jquery, _) {
  'use strict';

  var module = angular.module('grafana.controllers');

  module.controller('SeriesOverridesCtrl', function($scope, $element, popoverSrv) {
    $scope.overrideMenu = [];
    $scope.currentOverrides = [];
    $scope.override = $scope.override || {};

    $scope.addOverrideOption = function(name, propertyName, values) {
      var option = {};
      option.text = name;
      option.propertyName = propertyName;
      option.index = $scope.overrideMenu.length;
      option.values = values;

      option.submenu = _.map(values, function(value) {
        return { text: String(value), value: value };
      });

      $scope.overrideMenu.push(option);
    };

    $scope.setOverride = function(item, subItem) {
      // handle color overrides
      if (item.propertyName === 'color') {
        $scope.openColorSelector();
        return;
      }

      $scope.override[item.propertyName] = subItem.value;

      // automatically disable lines for this series and the fill bellow to series
      // can be removed by the user if they still want lines
      if (item.propertyName === 'fillBelowTo') {
        $scope.override['lines'] = false;
        $scope.ctrl.addSeriesOverride({alias: subItem.value, lines: false });
      }

      $scope.updateCurrentOverrides();
      $scope.ctrl.render();
    };

    $scope.colorSelected = function(color) {
      $scope.override['color'] = color;
      $scope.updateCurrentOverrides();
      $scope.ctrl.render();
    };

    $scope.openColorSelector = function() {
      popoverSrv.show({
        element: $element.find(".dropdown")[0],
        position: 'top center',
        openOn: 'click',
        template: '<gf-color-picker></gf-color-picker>',
        model: {
          autoClose: true,
          colorSelected: $scope.colorSelected,
        },
        onClose: function() {
          $scope.ctrl.render();
        }
      });
    };

    $scope.removeOverride = function(option) {
      delete $scope.override[option.propertyName];
      $scope.updateCurrentOverrides();
      $scope.ctrl.refresh();
    };

    $scope.getSeriesNames = function() {
      return _.map($scope.ctrl.seriesList, function(series) {
        return series.alias;
      });
    };

    $scope.updateCurrentOverrides = function() {
      $scope.currentOverrides = [];
      _.each($scope.overrideMenu, function(option) {
        var value = $scope.override[option.propertyName];
        if (_.isUndefined(value)) { return; }
        $scope.currentOverrides.push({
          name: option.text,
          propertyName: option.propertyName,
          value: String(value)
        });
      });
    };

    $scope.addOverrideOption('Bars', 'bars', [true, false]);
    $scope.addOverrideOption('Lines', 'lines', [true, false]);
    $scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
    $scope.addOverrideOption('Null point mode', 'nullPointMode', ['connected', 'null', 'null as zero']);
    $scope.addOverrideOption('Fill below to', 'fillBelowTo', $scope.getSeriesNames());
    $scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
    $scope.addOverrideOption('Points', 'points', [true, false]);
    $scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
    $scope.addOverrideOption('Stack', 'stack', [true, false, 'A', 'B', 'C', 'D']);
    $scope.addOverrideOption('Color', 'color', ['change']);
    $scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
    $scope.addOverrideOption('Z-index', 'zindex', [-3,-2,-1,0,1,2,3]);
    $scope.addOverrideOption('Transform', 'transform', ['negative-Y']);
    $scope.addOverrideOption('Legend', 'legend', [true, false]);
    $scope.updateCurrentOverrides();
  });
});
<|endoftext|>


<commit_before>// Database setup
require('../../config/mongo-db')();

// Models
const Game = require('../models/game');
const GameResponse = require('../models/game-response');

// Game Rules
const gameRules = require('../slackbot/game-rules');

Game.find({}).lean().exec((err, results) => {
  results.forEach((game) => {
    GameResponse.find({ 'gameId': game._id }).lean().exec((err, results) => {
      if (game.playerIds.length !== results.length) return;

      const gameCounter = gameRules.processToGameCounter(results);
      const drawByAll = gameRules.dhrawByAllPossibilites(gameCounter);
      const drawByOne = gameRules.drawByOnlyOnePossibility(gameCounter);
      if (!drawByAll && !drawByOne) {
        const winners = gameRules.giveWinners(gameCounter, results).map(winner => winner.userId);
        Game.update({ _id: game._id }, { winners });
      }
    });
  })
});
<commit_msg>fix typo<commit_after>// Database setup
require('../../config/mongo-db')();

// Models
const Game = require('../models/game');
const GameResponse = require('../models/game-response');

// Game Rules
const gameRules = require('../slackbot/game-rules');

Game.find({}).lean().exec((err, results) => {
  results.forEach((game) => {
    GameResponse.find({ 'gameId': game._id }).lean().exec((err, results) => {
      if (game.playerIds.length !== results.length) return;

      const gameCounter = gameRules.processToGameCounter(results);
      const drawByAll = gameRules.drawByAllPossibilites(gameCounter);
      const drawByOne = gameRules.drawByOnlyOnePossibility(gameCounter);
      if (!drawByAll && !drawByOne) {
        const winners = gameRules.giveWinners(gameCounter, results).map(winner => winner.userId);
        Game.update({ _id: game._id }, { winners });
      }
    });
  })
});
<|endoftext|>


<commit_before>var Info = function() {

}

RepoInfo.onFinishedLoading(function() {
  UserInfo.init();
})

UserInfo.onFinishedLoading(function() {

})

RepoInfo.init();
<commit_msg>Updating the RepoSearch description and search data if the repositories are updated.<commit_after>var Info = function() {

}

RepoInfo.onFinishedLoading(function() {
  UserInfo.init();
  if (this.updated) {
    JQuery.each(RepoSearch.instances, function() {
      this.updateStoreRepositories();
    })
  }
})

UserInfo.onFinishedLoading(function() {

})

RepoInfo.init();
<|endoftext|>


<commit_before>const level = require('level');
const path = require('path');
const h = require('virtual-dom/h');
const createElement = require('virtual-dom/create-element');
const inline = require('html-inline');
const fromString = require('from2-string');
const process = require('process');
const moment = require('moment');
const wordcount = require('wordcount');
const roundTo = require('round-to');
const streamEach = require('stream-each');

const topUsers = require('./lib/top-users');
const mostQuestions = require('./lib/most-questions');

const db = level(path.resolve(__dirname, 'db'), {valueEncoding: 'json'});

const users = {};

function onData(data, next) {
  if (!users[data.user]) {
    users[data.user] = {
      lines: 0,
      avgWords: 0,
      quotes: [],
      latest: moment.utc(data.timestamp, moment.ISO_8601),
      questions: 0
    };
  }

  users[data.user].lines++;

  // Cumulative moving average of the number of words in this user's messages.
  var avg = users[data.user].avgWords;
  avg += (wordcount(data.message) - avg) / users[data.user].lines;
  users[data.user].avgWords = avg;

  users[data.user].quotes.push(data.message);

  if (moment.utc(data.timestamp, moment.ISO_8601).isAfter(users[data.user].latest)) {
    users[data.user].latest = moment.utc(data.timestamp, moment.ISO_8601);
  }

  if (data.message.indexOf('?') !== -1) {
    users[data.user].questions++;
  }

  next();
}

function render() {
  const bigAsk = mostQuestions(users);

  const bigNumbers = h('table', [
    h('thead', [
      h('tr', [
        h('th', 'big numbers')
      ])
    ]),
    h('tbody', [
      h('tr', [
        h('td', `Why does ${bigAsk[0][0]} ask so many questions?
          ${roundTo(100 * bigAsk[0][1], 1)}% of their lines contained a
          question! ${bigAsk[1][0]} came in close second with
          ${roundTo(100 * bigAsk[1][1], 1)}% of their lines containing a
          question.`)
      ])
    ])
  ]);

  const content = h('div', [
    h('p', `Stats generated on ${moment.utc().toISOString()}`),
    h('p', `In the last 31 days, a total of ${Object.keys(users).length}
      different nicks were represented on destiny.gg.`),
    topUsers(users),
    bigNumbers
  ]);

  const html = fromString(`
    <!doctype html>
    <head>
      <meta charset="utf-8">
      <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
    ${createElement(content).toString()}
    </body>
    </html>
  `);

  html.pipe(inline({ignoreImages: true})).pipe(process.stdout);
}

streamEach(db.createValueStream(), onData, render);
<commit_msg>generate: only parse timestamp once<commit_after>const level = require('level');
const path = require('path');
const h = require('virtual-dom/h');
const createElement = require('virtual-dom/create-element');
const inline = require('html-inline');
const fromString = require('from2-string');
const process = require('process');
const moment = require('moment');
const wordcount = require('wordcount');
const roundTo = require('round-to');
const streamEach = require('stream-each');

const topUsers = require('./lib/top-users');
const mostQuestions = require('./lib/most-questions');

const db = level(path.resolve(__dirname, 'db'), {valueEncoding: 'json'});

const users = {};

function onData(data, next) {
  const time = moment.utc(data.timestamp, moment.ISO_8601);

  if (!users[data.user]) {
    users[data.user] = {
      lines: 0,
      avgWords: 0,
      quotes: [],
      latest: time,
      questions: 0
    };
  }

  users[data.user].lines++;

  // Cumulative moving average of the number of words in this user's messages.
  var avg = users[data.user].avgWords;
  avg += (wordcount(data.message) - avg) / users[data.user].lines;
  users[data.user].avgWords = avg;

  users[data.user].quotes.push(data.message);

  if (time.isAfter(users[data.user].latest)) {
    users[data.user].latest = time;
  }

  if (data.message.indexOf('?') !== -1) {
    users[data.user].questions++;
  }

  next();
}

function render() {
  const bigAsk = mostQuestions(users);

  const bigNumbers = h('table', [
    h('thead', [
      h('tr', [
        h('th', 'big numbers')
      ])
    ]),
    h('tbody', [
      h('tr', [
        h('td', `Why does ${bigAsk[0][0]} ask so many questions?
          ${roundTo(100 * bigAsk[0][1], 1)}% of their lines contained a
          question! ${bigAsk[1][0]} came in close second with
          ${roundTo(100 * bigAsk[1][1], 1)}% of their lines containing a
          question.`)
      ])
    ])
  ]);

  const content = h('div', [
    h('p', `Stats generated on ${moment.utc().toISOString()}`),
    h('p', `In the last 31 days, a total of ${Object.keys(users).length}
      different nicks were represented on destiny.gg.`),
    topUsers(users),
    bigNumbers
  ]);

  const html = fromString(`
    <!doctype html>
    <head>
      <meta charset="utf-8">
      <link rel="stylesheet" type="text/css" href="style.css">
    </head>
    <body>
    ${createElement(content).toString()}
    </body>
    </html>
  `);

  html.pipe(inline({ignoreImages: true})).pipe(process.stdout);
}

streamEach(db.createValueStream(), onData, render);
<|endoftext|>


<commit_before>/* eslint-env node */
/* eslint-disable camelcase */

const browsers = {
  safariMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Safari',
    browser_version: 'latest'
  },
  chromeMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  edgeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Edge',
    browser_version: '16'
  },
  edgeWin10Latest: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Edge',
    browser_version: 'latest'
  },
  chromeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  iphoneX: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '11.0',
    device: 'iPhone X',
    real_mobile: true
  },
  pixel2: {
    base: 'BrowserStack',
    os: 'android',
    os_version: '8.0',
    device: 'Google Pixel 2',
    real_mobile: true
  }
}

const browsersKeys = Object.keys(browsers)

module.exports = {
  browsers,
  browsersKeys
}
<commit_msg>BrowserStack: stop testing on latest Edge. (#31125)<commit_after>/* eslint-env node */
/* eslint-disable camelcase */

const browsers = {
  safariMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Safari',
    browser_version: 'latest'
  },
  chromeMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxMac: {
    base: 'BrowserStack',
    os: 'OS X',
    os_version: 'High Sierra',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  edgeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Edge',
    browser_version: '16'
  },
  chromeWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Chrome',
    browser_version: 'latest'
  },
  firefoxWin10: {
    base: 'BrowserStack',
    os: 'Windows',
    os_version: '10',
    browser: 'Firefox',
    browser_version: 'latest'
  },
  iphoneX: {
    base: 'BrowserStack',
    os: 'ios',
    os_version: '11.0',
    device: 'iPhone X',
    real_mobile: true
  },
  pixel2: {
    base: 'BrowserStack',
    os: 'android',
    os_version: '8.0',
    device: 'Google Pixel 2',
    real_mobile: true
  }
}

const browsersKeys = Object.keys(browsers)

module.exports = {
  browsers,
  browsersKeys
}
<|endoftext|>


<commit_before>module.exports = rimraf
rimraf.sync = rimrafSync

var path = require("path")
  , fs

try {
  // optional dependency
  fs = require("graceful-fs")
} catch (er) {
  fs = require("fs")
}

// for EMFILE handling
var timeout = 0
exports.EMFILE_MAX = 1000
exports.BUSYTRIES_MAX = 3

function rimraf (p, cb) {
  if (!cb) throw new Error("No callback passed to rimraf()")

  var busyTries = 0
  rimraf_(p, function CB (er) {
    if (er) {
      if (er.code === "EBUSY" && busyTries < exports.BUSYTRIES_MAX) {
        busyTries ++
        var time = busyTries * 100
        // try again, with the same exact callback as this one.
        return setTimeout(function () {
          rimraf_(p, CB)
        }, time)
      }

      // this one won't happen if graceful-fs is used.
      if (er.code === "EMFILE" && timeout < exports.EMFILE_MAX) {
        return setTimeout(function () {
          rimraf_(p, CB)
        }, timeout ++)
      }

      // already gone
      if (er.code === "ENOENT") er = null
    }

    timeout = 0
    cb(er)
  })
}

// Two possible strategies.
// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM
// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
//
// Both result in an extra syscall when you guess wrong.  However, there
// are likely far more normal files in the world than directories.  This
// is based on the assumption that a the average number of files per
// directory is >= 1.
//
// If anyone ever complains about this, then I guess the strategy could
// be made configurable somehow.  But until then, YAGNI.
function rimraf_ (p, cb) {
  fs.unlink(p, function (er) {
    if (er && er.code === "ENOENT")
      return cb()
    if (er && er.code === "EPERM")
      return rmdir(p, cb)
    return cb(er)
  })
}

function rmdir (p, cb) {
  fs.readdir(p, function (er, files) {
    if (er)
      return cb(er)
    var n = files.length
    if (n === 0)
      return fs.rmdir(p, cb)
    var errState
    files.forEach(function (f) {
      rimraf(path.join(p, f), function (er) {
        if (errState)
          return
        if (er)
          return cb(errState = er)
        if (--n === 0)
          fs.rmdir(p, cb)
      })
    })
  })
}

// this looks simpler, and is strictly *faster*, but will
// tie up the JavaScript thread and fail on excessively
// deep directory trees.
function rimrafSync (p) {
  try {
    fs.unlinkSync(p)
  } catch (er) {
    if (er.code === "ENOENT")
      return
    if (er.code !== "EPERM")
      throw er
    fs.readdirSync(p).forEach(function (f) {
      rimrafSync(path.join(p, f))
    })
    fs.rmdirSync(p)
  }
}
<commit_msg>Fix #15 Treat EISDIR like EPERM<commit_after>module.exports = rimraf
rimraf.sync = rimrafSync

var path = require("path")
  , fs

try {
  // optional dependency
  fs = require("graceful-fs")
} catch (er) {
  fs = require("fs")
}

// for EMFILE handling
var timeout = 0
exports.EMFILE_MAX = 1000
exports.BUSYTRIES_MAX = 3

function rimraf (p, cb) {
  if (!cb) throw new Error("No callback passed to rimraf()")

  var busyTries = 0
  rimraf_(p, function CB (er) {
    if (er) {
      if (er.code === "EBUSY" && busyTries < exports.BUSYTRIES_MAX) {
        busyTries ++
        var time = busyTries * 100
        // try again, with the same exact callback as this one.
        return setTimeout(function () {
          rimraf_(p, CB)
        }, time)
      }

      // this one won't happen if graceful-fs is used.
      if (er.code === "EMFILE" && timeout < exports.EMFILE_MAX) {
        return setTimeout(function () {
          rimraf_(p, CB)
        }, timeout ++)
      }

      // already gone
      if (er.code === "ENOENT") er = null
    }

    timeout = 0
    cb(er)
  })
}

// Two possible strategies.
// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
//
// Both result in an extra syscall when you guess wrong.  However, there
// are likely far more normal files in the world than directories.  This
// is based on the assumption that a the average number of files per
// directory is >= 1.
//
// If anyone ever complains about this, then I guess the strategy could
// be made configurable somehow.  But until then, YAGNI.
function rimraf_ (p, cb) {
  fs.unlink(p, function (er) {
    if (er && er.code === "ENOENT")
      return cb()
    if (er && (er.code === "EPERM" || er.code === "EISDIR"))
      return rmdir(p, cb)
    return cb(er)
  })
}

function rmdir (p, cb) {
  fs.readdir(p, function (er, files) {
    if (er)
      return cb(er)
    var n = files.length
    if (n === 0)
      return fs.rmdir(p, cb)
    var errState
    files.forEach(function (f) {
      rimraf(path.join(p, f), function (er) {
        if (errState)
          return
        if (er)
          return cb(errState = er)
        if (--n === 0)
          fs.rmdir(p, cb)
      })
    })
  })
}

// this looks simpler, and is strictly *faster*, but will
// tie up the JavaScript thread and fail on excessively
// deep directory trees.
function rimrafSync (p) {
  try {
    fs.unlinkSync(p)
  } catch (er) {
    if (er.code === "ENOENT")
      return
    if (er.code !== "EPERM" && er.code !== "EISDIR")
      throw er
    fs.readdirSync(p).forEach(function (f) {
      rimrafSync(path.join(p, f))
    })
    fs.rmdirSync(p)
  }
}
<|endoftext|>


<commit_before>/* jshint devel: true */
var PewPew = {};

!function() {
	'use strict';

	/**
	 * Upgrade class
	 */
	function Upgrade(name, maxLevel) {
		var self = this;
		this.name = name;
		this.maxLevel = maxLevel;
		this.level = 0;
		this.cost = function() {
			return (self.level + 1) * 100;
		};
		this.getElementId = function() {
			return "upgrade-" + self.name;
		};
		this.onBuy = function() {
			document.getElementById(self.getElementId() + "-cost").innerHTML = self
					.cost();
			document.getElementById(self.getElementId() + "-level").innerHTML = self.level;
		};
		this.getHtml = function() {
			return '
'
					+ self.name + "
" + 'Level: 0
'
					+ 'Cost: '
					+ self.cost() + "" + "
";
		};
		this.tryBuy = function() {
			if (self.level >= self.maxLevel) {
				return false;
			}
			if (PewPew.player.money < self.cost()) {
				return false;
			}
			PewPew.player.substractMoney(self.cost());
			self.level++;
			self.onBuy();
		};
	}

	/**
	 * player singleton
	 */
	PewPew.player = {
		money : 50000,
		upgrades : {
			damage : new Upgrade("damage", 10),
			income : new Upgrade("income", 10)
		},
		income : function() {
			return this.upgrades.income.level + 1;
		},
		damage : function() {
			return this.upgrades.damage.level + 1;
		},
		changeMoney : function(newMoney) {
			this.money = newMoney;
			document.getElementById("money").innerHTML = this.money;
		},
		addMoney : function(money) {
			return this.changeMoney(this.money + money);
		},
		substractMoney : function(money) {
			return this.addMoney(-money);
		}
	};
	/**
	 * Fill upgrades tab
	 */
	var html = "";
	for ( var upgrade in PewPew.player.upgrades) {
		if (PewPew.player.upgrades.hasOwnProperty(upgrade)) {
			html += PewPew.player.upgrades[upgrade].getHtml();
		}
	}
	document.getElementById("upgrade-tiles").innerHTML = html;
	// add the event listeners to the created buttons
	var upg;
	for (upgrade in PewPew.player.upgrades) {
		if (PewPew.player.upgrades.hasOwnProperty(upgrade)) {
			upg = PewPew.player.upgrades[upgrade];
			document.getElementById(upg.getElementId()).addEventListener(
					"click", upg.tryBuy);

		}
	}

	/**
	 * Enemy class
	 */
	function Enemy(hp, x, y, image, value) {
		var self = this;
		this.hp = hp;
		this.x = x;
		this.y = y;
		this.setX = function(x) {
			self.x = x;
		};
		this.setY = function(y) {
			self.y = y;
		};
		this.image = image;
		this.value = value;
		/**
		 * deals damage to the enemy
		 */
		this.recieveDamage = function(damage) {
			self.hp -= damage;
			if (self.hp <= 0) {
				self.onDestroy();
			}
		};
		/**
		 * called when an enemy is destroyed
		 */
		this.onDestroy = function() {
			PewPew.player.addMoney(self.value * PewPew.player.income());
			var index = PewPew.game.enemies.indexOf(self);
			if (index > -1) {
				PewPew.game.enemies.splice(index, 1);
			}
		};
		PewPew.game.enemies[game.enemies.length] = this;
	}

	PewPew.game = {
		level : 1,
		enemies : [],
		handleHit : function(evt) {
			evt.preventDefault();
			var touches = event.changedTouches;
			var touchId, x, y;
			for (var i = 0; i < event.changedTouches.length; i++) {
				touchId = event.changedTouches[i].identifier;
				x = event.changedTouches[i].pageX;
				y = event.changedTouches[i].pageY;
				for (var enemy in enemies) {
					//test if the enemy is hit
					if(x>=enemy.x && x<=enemy.x+enemy.image.width && y>=enemy.y&&y<=enemy.y+enemy.image.height){
						enemy.receiveDamage(PewPew.player.damage());
					}
				}
			}

		}
	};

	PewPew.canvas = {
		element : document.getElementById("canvas"),
		context : PewPew.canvas.element.getContext("2d"),
	};
	PewPew.canvas.element.addEventListener("touch", PewPew.game.handleHit
			.bind(PewPew.game));
}();<commit_msg>Add some enemy drawing on canvas<commit_after>/* jshint devel: true */
var PewPew = {};

!function() {
	'use strict';

	/**
	 * Upgrade class
	 */
	function Upgrade(name, maxLevel) {
		var self = this;
		this.name = name;
		this.maxLevel = maxLevel;
		this.level = 0;
		this.cost = function() {
			return (self.level + 1) * 100;
		};
		this.getElementId = function() {
			return "upgrade-" + self.name;
		};
		this.onBuy = function() {
			document.getElementById(self.getElementId() + "-cost").innerHTML = self
					.cost();
			document.getElementById(self.getElementId() + "-level").innerHTML = self.level;
		};
		this.getHtml = function() {
			return '
'
					+ self.name + "
" + 'Level: 0
'
					+ 'Cost: '
					+ self.cost() + "" + "
";
		};
		this.tryBuy = function() {
			if (self.level >= self.maxLevel) {
				return false;
			}
			if (PewPew.player.money < self.cost()) {
				return false;
			}
			PewPew.player.substractMoney(self.cost());
			self.level++;
			self.onBuy();
		};
	}

	/**
	 * player singleton
	 */
	PewPew.player = {
		money : 50000,
		upgrades : {
			damage : new Upgrade("damage", 10),
			income : new Upgrade("income", 10)
		},
		income : function() {
			return this.upgrades.income.level + 1;
		},
		damage : function() {
			return this.upgrades.damage.level + 1;
		},
		changeMoney : function(newMoney) {
			this.money = newMoney;
			document.getElementById("money").innerHTML = this.money;
		},
		addMoney : function(money) {
			return this.changeMoney(this.money + money);
		},
		substractMoney : function(money) {
			return this.addMoney(-money);
		}
	};
	/**
	 * Fill upgrades tab
	 */
	var html = "";
	for ( var upgrade in PewPew.player.upgrades) {
		if (PewPew.player.upgrades.hasOwnProperty(upgrade)) {
			html += PewPew.player.upgrades[upgrade].getHtml();
		}
	}
	document.getElementById("upgrade-tiles").innerHTML = html;
	// add the event listeners to the created buttons
	var upg;
	for (upgrade in PewPew.player.upgrades) {
		if (PewPew.player.upgrades.hasOwnProperty(upgrade)) {
			upg = PewPew.player.upgrades[upgrade];
			document.getElementById(upg.getElementId()).addEventListener(
					"click", upg.tryBuy);

		}
	}

	/**
	 * Enemy class
	 */
	function Enemy(hp, x, y, image, value) {
		var self = this;
		this.hp = hp;
		this.x = x;
		this.y = y;
		this.setX = function(x) {
			self.x = x;
		};
		this.setY = function(y) {
			self.y = y;
		};
		this.image = image;
		this.value = value;
		/**
		 * deals damage to the enemy
		 */
		this.recieveDamage = function(damage) {
			self.hp -= damage;
			if (self.hp <= 0) {
				self.onDestroy();
			}
		};
		/**
		 * called when an enemy is destroyed
		 */
		this.onDestroy = function() {
			PewPew.player.addMoney(self.value * PewPew.player.income());
			var index = PewPew.game.enemies.indexOf(self);
			if (index > -1) {
				PewPew.game.enemies.splice(index, 1);
			}
			// redraw the scene
			PewPew.canvas.context.clearRect(0, 0, PewPew.canvas.width,
					PewPew.canvas.height);
			for ( var enemy in PewPew.game.enemies) {
				PewPew.canvas.context.drawImage(enemy.canvasImage, enemy.x,
						enemy.y);
			}
		};
		this.canvasImage = new Image();
		this.canvasImage.src = this.image;
		this.canvasImage.onload = function() {
			PewPew.canvas.context.drawImage(self.canvasImage, self.x, self.y);
		};

		PewPew.game.enemies[game.enemies.length] = this;
	}

	PewPew.game = {
		level : 1,
		enemies : [],
		handleHit : function(evt) {
			evt.preventDefault();
			var touches = event.changedTouches;
			var touchId, x, y;
			for (var i = 0; i < event.changedTouches.length; i++) {
				touchId = event.changedTouches[i].identifier;
				x = event.changedTouches[i].pageX;
				y = event.changedTouches[i].pageY;
				for ( var enemy in enemies) {
					// test if the enemy is hit
					if (x >= enemy.x && x <= enemy.x + enemy.image.width
							&& y >= enemy.y
							&& y <= enemy.y + enemy.image.height) {
						enemy.receiveDamage(PewPew.player.damage());
					}
				}
			}

		}
	};

	PewPew.canvas = {
		element : document.getElementById("canvas"),
		context : PewPew.canvas.element.getContext("2d"),
	};
	PewPew.canvas.element.addEventListener("touch", PewPew.game.handleHit
			.bind(PewPew.game));
}();<|endoftext|>


<commit_before>import React, { Component, useState, useEffect, useMemo } from "react";
import Rect from './elements/Rect';
import Circle from './elements/Circle';
import Ellipse from './elements/Ellipse';
import Polygon from './elements/Polygon';
import Polyline from './elements/Polyline';
import Line from './elements/Line';
import Svg from './elements/Svg';
import Path from './elements/Path';
import G from './elements/G';
import Text from './elements/Text';
import TSpan from './elements/TSpan';
import TextPath from './elements/TextPath';
import Use from './elements/Use';
import Image from './elements/Image';
import Symbol from './elements/Symbol';
import Defs from './elements/Defs';
import LinearGradient from './elements/LinearGradient';
import RadialGradient from './elements/RadialGradient';
import Stop from './elements/Stop';
import ClipPath from './elements/ClipPath';
import Pattern from './elements/Pattern';
import Mask from './elements/Mask';

export const tags = {
  svg: Svg,
  circle: Circle,
  ellipse: Ellipse,
  g: G,
  text: Text,
  tspan: TSpan,
  textPath: TextPath,
  path: Path,
  polygon: Polygon,
  polyline: Polyline,
  line: Line,
  rect: Rect,
  use: Use,
  image: Image,
  symbol: Symbol,
  defs: Defs,
  linearGradient: LinearGradient,
  radialGradient: RadialGradient,
  stop: Stop,
  clipPath: ClipPath,
  pattern: Pattern,
  mask: Mask
};

export function SvgAst({ ast, override }) {
  const { props, children } = ast;
  return (
    <Svg {...props} {...override}>
      {children}
    </Svg>
  );
}

export function SvgXml({ xml, ...props }) {
  const ast = useMemo(() => xml && parse(xml), [xml]);
  return (ast && <SvgAst ast={ast} override={props} />) || null;
}

async function fetchText(uri) {
  const response = await fetch(uri);
  return await response.text();
}

const err = console.error.bind(console);

export function SvgUri({ uri, ...props }) {
  const [xml, setXml] = useState();
  useEffect(() => {
    fetchText(uri)
      .then(setXml)
      .catch(err);
  }, [uri]);
  return (xml && <SvgXml xml={xml} {...props} />) || null;
}

// Extending Component is required for Animated support.

export class SvgFromXml extends Component {
  state = {};
  componentDidMount() {
    const { xml } = this.props;
    this.parse(xml);
  }
  componentDidUpdate(prevProps) {
    const { xml } = this.props;
    if (xml !== prevProps.xml) {
      this.parse(xml);
    }
  }
  parse(xml) {
    try {
      const ast = parse(xml);
      this.setState({ ast });
    } catch (e) {
      console.error(e);
    }
  }
  render() {
    const { ast } = this.state;
    return ast ? <SvgAst ast={ast} override={this.props} /> : null;
  }
}

export class SvgFromUri extends Component {
  state = {};
  componentDidMount() {
    const { uri } = this.props;
    this.fetch(uri);
  }
  componentDidUpdate(prevProps) {
    const { uri } = this.props;
    if (uri !== prevProps.uri) {
      this.fetch(uri);
    }
  }
  async fetch(uri) {
    try {
      const xml = await fetchText(uri);
      this.setState({ xml });
    } catch (e) {
      console.error(e);
    }
  }
  render() {
    const { xml } = this.state;
    return xml ? <SvgFromXml xml={xml} {...this.props} /> : null;
  }
}

const upperCase = (match, letter) => letter.toUpperCase();

const camelCase = phrase => phrase.replace(/-([a-z])/g, upperCase);

export function getStyle(string) {
  const style = {};
  const declarations = string.split(";");
  for (let i = 0, l = declarations.length; i < l; i++) {
    const declaration = declarations[i].split(":");
    const property = declaration[0];
    const value = declaration[1];
    style[camelCase(property.trim())] = value.trim();
  }
  return style;
}

export function astToReact(child, i) {
  if (typeof child === "object") {
    const { Tag, props, children } = child;
    return (
      <Tag key={i} {...props}>
        {children.map(astToReact)}
      </Tag>
    );
  }
  return child;
}

// slimmed down parser based on https://github.com/Rich-Harris/svg-parser

function locate(source, search) {
  const lines = source.split("\n");
  for (let line = 0, l = lines.length; line < l; line++) {
    const { length } = lines[line];
    if (search < length) {
      return { line, column: search };
    } else {
      search -= length;
    }
  }
}

const validNameCharacters = /[a-zA-Z0-9:_-]/;
const whitespace = /[\s\t\r\n]/;
const quotemark = /['"]/;

function repeat(str, i) {
  let result = "";
  while (i--) result += str;
  return result;
}

export function parse(source) {
  const length = source.length;
  let currentElement = null;
  let state = metadata;
  let children = null;
  let root = null;
  let stack = [];

  function error(message) {
    const { line, column } = locate(source, i);
    const before = source
      .slice(0, i)
      .replace(/^\t+/, match => repeat("  ", match.length));
    const beforeLine = /(^|\n).*$/.exec(before)[0];
    const after = source.slice(i);
    const afterLine = /.*(\n|$)/.exec(after)[0];

    const snippet = `${beforeLine}${afterLine}\n${repeat(
      " ",
      beforeLine.length
    )}^`;

    throw new Error(
      `${message} (${line}:${column}). If this is valid SVG, it's probably a bug. Please raise an issue\n\n${snippet}`
    );
  }

  function metadata() {
    while (
      (i < length && source[i] !== "<") ||
      !validNameCharacters.test(source[i + 1])
      ) {
      i++;
    }

    return neutral();
  }

  function neutral() {
    let text = "";
    while (i < length && source[i] !== "<") text += source[i++];

    if (/\S/.test(text)) {
      children.push(text);
    }

    if (source[i] === "<") {
      return openingTag;
    }

    return neutral;
  }

  function openingTag() {
    const char = source[i];

    if (char === "?") return neutral; // <?xml...

    if (char === "!") {
      if (source.slice(i + 1, i + 3) === "--") return comment;
      if (source.slice(i + 1, i + 8) === "[CDATA[") return cdata;
      if (/doctype/i.test(source.slice(i + 1, i + 8))) return neutral;
    }

    if (char === "/") return closingTag;

    const tag = getName();
    const props = {};
    const element = {
      tag,
      props,
      children: [],
      Tag: tags[tag]
    };

    if (currentElement) {
      children.push(element);
    } else {
      root = element;
    }

    getAttributes(props);

    const { style } = props;
    if (style) {
      props.style = getStyle(style);
    }

    let selfClosing = false;

    if (source[i] === "/") {
      i += 1;
      selfClosing = true;
    }

    if (source[i] !== ">") {
      error("Expected >");
    }

    if (!selfClosing) {
      currentElement = element;
      ({ children } = element);
      stack.push(element);
    }

    return neutral;
  }

  function comment() {
    const index = source.indexOf("-->", i);
    if (!~index) error("expected -->");

    i = index + 2;
    return neutral;
  }

  function cdata() {
    const index = source.indexOf("]]>", i);
    if (!~index) error("expected ]]>");

    i = index + 2;
    return neutral;
  }

  function closingTag() {
    const tag = getName();

    if (!tag) error("Expected tag name");

    if (tag !== currentElement.tag) {
      error(
        `Expected closing tag </${tag}> to match opening tag <${
          currentElement.tag
          }>`
      );
    }

    if (source[i] !== ">") {
      error("Expected >");
    }

    stack.pop();
    currentElement = stack[stack.length - 1];
    if (currentElement) {
      ({ children } = currentElement);
    }

    return neutral;
  }

  function getName() {
    let name = "";
    while (i < length && validNameCharacters.test(source[i]))
      name += source[i++];

    return name;
  }

  function getAttributes(props) {
    while (i < length) {
      if (!whitespace.test(source[i])) return;
      allowSpaces();

      const name = getName();
      if (!name) return;

      let value = true;

      allowSpaces();
      if (source[i] === "=") {
        i += 1;
        allowSpaces();

        value = getAttributeValue();
        if (!isNaN(value) && value.trim() !== "") value = +value;
      }

      props[camelCase(name)] = value;
    }
  }

  function getAttributeValue() {
    return quotemark.test(source[i])
      ? getQuotedAttributeValue()
      : getUnquotedAttributeValue();
  }

  function getUnquotedAttributeValue() {
    let value = "";
    do {
      const char = source[i];
      if (char === " " || char === ">" || char === "/") {
        return value;
      }

      value += char;
      i += 1;
    } while (i < length);

    return value;
  }

  function getQuotedAttributeValue() {
    const quotemark = source[i++];

    let value = "";
    let escaped = false;

    while (i < length) {
      const char = source[i++];
      if (char === quotemark && !escaped) {
        return value;
      }

      if (char === "\\" && !escaped) {
        escaped = true;
      }

      value += escaped ? `\\${char}` : char;
      escaped = false;
    }
  }

  function allowSpaces() {
    while (i < length && whitespace.test(source[i])) i += 1;
  }

  let i = 0;
  while (i < length) {
    if (!state) error("Unexpected character");
    state = state();
    i += 1;
  }

  if (state !== neutral) {
    error("Unexpected end of input");
  }

  root.children = root.children.map(astToReact);

  return root;
}
<commit_msg>fix: handle optional semi-colon in the end of xml style attributes<commit_after>import React, { Component, useState, useEffect, useMemo } from "react";
import Rect from './elements/Rect';
import Circle from './elements/Circle';
import Ellipse from './elements/Ellipse';
import Polygon from './elements/Polygon';
import Polyline from './elements/Polyline';
import Line from './elements/Line';
import Svg from './elements/Svg';
import Path from './elements/Path';
import G from './elements/G';
import Text from './elements/Text';
import TSpan from './elements/TSpan';
import TextPath from './elements/TextPath';
import Use from './elements/Use';
import Image from './elements/Image';
import Symbol from './elements/Symbol';
import Defs from './elements/Defs';
import LinearGradient from './elements/LinearGradient';
import RadialGradient from './elements/RadialGradient';
import Stop from './elements/Stop';
import ClipPath from './elements/ClipPath';
import Pattern from './elements/Pattern';
import Mask from './elements/Mask';

export const tags = {
  svg: Svg,
  circle: Circle,
  ellipse: Ellipse,
  g: G,
  text: Text,
  tspan: TSpan,
  textPath: TextPath,
  path: Path,
  polygon: Polygon,
  polyline: Polyline,
  line: Line,
  rect: Rect,
  use: Use,
  image: Image,
  symbol: Symbol,
  defs: Defs,
  linearGradient: LinearGradient,
  radialGradient: RadialGradient,
  stop: Stop,
  clipPath: ClipPath,
  pattern: Pattern,
  mask: Mask
};

export function SvgAst({ ast, override }) {
  const { props, children } = ast;
  return (
    <Svg {...props} {...override}>
      {children}
    </Svg>
  );
}

export function SvgXml({ xml, ...props }) {
  const ast = useMemo(() => xml && parse(xml), [xml]);
  return (ast && <SvgAst ast={ast} override={props} />) || null;
}

async function fetchText(uri) {
  const response = await fetch(uri);
  return await response.text();
}

const err = console.error.bind(console);

export function SvgUri({ uri, ...props }) {
  const [xml, setXml] = useState();
  useEffect(() => {
    fetchText(uri)
      .then(setXml)
      .catch(err);
  }, [uri]);
  return (xml && <SvgXml xml={xml} {...props} />) || null;
}

// Extending Component is required for Animated support.

export class SvgFromXml extends Component {
  state = {};
  componentDidMount() {
    const { xml } = this.props;
    this.parse(xml);
  }
  componentDidUpdate(prevProps) {
    const { xml } = this.props;
    if (xml !== prevProps.xml) {
      this.parse(xml);
    }
  }
  parse(xml) {
    try {
      const ast = parse(xml);
      this.setState({ ast });
    } catch (e) {
      console.error(e);
    }
  }
  render() {
    const { ast } = this.state;
    return ast ? <SvgAst ast={ast} override={this.props} /> : null;
  }
}

export class SvgFromUri extends Component {
  state = {};
  componentDidMount() {
    const { uri } = this.props;
    this.fetch(uri);
  }
  componentDidUpdate(prevProps) {
    const { uri } = this.props;
    if (uri !== prevProps.uri) {
      this.fetch(uri);
    }
  }
  async fetch(uri) {
    try {
      const xml = await fetchText(uri);
      this.setState({ xml });
    } catch (e) {
      console.error(e);
    }
  }
  render() {
    const { xml } = this.state;
    return xml ? <SvgFromXml xml={xml} {...this.props} /> : null;
  }
}

const upperCase = (match, letter) => letter.toUpperCase();

const camelCase = phrase => phrase.replace(/-([a-z])/g, upperCase);

export function getStyle(string) {
  const style = {};
  const declarations = string.split(";");
  const { length } = declarations;
  for (let i = 0; i < length; i++) {
    const declaration = declarations[i];
    if (declaration.length !== 0) {
      const split = declaration.split(":");
      const property = split[0];
      const value = split[1];
    style[camelCase(property.trim())] = value.trim();
  }
  }
  return style;
}

export function astToReact(child, i) {
  if (typeof child === "object") {
    const { Tag, props, children } = child;
    return (
      <Tag key={i} {...props}>
        {children.map(astToReact)}
      </Tag>
    );
  }
  return child;
}

// slimmed down parser based on https://github.com/Rich-Harris/svg-parser

function locate(source, search) {
  const lines = source.split("\n");
  const nLines = lines.length;
  for (let line = 0; line < nLines; line++) {
    const { length } = lines[line];
    if (search < length) {
      return { line, column: search };
    } else {
      search -= length;
    }
  }
}

const validNameCharacters = /[a-zA-Z0-9:_-]/;
const whitespace = /[\s\t\r\n]/;
const quotemark = /['"]/;

function repeat(str, i) {
  let result = "";
  while (i--) result += str;
  return result;
}

export function parse(source) {
  const length = source.length;
  let currentElement = null;
  let state = metadata;
  let children = null;
  let root = null;
  let stack = [];

  function error(message) {
    const { line, column } = locate(source, i);
    const before = source
      .slice(0, i)
      .replace(/^\t+/, match => repeat("  ", match.length));
    const beforeLine = /(^|\n).*$/.exec(before)[0];
    const after = source.slice(i);
    const afterLine = /.*(\n|$)/.exec(after)[0];

    const snippet = `${beforeLine}${afterLine}\n${repeat(
      " ",
      beforeLine.length
    )}^`;

    throw new Error(
      `${message} (${line}:${column}). If this is valid SVG, it's probably a bug. Please raise an issue\n\n${snippet}`
    );
  }

  function metadata() {
    while (
      i + 1 < length &&
      (source[i] !== "<" || !validNameCharacters.test(source[i + 1]))
      ) {
      i++;
    }

    return neutral();
  }

  function neutral() {
    let text = "";
    let char;
    while (i < length && (char = source[i]) !== "<") {
      text += char;
      i += 1;
    }

    if (/\S/.test(text)) {
      children.push(text);
    }

    if (source[i] === "<") {
      return openingTag;
    }

    return neutral;
  }

  function openingTag() {
    const char = source[i];

    if (char === "?") return neutral; // <?xml...

    if (char === "!") {
      let start = i + 1;
      if (source.slice(start, i + 3) === "--") return comment;
      if (source.slice(start, i + 8) === "[CDATA[") return cdata;
      if (/doctype/i.test(source.slice(start, i + 8))) return neutral;
    }

    if (char === "/") return closingTag;

    const tag = getName();
    const props = {};
    const element = {
      tag,
      props,
      children: [],
      Tag: tags[tag]
    };

    if (currentElement) {
      children.push(element);
    } else {
      root = element;
    }

    getAttributes(props);

    const { style } = props;
    if (style) {
      props.style = getStyle(style);
    }

    let selfClosing = false;

    if (source[i] === "/") {
      i += 1;
      selfClosing = true;
    }

    if (source[i] !== ">") {
      error("Expected >");
    }

    if (!selfClosing) {
      currentElement = element;
      ({ children } = element);
      stack.push(element);
    }

    return neutral;
  }

  function comment() {
    const index = source.indexOf("-->", i);
    if (!~index) error("expected -->");

    i = index + 2;
    return neutral;
  }

  function cdata() {
    const index = source.indexOf("]]>", i);
    if (!~index) error("expected ]]>");

    i = index + 2;
    return neutral;
  }

  function closingTag() {
    const tag = getName();

    if (!tag) error("Expected tag name");

    if (tag !== currentElement.tag) {
      error(
        `Expected closing tag </${tag}> to match opening tag <${
          currentElement.tag
          }>`
      );
    }

    if (source[i] !== ">") {
      error("Expected >");
    }

    stack.pop();
    currentElement = stack[stack.length - 1];
    if (currentElement) {
      ({ children } = currentElement);
    }

    return neutral;
  }

  function getName() {
    let name = "";
    let char;
    while (i < length && validNameCharacters.test((char = source[i]))) {
      name += char;
      i += 1;
    }

    return name;
  }

  function getAttributes(props) {
    while (i < length) {
      if (!whitespace.test(source[i])) return;
      allowSpaces();

      const name = getName();
      if (!name) return;

      let value = true;

      allowSpaces();
      if (source[i] === "=") {
        i += 1;
        allowSpaces();

        value = getAttributeValue();
        if (!isNaN(value) && value.trim() !== "") value = +value;
      }

      props[camelCase(name)] = value;
    }
  }

  function getAttributeValue() {
    return quotemark.test(source[i])
      ? getQuotedAttributeValue()
      : getUnquotedAttributeValue();
  }

  function getUnquotedAttributeValue() {
    let value = "";
    do {
      const char = source[i];
      if (char === " " || char === ">" || char === "/") {
        return value;
      }

      value += char;
      i += 1;
    } while (i < length);

    return value;
  }

  function getQuotedAttributeValue() {
    const quotemark = source[i++];

    let value = "";
    let escaped = false;

    while (i < length) {
      const char = source[i++];
      if (char === quotemark && !escaped) {
        return value;
      }

      if (char === "\\" && !escaped) {
        escaped = true;
      }

      value += escaped ? `\\${char}` : char;
      escaped = false;
    }
  }

  function allowSpaces() {
    while (i < length && whitespace.test(source[i])) i += 1;
  }

  let i = 0;
  while (i < length) {
    if (!state) error("Unexpected character");
    state = state();
    i += 1;
  }

  if (state !== neutral) {
    error("Unexpected end of input");
  }

  root.children = root.children.map(astToReact);

  return root;
}
<|endoftext|>


<commit_before>/*!
 * jQuery Equal Height v0.0.1 (https://github.com/Nikker/jquery.equal-height)
 * Copyright 2015-2016 Nikki DelRosso
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
if (typeof jQuery === 'undefined') {
  throw new Error('The jQuery equal height extension requires jQuery!');
}

jQuery.fn.equalHeight = function() {

	var $ = jQuery;
	var that = this;

	var setHeights = function() {
		var elems = {};
		var cont = $(that);

		// Reset the elements heights
		cont.each(function() {
			$(this).height('');
		});

		// Create a mapping of elements and the max height for all elements at that top offset
		cont.each(function() {
			var t = $(this).offset().top;
			if (typeof elems[t] == "undefined") elems[t] = {maxHeight: 0, e: []};
			elems[t].e.push($(this));
			elems[t].maxHeight = Math.max($(this).outerHeight(), elems[t].maxHeight);
		});

		// Apply the max height to all elements in each offset class
		for (var t in elems) {
			var mh = elems[t].maxHeight;
			for (var i in elems[t].e) {
				var e = elems[t].e[i];
				var padding = e.outerHeight() - e.height();
				e.height(mh - padding);
			}
		}
	};

	setHeights();
	$(window).resize(setHeights);
	$(this).find('img').load(setHeights);
};
<commit_msg>Update heights on page fully loaded<commit_after>/*!
 * jQuery Equal Height v0.0.2 (https://github.com/Nikker/jquery.equal-height)
 * Copyright 2015-2016 Nikki DelRosso
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */
if (typeof jQuery === 'undefined') {
  throw new Error('The jQuery equal height extension requires jQuery!');
}

jQuery.fn.equalHeight = function() {

	var $ = jQuery;
	var that = this;

	var setHeights = function() {
		var elems = {};
		var cont = $(that);

		// Reset the elements heights
		cont.each(function() {
			$(this).height('');
		});

		// Create a mapping of elements and the max height for all elements at that top offset
		cont.each(function() {
			var t = $(this).offset().top;
			if (typeof elems[t] == "undefined") elems[t] = {maxHeight: 0, e: []};
			elems[t].e.push($(this));
			elems[t].maxHeight = Math.max($(this).outerHeight(), elems[t].maxHeight);
		});

		// Apply the max height to all elements in each offset class
		for (var t in elems) {
			var mh = elems[t].maxHeight;
			for (var i in elems[t].e) {
				var e = elems[t].e[i];
				var padding = e.outerHeight() - e.height();
				e.height(mh - padding);
			}
		}
	};

	setHeights();
	$(window).resize(setHeights);
	$(this).find('img').load(setHeights);
	$(window).bind('load', setHeights);
};
<|endoftext|>


<commit_before>require('../../helper');
var assert = require('../../support/assert');

var TestClient = require('../../support/test-client');
var BatchTestClient = require('../../support/batch-test-client');
var JobStatus = require('../../../batch/job_status');

describe('multiple batch clients job query order', function() {

    before(function(done) {
        this.batchTestClient1 = new BatchTestClient({ name: 'consumerA' });
        this.batchTestClient2 = new BatchTestClient({ name: 'consumerB' });

        this.testClient = new TestClient();
        this.testClient.getResult('create table ordered_inserts (status numeric)', done);
    });

    after(function (done) {
        this.batchTestClient1.drain(function(err) {
            if (err) {
                return done(err);
            }

            this.batchTestClient2.drain(function(err) {
                if (err) {
                    return done(err);
                }

                this.testClient.getResult('drop table ordered_inserts', done);
            }.bind(this));
        }.bind(this));
    });

    function createJob(queries) {
        return {
            query: queries
        };
    }

    it('should run job queries in order (multiple consumers)', function (done) {
        var jobRequest1 = createJob(["insert into ordered_inserts values(1)", "insert into ordered_inserts values(2)"]);
        var jobRequest2 = createJob(["insert into ordered_inserts values(3)"]);

        var self = this;

        this.batchTestClient1.createJob(jobRequest1, function(err, jobResult1) {
            if (err) {
                return done(err);
            }
            this.batchTestClient2.createJob(jobRequest2, function(err, jobResult2) {
                if (err) {
                    return done(err);
                }

                jobResult1.getStatus(function (err, job1) {
                    if (err) {
                        return done(err);
                    }
                    jobResult2.getStatus(function(err, job2) {
                        if (err) {
                            return done(err);
                        }
                        assert.equal(job1.status, JobStatus.DONE);
                        assert.equal(job2.status, JobStatus.DONE);

                        self.testClient.getResult('select * from ordered_inserts', function(err, rows) {
                            assert.ok(!err);

                            assert.deepEqual(rows, [{ status: 1 }, { status: 2 }, { status: 3 }]);
                            assert.ok(
                                new Date(job1.updated_at).getTime() < new Date(job2.updated_at).getTime(),
                                'job1 (' + job1.updated_at + ') should finish before job2 (' + job2.updated_at + ')'
                            );
                            done();
                        });

                    });
                });
            });
        }.bind(this));
    });

});
<commit_msg>Drop table if exists<commit_after>require('../../helper');
var assert = require('../../support/assert');

var TestClient = require('../../support/test-client');
var BatchTestClient = require('../../support/batch-test-client');
var JobStatus = require('../../../batch/job_status');

describe('multiple batch clients job query order', function() {

    before(function(done) {
        this.batchTestClient1 = new BatchTestClient({ name: 'consumerA' });
        this.batchTestClient2 = new BatchTestClient({ name: 'consumerB' });

        this.testClient = new TestClient();
        this.testClient.getResult(
            'drop table if exists ordered_inserts; create table ordered_inserts (status numeric)',
            done
        );
    });

    after(function (done) {
        this.batchTestClient1.drain(function(err) {
            if (err) {
                return done(err);
            }

            this.batchTestClient2.drain(done);
        }.bind(this));
    });

    function createJob(queries) {
        return {
            query: queries
        };
    }

    it('should run job queries in order (multiple consumers)', function (done) {
        var jobRequest1 = createJob(["insert into ordered_inserts values(1)", "insert into ordered_inserts values(2)"]);
        var jobRequest2 = createJob(["insert into ordered_inserts values(3)"]);

        var self = this;

        this.batchTestClient1.createJob(jobRequest1, function(err, jobResult1) {
            if (err) {
                return done(err);
            }
            this.batchTestClient2.createJob(jobRequest2, function(err, jobResult2) {
                if (err) {
                    return done(err);
                }

                jobResult1.getStatus(function (err, job1) {
                    if (err) {
                        return done(err);
                    }
                    jobResult2.getStatus(function(err, job2) {
                        if (err) {
                            return done(err);
                        }
                        assert.equal(job1.status, JobStatus.DONE);
                        assert.equal(job2.status, JobStatus.DONE);

                        self.testClient.getResult('select * from ordered_inserts', function(err, rows) {
                            assert.ok(!err);

                            assert.deepEqual(rows, [{ status: 1 }, { status: 2 }, { status: 3 }]);
                            assert.ok(
                                new Date(job1.updated_at).getTime() < new Date(job2.updated_at).getTime(),
                                'job1 (' + job1.updated_at + ') should finish before job2 (' + job2.updated_at + ')'
                            );
                            done();
                        });

                    });
                });
            });
        }.bind(this));
    });

});
<|endoftext|>


<commit_before>(function (mt) {

    mt.player = {};

    /**
     * @param {YT.Player} delegate
     * @constructor
     */
    mt.player.YoutubePlayer = function (delegate) {
        var self = this;

        self.fadeDuration = 5000;

        self.delegate = delegate;
        self.busy = false;
        self.lastSampledTime = 0;
        self.canPlayThroughDeferred = undefined;
        self.endOfFadeDeferred = undefined;
        self.listeners = {timeupdate: {}};

        self.delegate.addEventListener('onStateChange', function (evt) {
            console.debug('onStateChange executed', evt.data);

            if (evt.data === YT.PlayerState.PLAYING) {
                // end of first buffering phase is considered as a can play through event
                self.canPlayThroughDeferred.resolve();
            }
        });
    };

    /**
     * Clears the previous playback state and initialize required objects for the next one.
     */
    mt.player.YoutubePlayer.prototype.reset = function () {
        var self = this;

        self.lastSampledTime = 0;

        // clear previous state
        if (self.canPlayThroughDeferred) {
            self.canPlayThroughDeferred.reject();
        }

        if (self.endOfFadeDeferred) {
            self.endOfFadeDeferred.resolve();
        }

        // install new state
        self.canPlayThroughDeferred = jQuery.Deferred();
        self.canPlayThroughDeferred.done(function () {
            self.delegate.pauseVideo();
        });

        // make the player silent and invisible
        self.fade('out', 0);
    };

    /**
     * @param {string} key the listener unique key, can be used to remove it later
     * @param {function} listener the listener function
     */
    mt.player.YoutubePlayer.prototype.addTimeUpdateListener = function (key, listener) {
        this.listeners.timeupdate[key] = this.listeners.timeupdate[key] || [];
        this.listeners.timeupdate[key].push(listener);
    };

    /**
     * @param {string} key
     */
    mt.player.YoutubePlayer.prototype.removeTimeUpdateListener = function (key) {
        if (key in this.listeners.timeupdate) {
            this.listeners.timeupdate[key] = [];
        }
    };

    /**
     * Clears the previous playback (stop a execute all promises) and start to load the given video.
     *
     * @param {string} videoId
     * @return {jQuery.promise} resolved when the video can play through the end without stop
     */
    mt.player.YoutubePlayer.prototype.loadVideo = function (videoId) {
        var self = this;

        self.reset();

        self.busy = true;

        // load the video, and when the video will start to play, we will pause it, see canPlayThroughDeferred
        self.delegate.loadVideoById({videoId: videoId, suggestedQuality: 'small'});

        // poll the current video position to generate the timeupdate event
        self.sampleTimeInterval = setInterval(function () {
            var sampledTime = self.delegate.getCurrentTime() * 1000;
            if (self.lastSampledTime !== sampledTime) {
                var event = {currentTime: sampledTime};

                for (var key in self.listeners.timeupdate)
                    for (var idxCallback = 0; idxCallback < self.listeners.timeupdate[key].length; idxCallback++) {
                        var callback = self.listeners.timeupdate[key][idxCallback];
                        callback(event);
                    }
            }
            self.lastSampledTime = sampledTime;
        }, 100);

        return self.canPlayThroughDeferred.promise();
    };

    /**
     * Starts the previously loaded video.
     */
    mt.player.YoutubePlayer.prototype.playVideo = function () {
        this.delegate.playVideo();
    };

    /**
     * Stops the video and release the player for further usage.
     */
    mt.player.YoutubePlayer.prototype.stopVideo = function () {
        clearInterval(this.sampleTimeInterval);
        this.delegate.stopVideo();
        this.busy = false;
    };

    /**
     * Fades the player without modifying the playback status (no play or stop call).
     *
     * If there was a pending fade operation, it is terminated so that it jumps to the end values. If duration is equal
     * to 0, it means immediate transition.
     *
     * @param {string} direction "in" or "out"
     * @param {number} duration the duration in milliseconds
     * @return {jQuery.promise} resolved when the fade operation is finished
     */
    mt.player.YoutubePlayer.prototype.fade = function (direction, duration) {
        var bounds = {'in': {start: 0, end: 100}, out: {start: 100, end: 0}};
        var self = this;
        var immediate = duration === 0;

        if (self.endOfFadeDeferred) {
            // there is a pending fade operation, ensure it is resolved
            self.endOfFadeDeferred.resolve();
        }

        self.endOfFadeDeferred = jQuery.Deferred();

        var playerStyle = self.delegate.getIframe().style;

        // remove transition and set extreme values when it is resolved
        self.endOfFadeDeferred.always(function () {
            playerStyle['-webkit-transition'] = '';
            playerStyle.opacity = bounds[direction].end;
            self.delegate.setVolume(bounds[direction].end);
        });

        if (immediate) {
            // no animation, resolve straight
            self.endOfFadeDeferred.resolve();
        } else {
            // make sure we start form the beginning
            playerStyle.opacity = bounds[direction].start;
            self.delegate.setVolume(bounds[direction].start);

            // use css transitions to animate opacity
            playerStyle['-webkit-transition'] = 'opacity ' + duration + 'ms';
            playerStyle.opacity = bounds[direction].end;

            // use classic js interval for sound fade
            var fadeStartTime = Date.now();
            var fadeInterval = setInterval(function () {
                var ratio = Math.min((Date.now() - fadeStartTime) / duration, 1);
                if (ratio === 1) {
                    self.endOfFadeDeferred.resolve();
                }
                self.delegate.setVolume(100 * (direction === 'in' ? ratio : 1 - ratio));
            }, 100);

            self.endOfFadeDeferred.always(function () {
                clearInterval(fadeInterval);
            });
        }

        return self.endOfFadeDeferred.promise();
    };

/////////////////////////////// VideoHandle

    /**
     * @param {mt.player.PlayersPool} playersPool
     * @param {string} uid a generated id that is unique to this handle
     * @param {{id: string, provider: string, coarseDuration: number}} video
     * @param {Array.<{time: number, callback: function}>} cues the cue points
     * @constructor
     */
    mt.player.VideoHandle = function (playersPool, uid, video, cues) {
        this.playersPool = playersPool;
        this.uid = uid;
        this.video = video;
        this.cues = cues;
        this.player = undefined;
        this.canPlayThroughDeferred = jQuery.Deferred();
        this.outDeferred = jQuery.Deferred();
        this.disposed = false;
    };

    /**
     * @return {jQuery.promise} when the video can play through
     */
    mt.player.VideoHandle.prototype.load = function () {
        var self = this;

        self.checkUsable();
        self.playersPool.ensurePlayerAvailableForProvider(this.video.provider).done(function (player) {
            self.player = player;
            var lastCurrentTime = 0;
            // register the listener for cues
            self.player.addTimeUpdateListener(self.uid + '_cue', function (evt) {
                // go through each cue and execute it if it is the goode time slot
                self.cues.forEach(function (cue) {
                    // execute the cue if last time is before the cue time and current time is after
                    if (lastCurrentTime <= cue.time && cue.time <= evt.currentTime) {
                        console.log('%s executed', self.uid + '_cue');
                        cue.callback();
                    }
                    lastCurrentTime = evt.currentTime;
                })
            });
            self.player.loadVideo(self.video.id).done(self.canPlayThroughDeferred.resolve);
        });
        return self.canPlayThroughDeferred.promise();
    };

    /**
     * Properly release the handle by removing all the listeners and stopping the video.
     *
     * After a call to that method, it is not possible to reuse the handle.
     */
    mt.player.VideoHandle.prototype.dispose = function () {
        this.disposed = true;
        this.player.removeTimeUpdateListener(this.uid + '_cue');
        this.canPlayThroughDeferred.reject();
        this.player.stopVideo();
    };

    /**
     * Starts and fade in the video.
     *
     * @param {number} duration fade duration in milliseconds
     */
    mt.player.VideoHandle.prototype.in = function (duration) {
        if (!this.player) throw new Error('The video should be loaded before calling in');
        this.checkUsable();

        this.player.playVideo();
        this.player.fade('in', duration);
    };

    /**
     * Fades out and stops the video.
     *
     * @param {number} fadeDuration fade duration in milliseconds
     * @return {jQuery.promise} resolved when the fade operation is finished and the player stopped. The argument it this handle.
     */
    mt.player.VideoHandle.prototype.out = function (fadeDuration) {
        if (!this.player) throw new Error('The video should be loaded before calling out');
        this.checkUsable();

        var self = this;
        self.player.fade('out', fadeDuration).done(function () {
            self.outDeferred.resolve(self);
        });
        return self.outDeferred.promise();
    };

    /**
     * Throws an error if handle is disposed.
     *
     * @throws {Error}
     * @private
     */
    mt.player.VideoHandle.prototype.checkUsable = function () {
        if (this.disposed) {
            throw new Error('Can not use a the disposed handle ' + this.uid);
        }
    };

/////////////////////////////// PlayerPool

    /**
     * @param {function(): HTMLElement} domNodeSupplier a function that supply the dom to attach the player
     * @constructor
     */
    mt.player.PlayersPool = function (domNodeSupplier) {
        this.domNodeSupplierFn = domNodeSupplier;
        this.playersByProvider = {youtube: []};
        this.handlesCounter = 0;
    };

    /**
     * Prepares a video and gives back a handle to interact with it.
     *
     * @param {{id: string, provider: string, coarseDuration: number}} video the video the load
     * @param {Array.<{time: number, callback: function}>} cues the cues points
     * @return {mt.player.VideoHandle}
     */
    mt.player.PlayersPool.prototype.prepareVideo = function (video, cues) {
        return new mt.player.VideoHandle(this, mt.tools.uniqueId(), video, cues);
    };

    /**
     * Ensures that there is enough players available for the supplied provider.
     *
     * If all the players for that provider are playing, creates a new one.
     *
     * @param {string} provider the video provider name
     * @return {jQuery.promise} resolved when the player is ready to accept load requests
     */
    mt.player.PlayersPool.prototype.ensurePlayerAvailableForProvider = function (provider) {
        var self = this;
        if (!(provider in self.playersByProvider)) {
            throw new Error("Unknown provider " + provider);
        }

        var playerDeferred = jQuery.Deferred();
        var found = false;

        var players = self.playersByProvider[provider];
        for (var idx = 0; idx < players.length; idx++) {
            var player = players[idx];
            if (!player.busy) {
                found = true;
                playerDeferred.resolve(player);
            }
        }

        if (!found) {
            // we need to create a new instance, when done save it
            playerDeferred.done(function (player) {
                players.push(player);
            });

            // get the dom node where we are going to insert the player
            var domNode = self.domNodeSupplierFn();

            // avoid black flash by hiding the container until the player is ready
            domNode.style.display = 'none';

            if (provider === 'youtube') {
                new YT.Player(domNode, {
                    height: '390',
                    width: '640',
                    playerVars: {
                        controls: 0,
                        showinfo: 0,
                        iv_load_policy: 3,
                        disablekb: 1,
                        modestbranding: 1,
                        rel: 0
                    },
                    events: {
                        onReady: function (evt) {
                            // now that the player is ready we can make it visible
                            evt.target.getIframe().style.display = '';
                            playerDeferred.resolve(new mt.player.YoutubePlayer(evt.target))
                        }
                    }
                });
            }
        }

        return playerDeferred.promise();
    };

})(window.mt = window.mt || {});<commit_msg>switched to default quality video for youtube<commit_after>(function (mt) {

    mt.player = {};

    /**
     * @param {YT.Player} delegate
     * @constructor
     */
    mt.player.YoutubePlayer = function (delegate) {
        var self = this;

        self.fadeDuration = 5000;

        self.delegate = delegate;
        self.busy = false;
        self.lastSampledTime = 0;
        self.canPlayThroughDeferred = undefined;
        self.endOfFadeDeferred = undefined;
        self.listeners = {timeupdate: {}};

        self.delegate.addEventListener('onStateChange', function (evt) {
            console.debug('onStateChange executed', evt.data);

            if (evt.data === YT.PlayerState.PLAYING) {
                // end of first buffering phase is considered as a can play through event
                self.canPlayThroughDeferred.resolve();
            }
        });
    };

    /**
     * Clears the previous playback state and initialize required objects for the next one.
     */
    mt.player.YoutubePlayer.prototype.reset = function () {
        var self = this;

        self.lastSampledTime = 0;

        // clear previous state
        if (self.canPlayThroughDeferred) {
            self.canPlayThroughDeferred.reject();
        }

        if (self.endOfFadeDeferred) {
            self.endOfFadeDeferred.resolve();
        }

        // install new state
        self.canPlayThroughDeferred = jQuery.Deferred();
        self.canPlayThroughDeferred.done(function () {
            self.delegate.pauseVideo();
        });

        // make the player silent and invisible
        self.fade('out', 0);
    };

    /**
     * @param {string} key the listener unique key, can be used to remove it later
     * @param {function} listener the listener function
     */
    mt.player.YoutubePlayer.prototype.addTimeUpdateListener = function (key, listener) {
        this.listeners.timeupdate[key] = this.listeners.timeupdate[key] || [];
        this.listeners.timeupdate[key].push(listener);
    };

    /**
     * @param {string} key
     */
    mt.player.YoutubePlayer.prototype.removeTimeUpdateListener = function (key) {
        if (key in this.listeners.timeupdate) {
            this.listeners.timeupdate[key] = [];
        }
    };

    /**
     * Clears the previous playback (stop a execute all promises) and start to load the given video.
     *
     * @param {string} videoId
     * @return {jQuery.promise} resolved when the video can play through the end without stop
     */
    mt.player.YoutubePlayer.prototype.loadVideo = function (videoId) {
        var self = this;

        self.reset();

        self.busy = true;

        // load the video, and when the video will start to play, we will pause it, see canPlayThroughDeferred
        self.delegate.loadVideoById({videoId: videoId, suggestedQuality: 'default'});

        // poll the current video position to generate the timeupdate event
        self.sampleTimeInterval = setInterval(function () {
            var sampledTime = self.delegate.getCurrentTime() * 1000;
            if (self.lastSampledTime !== sampledTime) {
                var event = {currentTime: sampledTime};

                for (var key in self.listeners.timeupdate)
                    for (var idxCallback = 0; idxCallback < self.listeners.timeupdate[key].length; idxCallback++) {
                        var callback = self.listeners.timeupdate[key][idxCallback];
                        callback(event);
                    }
            }
            self.lastSampledTime = sampledTime;
        }, 100);

        return self.canPlayThroughDeferred.promise();
    };

    /**
     * Starts the previously loaded video.
     */
    mt.player.YoutubePlayer.prototype.playVideo = function () {
        this.delegate.playVideo();
    };

    /**
     * Stops the video and release the player for further usage.
     */
    mt.player.YoutubePlayer.prototype.stopVideo = function () {
        clearInterval(this.sampleTimeInterval);
        this.delegate.stopVideo();
        this.busy = false;
    };

    /**
     * Fades the player without modifying the playback status (no play or stop call).
     *
     * If there was a pending fade operation, it is terminated so that it jumps to the end values. If duration is equal
     * to 0, it means immediate transition.
     *
     * @param {string} direction "in" or "out"
     * @param {number} duration the duration in milliseconds
     * @return {jQuery.promise} resolved when the fade operation is finished
     */
    mt.player.YoutubePlayer.prototype.fade = function (direction, duration) {
        var bounds = {'in': {start: 0, end: 100}, out: {start: 100, end: 0}};
        var self = this;
        var immediate = duration === 0;

        if (self.endOfFadeDeferred) {
            // there is a pending fade operation, ensure it is resolved
            self.endOfFadeDeferred.resolve();
        }

        self.endOfFadeDeferred = jQuery.Deferred();

        var playerStyle = self.delegate.getIframe().style;

        // remove transition and set extreme values when it is resolved
        self.endOfFadeDeferred.always(function () {
            playerStyle['-webkit-transition'] = '';
            playerStyle.opacity = bounds[direction].end;
            self.delegate.setVolume(bounds[direction].end);
        });

        if (immediate) {
            // no animation, resolve straight
            self.endOfFadeDeferred.resolve();
        } else {
            // make sure we start form the beginning
            playerStyle.opacity = bounds[direction].start;
            self.delegate.setVolume(bounds[direction].start);

            // use css transitions to animate opacity
            playerStyle['-webkit-transition'] = 'opacity ' + duration + 'ms';
            playerStyle.opacity = bounds[direction].end;

            // use classic js interval for sound fade
            var fadeStartTime = Date.now();
            var fadeInterval = setInterval(function () {
                var ratio = Math.min((Date.now() - fadeStartTime) / duration, 1);
                if (ratio === 1) {
                    self.endOfFadeDeferred.resolve();
                }
                self.delegate.setVolume(100 * (direction === 'in' ? ratio : 1 - ratio));
            }, 100);

            self.endOfFadeDeferred.always(function () {
                clearInterval(fadeInterval);
            });
        }

        return self.endOfFadeDeferred.promise();
    };

/////////////////////////////// VideoHandle

    /**
     * @param {mt.player.PlayersPool} playersPool
     * @param {string} uid a generated id that is unique to this handle
     * @param {{id: string, provider: string, coarseDuration: number}} video
     * @param {Array.<{time: number, callback: function}>} cues the cue points
     * @constructor
     */
    mt.player.VideoHandle = function (playersPool, uid, video, cues) {
        this.playersPool = playersPool;
        this.uid = uid;
        this.video = video;
        this.cues = cues;
        this.player = undefined;
        this.canPlayThroughDeferred = jQuery.Deferred();
        this.outDeferred = jQuery.Deferred();
        this.disposed = false;
    };

    /**
     * @return {jQuery.promise} when the video can play through
     */
    mt.player.VideoHandle.prototype.load = function () {
        var self = this;

        self.checkNotDisposed();
        self.playersPool.ensurePlayerAvailableForProvider(this.video.provider).done(function (player) {
            self.player = player;
            var lastCurrentTime = 0;
            // register the listener for cues
            self.player.addTimeUpdateListener(self.uid + '_cue', function (evt) {
                // go through each cue and execute it if it is the goode time slot
                self.cues.forEach(function (cue) {
                    // execute the cue if last time is before the cue time and current time is after
                    if (lastCurrentTime <= cue.time && cue.time <= evt.currentTime) {
                        console.log('%s executed', self.uid + '_cue');
                        cue.callback();
                    }
                    lastCurrentTime = evt.currentTime;
                })
            });
            self.player.loadVideo(self.video.id).done(self.canPlayThroughDeferred.resolve);
        });
        return self.canPlayThroughDeferred.promise();
    };

    /**
     * Properly release the handle by removing all the listeners and stopping the video.
     *
     * After a call to that method, it is not possible to reuse the handle.
     */
    mt.player.VideoHandle.prototype.dispose = function () {
        this.disposed = true;
        this.player.removeTimeUpdateListener(this.uid + '_cue');
        this.canPlayThroughDeferred.reject();
        this.player.stopVideo();
    };

    /**
     * Starts and fade in the video.
     *
     * @param {number} duration fade duration in milliseconds
     */
    mt.player.VideoHandle.prototype.in = function (duration) {
        this.checkNotDisposed();
        if (!this.player) throw new Error('The video should be loaded before calling in');

        this.player.playVideo();
        this.player.fade('in', duration);
    };

    /**
     * Fades out and stops the video.
     *
     * @param {number} fadeDuration fade duration in milliseconds
     * @return {jQuery.promise} resolved when the fade operation is finished and the player stopped. The argument it this handle.
     */
    mt.player.VideoHandle.prototype.out = function (fadeDuration) {
        this.checkNotDisposed();
        if (!this.player) throw new Error('The video should be loaded before calling out');

        var self = this;
        self.player.fade('out', fadeDuration).done(function () {
            self.outDeferred.resolve(self);
        });
        return self.outDeferred.promise();
    };

    /**
     * Throws an error if handle is disposed.
     *
     * @throws {Error}
     * @private
     */
    mt.player.VideoHandle.prototype.checkNotDisposed = function () {
        if (this.disposed) {
            throw new Error('Can not use a the disposed handle ' + this.uid);
        }
    };

/////////////////////////////// PlayerPool

    /**
     * @param {function(): HTMLElement} domNodeSupplier a function that supply the dom to attach the player
     * @constructor
     */
    mt.player.PlayersPool = function (domNodeSupplier) {
        this.domNodeSupplierFn = domNodeSupplier;
        this.playersByProvider = {youtube: []};
        this.handlesCounter = 0;
    };

    /**
     * Prepares a video and gives back a handle to interact with it.
     *
     * @param {{id: string, provider: string, coarseDuration: number}} video the video the load
     * @param {Array.<{time: number, callback: function}>} cues the cues points
     * @return {mt.player.VideoHandle}
     */
    mt.player.PlayersPool.prototype.prepareVideo = function (video, cues) {
        return new mt.player.VideoHandle(this, mt.tools.uniqueId(), video, cues);
    };

    /**
     * Ensures that there is enough players available for the supplied provider.
     *
     * If all the players for that provider are playing, creates a new one.
     *
     * @param {string} provider the video provider name
     * @return {jQuery.promise} resolved when the player is ready to accept load requests
     */
    mt.player.PlayersPool.prototype.ensurePlayerAvailableForProvider = function (provider) {
        var self = this;
        if (!(provider in self.playersByProvider)) {
            throw new Error("Unknown provider " + provider);
        }

        var playerDeferred = jQuery.Deferred();
        var found = false;

        var players = self.playersByProvider[provider];
        for (var idx = 0; idx < players.length; idx++) {
            var player = players[idx];
            if (!player.busy) {
                found = true;
                playerDeferred.resolve(player);
            }
        }

        if (!found) {
            // we need to create a new instance, when done save it
            playerDeferred.done(function (player) {
                players.push(player);
            });

            // get the dom node where we are going to insert the player
            var domNode = self.domNodeSupplierFn();

            // avoid black flash by hiding the container until the player is ready
            domNode.style.display = 'none';

            if (provider === 'youtube') {
                new YT.Player(domNode, {
                    height: '390',
                    width: '640',
                    playerVars: {
                        controls: 0,
                        showinfo: 0,
                        iv_load_policy: 3,
                        disablekb: 1,
                        modestbranding: 1,
                        rel: 0
                    },
                    events: {
                        onReady: function (evt) {
                            // now that the player is ready we can make it visible
                            evt.target.getIframe().style.display = '';
                            playerDeferred.resolve(new mt.player.YoutubePlayer(evt.target))
                        }
                    }
                });
            }
        }

        return playerDeferred.promise();
    };

})(window.mt = window.mt || {});<|endoftext|>


<commit_before>'use strict'

var async = require('async')
/**
 * Executes the submitted and the solution, to compare the stdout.
 * The module to be require as the first param.
 */
var seneca = require('seneca')({
  default_plugins: {
    'mem-store': true
  }
})

seneca.use('entity')
seneca.use(process.argv[2])

async.waterfall([
  function (callback) {
    seneca.act({role: 'math', cmd: 'sum', left: '3', right: '5'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  },
  function (callback) {
    seneca.act({role: 'math', cmd: 'sum', left: '13', right: '55'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  },
  function (callback) {
    seneca.act({role: 'math', cmd: 'product', left: '13', right: '55'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  }
]
, function () {
  seneca.act({role: 'math', cmd: 'operation-history'}, function (err, result) {
    if (err) return console.error(err)
    result.answer.forEach(function (en) {
      console.log(en.cmd, en.left, en.right)
    })
  })
})
<commit_msg>fixed mem-store exercise<commit_after>'use strict'

var async = require('async')
/**
 * Executes the submitted and the solution, to compare the stdout.
 * The module to be require as the first param.
 */
var seneca = require('seneca')()

seneca.use('basic')
seneca.use('entity')
seneca.use(process.argv[2])

async.waterfall([
  function (callback) {
    seneca.act({role: 'math', cmd: 'sum', left: '3', right: '5'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  },
  function (callback) {
    seneca.act({role: 'math', cmd: 'sum', left: '13', right: '55'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  },
  function (callback) {
    seneca.act({role: 'math', cmd: 'product', left: '13', right: '55'}, function (err, result) {
      if (err) return console.error(err)
      callback()
    })
  }
]
, function () {
  seneca.act({role: 'math', cmd: 'operation-history'}, function (err, result) {
    if (err) return console.error(err)
    result.answer.forEach(function (en) {
      console.log(en.cmd, en.left, en.right)
    })
  })
})
<|endoftext|>