<commit_before>// adopted from: claim <https://github.com/kevva/claim/blob/master/index.js>
// Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (MIT)

// tta -- tiny test assertion

var assert = require('./assert')
var AssertionError = assert.AssertionError

function create (val, expected, operator, msg, fn) {
  return {
    actual: val,
    expected: expected,
    message: msg,
    operator: operator,
    stackStartFunction: fn
  }
}

function test (ok, opts) {
  if (!ok) throw new AssertionError(opts)
}

function pass (msg) {
  test(true, create(true, true, 'pass', msg, pass))
}

function fail (msg) {
  test(false, create(false, false, 'fail', msg, fail))
}

function ok (val, msg) {
  test(val, create(val, true, '==', msg, ok))
}

function notOk (val, msg) {
  test(!val, create(val, true, '==', msg, notOk))
}

function isTrue (val, msg) {
  test(val === true, create(val, true, '===', msg, isTrue))
}

function isFalse (val, msg) {
  test(val === false, create(val, false, '===', msg, isFalse))
}

function eq (val, expected, msg) {
  test(val == expected, create(val, expected, '==', msg, eq))
}

function ne (val, expected, msg) {
  test(val != expected, create(val, expected, '!=', msg, ne))
}

function is (val, expected, msg) {
  test(val === expected, create(val, expected, '===', msg, is))
}

function not (val, expected, msg) {
  test(val !== expected, create(val, expected, '!==', msg, not))
}

function same (val, expected, msg) {
  try {
    assert.deepEqual(val, expected, msg)
  } catch (err) {
    test(false, create(val, expected, '!==', msg, same))
  }
}

function notSame (val, expected, msg) {
  try {
    assert.notDeepEqual(val, expected, msg)
  } catch (err) {
    test(false, create(val, expected, '!==', msg, notSame))
  }
}

function throws (fn, err, msg) {
  try {
    assert.throws(fn, err, msg)
  } catch (err) {
    test(false, create(err.actual, err.expected, err.operator, err.message, throws))
  }
}

function doesNotThrow (fn, msg) {
  try {
    assert.doesNotThrow(fn, msg)
  } catch (err) {
    test(false, create(err.actual, err.expected, err.operator, err.message, doesNotThrow))
  }
}

function regexTest (regex, contents, msg) {
  test(regex.test(contents), create(regex, contents, '===', msg, regexTest))
}

function ifError (err, msg) {
  test(!err, create(err, 'Error', '!==', msg, ifError))
}

module.exports = {
  pass: pass,
  fail: fail,
  ok: ok,
  assert: ok,
  notOk: notOk,
  truthy: ok,
  falsy: notOk,
  true: isTrue,
  false: isFalse,
  eq: eq,
  ne: ne,
  is: is,
  equal: is,
  not: not,
  isnt: not,
  same: same,
  deepEqual: same,
  notSame: notSame,
  diff: notSame,
  throws: throws,
  doesNotThrow: doesNotThrow,
  regexTest: regexTest,
  ifError: ifError,
  ifErr: ifError
}
<commit_msg>update test/assertion/claim — use node assert<commit_after>// adopted from: claim <https://github.com/kevva/claim/blob/master/index.js>
// Copyright (c) Kevin Mårtensson <kevinmartensson@gmail.com> (MIT)

// tta -- tiny test assertion

var assert = require('assert')
var AssertionError = assert.AssertionError

function create (val, expected, operator, msg, fn) {
  return {
    actual: val,
    expected: expected,
    message: msg,
    operator: operator,
    stackStartFunction: fn
  }
}

function test (ok, opts) {
  if (!ok) throw new AssertionError(opts)
}

function pass (msg) {
  test(true, create(true, true, 'pass', msg, pass))
}

function fail (msg) {
  test(false, create(false, false, 'fail', msg, fail))
}

function ok (val, msg) {
  test(val, create(val, true, '==', msg, ok))
}

function notOk (val, msg) {
  test(!val, create(val, true, '==', msg, notOk))
}

function isTrue (val, msg) {
  test(val === true, create(val, true, '===', msg, isTrue))
}

function isFalse (val, msg) {
  test(val === false, create(val, false, '===', msg, isFalse))
}

function eq (val, expected, msg) {
  test(val == expected, create(val, expected, '==', msg, eq))
}

function ne (val, expected, msg) {
  test(val != expected, create(val, expected, '!=', msg, ne))
}

function is (val, expected, msg) {
  test(val === expected, create(val, expected, '===', msg, is))
}

function not (val, expected, msg) {
  test(val !== expected, create(val, expected, '!==', msg, not))
}

function same (val, expected, msg) {
  try {
    assert.deepEqual(val, expected, msg)
  } catch (err) {
    test(false, create(val, expected, '!==', msg, same))
  }
}

function notSame (val, expected, msg) {
  try {
    assert.notDeepEqual(val, expected, msg)
  } catch (err) {
    test(false, create(val, expected, '!==', msg, notSame))
  }
}

function throws (fn, err, msg) {
  try {
    assert.throws(fn, err, msg)
  } catch (err) {
    test(false, create(err.actual, err.expected, err.operator, err.message, throws))
  }
}

function doesNotThrow (fn, msg) {
  try {
    assert.doesNotThrow(fn, msg)
  } catch (err) {
    test(false, create(err.actual, err.expected, err.operator, err.message, doesNotThrow))
  }
}

function regexTest (regex, contents, msg) {
  test(regex.test(contents), create(regex, contents, '===', msg, regexTest))
}

function ifError (err, msg) {
  test(!err, create(err, 'Error', '!==', msg, ifError))
}

module.exports = {
  pass: pass,
  fail: fail,
  ok: ok,
  assert: ok,
  notOk: notOk,
  truthy: ok,
  falsy: notOk,
  true: isTrue,
  false: isFalse,
  eq: eq,
  ne: ne,
  is: is,
  equal: is,
  not: not,
  isnt: not,
  same: same,
  deepEqual: same,
  notSame: notSame,
  diff: notSame,
  throws: throws,
  doesNotThrow: doesNotThrow,
  regexTest: regexTest,
  ifError: ifError,
  ifErr: ifError
}
<|endoftext|>


<commit_before>/*
 * This file is part of NectarJS
 * Copyright (c) 2017 - 2020 Adrien THIERRY
 * http://nectarjs.com - https://seraum.com/
 *
 * sources : https://github.com/nectarjs/nectarjs
 *
 * NectarJS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NectarJS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NectarJS.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

function StringLiteral(_path)
{
	if(_path.node.extra.raw[0] && _path.node.extra.raw[0] == "'")
	{
		_path.node.extra.raw = '"' + _path.node.value.replace(/\\/g, '\\\\').replace(/"/g, '\\\"') + '"';
	}

	if(_path.parent.type == "MemberExpression" || _path.parent.type == "CallExpression")
	{
		//_path.replaceWithSourceString("__NJS_VAR(" + _path.node.extra.raw + ")");
		//_path.skip();
	}
}
module.exports = StringLiteral;<commit_msg>Refactoring<commit_after>/*
 * This file is part of NectarJS
 * Copyright (c) 2017 - 2020 Adrien THIERRY
 * http://nectarjs.com - https://seraum.com/
 *
 * sources : https://github.com/nectarjs/nectarjs
 *
 * NectarJS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * NectarJS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with NectarJS.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

function StringLiteral(_path)
{
	if(_path.node.extra.raw[0] && _path.node.extra.raw[0] == "'")
	{
		_path.node.extra.raw = '"' + _path.node.value.replace(/\\/g, '\\\\').replace(/"/g, '\\\"') + '"';
	}

	if(_path.parent.type == "MemberExpression" || _path.parent.type == "CallExpression")
	{
		//
	}
	else
	{
		_path.replaceWithSourceString("__NJS_VAR(" + _path.node.extra.raw + ")");
		_path.skip();
	}
}
module.exports = StringLiteral;<|endoftext|>


<commit_before>/* eslint global-require: 0, consistent-return: 0 */

const Filter = require('broccoli-filter');
const CLIEngine = require('eslint').CLIEngine;

/**
 * Calculates the severity of a eslint.linter.verify result
 * @param {Array} result Eslint verify result array
 * @returns {Number} If the returned number is greater than 0 the result contains errors.
 */
function getResultSeverity(result) {

  // count all errors
  return result.reduce(function reduceToCount(previous, message) {
    if (message.fatal) {
      return previous + 1;
    }

    if (message.severity === 2) {
      return previous + 1;
    }

    return previous;
  }, 0);
}

/**
 * Ignores messages that are about ignored files as they are intended
 * but we are processing a file at a time
 *
 * @param {Array} errors result errors
 * @returns {Array} filtered errors
 */
function filterIgnoredFileMessages(errors) {
  const ignoreRegex = /File ignored because of your \.eslintignore file/;

  return errors.filter(function filterErrors(error) {
    if (error.message.match(ignoreRegex)) {
      return false;
    }
    return true;
  });
}

/**
 * Filters all ignored file messages from result object
 * @param {Object} result result errors
 * @returns {Object} filtered results
 */
function filterAllIgnoredFileMessages(result) {
  const resultOutput = result;

  result.results.map(function filterIgnoredErrors(resultItem) {
    resultItem.messages = filterIgnoredFileMessages(resultItem.messages);
    return resultItem;
  });
  return resultOutput;
}

/**
 * Uses the content of each file in a given tree and runs eslint validation on it.
 * @param {Object} inputTree Tree from broccoli.makeTree
 * @param {{config: String, rulesdir: String, format: String}} options Filter options
 * @returns {EslintValidationFilter} Filter obconfig @constructor
 */
function EslintValidationFilter(inputTree, options) {
  if (!(this instanceof EslintValidationFilter)) {
    return new EslintValidationFilter(inputTree, options);
  }
  this.options = options || {};
  this.eslintOptions = options.options || {};
  // set inputTree
  this.inputTree = inputTree;

  // set formatter
  this.formatter = require(this.options.format || 'eslint/lib/formatters/stylish');

  this.cli = new CLIEngine(this.eslintOptions);

  this.testGenerator = options.testGenerator;
  if (this.testGenerator) {
    this.targetExtension = 'eslint-test.js';
  }
}

module.exports = EslintValidationFilter;
EslintValidationFilter.prototype = Object.create(Filter.prototype);
EslintValidationFilter.prototype.constructor = EslintValidationFilter;
EslintValidationFilter.prototype.extensions = ['js'];
EslintValidationFilter.prototype.targetExtension = 'js';

EslintValidationFilter.prototype.write = function write(readTree, destDir) {
  return readTree(this.inputTree).then(srcDir => {
    if (!this.eslintrc) {
      this.eslintrc = srcDir;
    }

    return Filter.prototype.write.call(this, readTree, destDir);
  });
};

EslintValidationFilter.prototype.processString = function processString(content, relativePath) {
  // verify file content
  const result = this.cli.executeOnFiles([this.eslintrc + '/' + relativePath]);
  const filteredResults = filterAllIgnoredFileMessages(result);

  // if verification has result
  if (filteredResults.results[0].messages.length) {

    // log formatter output
    console.log(this.formatter(filteredResults.results));

    if (getResultSeverity(filteredResults.results) > 0) {
      if ('throwOnError' in this.internalOptions && this.internalOptions.throwOnError === true) {
        // throw error if severe messages exist
        throw new Error('severe rule errors');
      }
    }
  }

  if (this.testGenerator) {
    return this.testGenerator(relativePath, filteredResults.results[0].messages || []);
  }

  // return unmodified string
  return content;
};
<commit_msg>Platform-independent path-handling; more robust null-checking.<commit_after>/* eslint global-require: 0, consistent-return: 0 */

const path = require('path');

const Filter = require('broccoli-filter');
const CLIEngine = require('eslint').CLIEngine;

/**
 * Calculates the severity of a eslint.linter.verify result
 * @param {Array} result Eslint verify result array
 * @returns {Number} If the returned number is greater than 0 the result contains errors.
 */
function getResultSeverity(result) {

  // count all errors
  return result.reduce(function reduceToCount(previous, message) {
    if (message.fatal) {
      return previous + 1;
    }

    if (message.severity === 2) {
      return previous + 1;
    }

    return previous;
  }, 0);
}

/**
 * Ignores messages that are about ignored files as they are intended
 * but we are processing a file at a time
 *
 * @param {Array} errors result errors
 * @returns {Array} filtered errors
 */
function filterIgnoredFileMessages(errors) {
  const ignoreRegex = /File ignored because of your \.eslintignore file/;

  return errors.filter(function filterErrors(error) {
    if (error.message.match(ignoreRegex)) {
      return false;
    }
    return true;
  });
}

/**
 * Filters all ignored file messages from result object
 * @param {Object} result result errors
 * @returns {Object} filtered results
 */
function filterAllIgnoredFileMessages(result) {
  const resultOutput = result;

  result.results.map(function filterIgnoredErrors(resultItem) {
    resultItem.messages = filterIgnoredFileMessages(resultItem.messages);
    return resultItem;
  });
  return resultOutput;
}

/**
 * Uses the content of each file in a given tree and runs eslint validation on it.
 * @param {Object} inputTree Tree from broccoli.makeTree
 * @param {{config: String, rulesdir: String, format: String}} options Filter options
 * @returns {EslintValidationFilter} Filter obconfig @constructor
 */
function EslintValidationFilter(inputTree, options) {
  if (!(this instanceof EslintValidationFilter)) {
    return new EslintValidationFilter(inputTree, options);
  }
  this.options = options || {};
  this.eslintOptions = options.options || {};
  // set inputTree
  this.inputTree = inputTree;

  // set formatter
  this.formatter = require(this.options.format || 'eslint/lib/formatters/stylish');

  this.cli = new CLIEngine(this.eslintOptions);

  this.testGenerator = options.testGenerator;
  if (this.testGenerator) {
    this.targetExtension = 'eslint-test.js';
  }
}

module.exports = EslintValidationFilter;
EslintValidationFilter.prototype = Object.create(Filter.prototype);
EslintValidationFilter.prototype.constructor = EslintValidationFilter;
EslintValidationFilter.prototype.extensions = ['js'];
EslintValidationFilter.prototype.targetExtension = 'js';

EslintValidationFilter.prototype.write = function write(readTree, destDir) {
  return readTree(this.inputTree).then(srcDir => {
    if (!this.eslintrc) {
      this.eslintrc = srcDir;
    }

    return Filter.prototype.write.call(this, readTree, destDir);
  });
};

EslintValidationFilter.prototype.processString = function processString(content, relativePath) {
  // verify file content
  const result = this.cli.executeOnFiles([path.join(this.eslintrc, relativePath)]);
  const filteredResults = filterAllIgnoredFileMessages(result);

  // if verification has result
  if (filteredResults.results.length &&
      filteredResults.results[0].messages.length) {

    // log formatter output
    console.log(this.formatter(filteredResults.results));

    if (getResultSeverity(filteredResults.results) > 0) {
      if ('throwOnError' in this.internalOptions && this.internalOptions.throwOnError === true) {
        // throw error if severe messages exist
        throw new Error('severe rule errors');
      }
    }
  }

  if (this.testGenerator) {
    let messages = [];

    if (filteredResults.results.length) {
      messages = filteredResults.results[0].messages || [];
    }

    return this.testGenerator(relativePath, messages);
  }

  // return unmodified string
  return content;
};
<|endoftext|>


<commit_before>/**
 * Imports
 */

var fs = require('fs')

/**
 * Vars
 */

function motor () {
  return {
    path: '/sys/class/tacho-motor/',
    available: getPaths('/sys/class/tacho-motor/'),
    prefix: 'out'
  }
}

function sensor () {
  return {
    path: '/sys/class/lego-sensor/',
    available: getPaths('/sys/class/lego-sensor/'),
    prefix: 'in'
  }
}

/**
 * Expose devices
 */

module.exports = devices

/**
 * Get a device
 * @param  {String} port
 * @return {String} path
 */

function devices (port) {
  var device = isNaN(port) ? motor() : sensor()
  if (device.prefix === motor().prefix) {
    port = port.toUpperCase()
  }
  if (device.available[device.prefix + port]) {
    return device.path + device.available[device.prefix + port]
  } else {
    throw new Error('no device in port ' + port)
  }
}

function getPaths (path) {
  return fs.readdirSync(path).reduce(function (obj, file) {
    var portName = fs.readFileSync(path + file + '/address', 'utf-8').trim()
    obj[portName] = file.split(':')[0].trim()
    return obj
  }, {})
}
<commit_msg>fix portName for nxt<commit_after>/**
 * Imports
 */

var fs = require('fs')

/**
 * Vars
 */

function motor () {
  return {
    path: '/sys/class/tacho-motor/',
    available: getPaths('/sys/class/tacho-motor/'),
    prefix: 'out'
  }
}

function sensor () {
  return {
    path: '/sys/class/lego-sensor/',
    available: getPaths('/sys/class/lego-sensor/'),
    prefix: 'in'
  }
}

/**
 * Expose devices
 */

module.exports = devices

/**
 * Get a device
 * @param  {String} port
 * @return {String} path
 */

function devices (port) {
  var device = isNaN(port) ? motor() : sensor()
  if (device.prefix === motor().prefix) {
    port = port.toUpperCase()
  }
  if (device.available[device.prefix + port]) {
    return device.path + device.available[device.prefix + port]
  } else {
    throw new Error('no device in port ' + port)
  }
}

function getPaths (path) {
  return fs.readdirSync(path).reduce(function (obj, file) {
    var portName = fs.readFileSync(path + file + '/address', 'utf-8').split(':')[0].trim()
    obj[portName] = file.trim()
    return obj
  }, {})
}
<|endoftext|>


<commit_before>describe('CardsList', () => {
  afterEach(() => sandbox.restore())

  let cardsList
  let cards
  let CardSpy

  beforeEach(() => {
    cards = [ a`.list-card`,
              a`.list-card`,
              a`.list-card.hide` ]

    bodyHas(a`.list-cards`.with(...cards))

    cardsList = document.querySelector('.list-cards')

    CardSpy = stub(global, 'Card')
  })

  describe('constructor', () => {
    it('builds cards', () => {
      new CardsList(cardsList)

      expect(CardSpy).to.have.been.calledThrice
      expect(CardSpy).to.have.been.calledWith(
        sinon.match.instanceOf(window.HTMLElement))
    })
  });

  context('card created', () => {
    it('creates new card', (done) => {
      new CardsList(cardsList)
      CardSpy.reset()

      let newCard = a`.list-card.is-due-completed.active-card`
      cardsList.appendChild(newCard)

      _.in(10, () => {
        expect(CardSpy).to.have.been.calledWith(newCard)
        done()
      })
    })
  })

  context('card dropped', () => {
    it('creates new card', (done) => {
      let cardPlaceholder = a`.list-card.placeholder`
      let blinkingCard    = a`.list-card.js-member-droppable`
      let cardDropped     = a`.list-card.js-member-droppable`

      new CardsList(cardsList)
      CardSpy.reset()

      cardsList.appendChild(cardPlaceholder)

      _.in(0, () => {
        cardsList.removeChild(cardPlaceholder)
        cardsList.appendChild(blinkingCard)
      })
      _.in(100, () => {
        cardsList.removeChild(blinkingCard)
        cardsList.appendChild(cardDropped)
      })
      _.in(110, () => {
        expect(CardSpy).to.have.been.calledWith(cardDropped)
        done()
      })
    })
  })
})
<commit_msg>improved cards_list specs<commit_after>describe('CardsList', () => {
  afterEach(() => sandbox.restore())

  let cardsList
  let cards
  let CardSpy

  beforeEach(() => {
    cards = [ a`.list-card`,
              a`.list-card`,
              a`.list-card.hide` ]

    bodyHas(a`.list-cards`.with(...cards))

    cardsList = document.querySelector('.list-cards')

    CardSpy = stub(global, 'Card')
  })

  describe('constructor', () => {
    it('builds cards', () => {
      new CardsList(cardsList)

      expect(CardSpy.firstCall ).to.have.been.calledWith(cards[0])
      expect(CardSpy.secondCall).to.have.been.calledWith(cards[1])
      expect(CardSpy.thirdCall ).to.have.been.calledWith(cards[2])
    })
  });

  context('card created', () => {
    it('creates new card', (done) => {
      new CardsList(cardsList)
      CardSpy.reset()

      let newCard = a`.list-card.is-due-completed.active-card`
      cardsList.appendChild(newCard)

      _.in(10, () => {
        expect(CardSpy).to.have.been.calledWith(newCard)
        done()
      })
    })
  })

  context('card dropped', () => {
    it('creates new card', (done) => {
      let cardPlaceholder = a`.list-card.placeholder`
      let blinkingCard    = a`.list-card.js-member-droppable`
      let cardDropped     = a`.list-card.js-member-droppable`

      new CardsList(cardsList)
      CardSpy.reset()

      cardsList.appendChild(cardPlaceholder)

      _.in(0, () => {
        cardsList.removeChild(cardPlaceholder)
        cardsList.appendChild(blinkingCard)
      })
      _.in(100, () => {
        cardsList.removeChild(blinkingCard)
        cardsList.appendChild(cardDropped)
      })
      _.in(110, () => {
        expect(CardSpy).to.have.been.calledWith(cardDropped)
        done()
      })
    })
  })
})
<|endoftext|>


<commit_before>import Ember from 'ember';
import Message from 'hyperchannel/models/message';

export default Ember.Controller.extend({

  newMessage: null,
  space: Ember.inject.controller(),
  coms: Ember.inject.service(),

  actions: {
    sendMessage: function(newMessage) {
      let message = Message.create({
        type: 'message-chat',
        date: new Date(),
        nickname: this.get('space.model.server.nickname'),
        content: newMessage
      });

      this.get('coms').transferMessage(
        this.get('space.model'),
        this.get('model.sockethubChannelId'),
        message.get('content')
      );

      this.get('model.messages').pushObject(message);
      this.set('newMessage', null);
    },

    executeCommand: function(newMessage) {
      const availableCommands = [
        "help",
        "join",
        "leave",
        "me",
        "msg",
        "part",
        "topic"
      ];
      let commandText = newMessage.substr(1);
      let commandSplitted = commandText.split(" ");
      let command = commandSplitted[0];

      if (availableCommands.includes(command.toLowerCase())) {
        this.send(command + 'Command', commandSplitted.slice(1));
      } else {
        Ember.Logger.warn('[channel]', 'Unknown command', commandText);
      }

      this.set('newMessage', null);
    },

    joinCommand: function(args) {
      let space = this.get('space.model');
      let channel = this.get('coms').createChannel(space, args[0]);
      this.get('storage').saveSpace(space);
      this.transitionToRoute('space.channel', space, channel);
    },

    partCommand: function() {
      let space = this.get('space.model');
      let channelName = this.get('model.name');
      this.get('coms').removeChannel(space, channelName);
      let lastChannel = space.get('channels.lastObject');
      this.transitionToRoute('space.channel', space, lastChannel);
    },

    leaveCommand: function() {
      this.send('partCommand');
    },

    helpCommand: function() {
    },

    meCommand: function(args) {
      let newMessage = args.join(' ');

      let message = Message.create({
        type: 'message-chat-me',
        date: new Date(),
        nickname: this.get('space.model.server.nickname'),
        content: newMessage
      });

      this.get('coms').transferMeMessage(
        this.get('space.model'),
        this.get('model.sockethubChannelId'),
        message.get('content')
      );

      this.get('model.messages').pushObject(message);
    },

    msgCommand: function(args) {
      let username = args.shift();
      this.get('coms').createUserChannel(this.get('space.model'), username);
      // TODO fix this, sockethub sends a failure event with error
      // "TypeError: Cannot read property 'indexOf' of undefined"
      // this.get('coms').transferMessage(this.get('space.model'), username, args.join(' '));
    },

    topicCommand: function(args) {
      let channel = this.get('model');
      let topic = args.join(' ');

      this.get('coms').changeTopic(this.get('space.model'), channel, topic);
    }
  }

});
<commit_msg>Re-add missing storage service to base_channel<commit_after>import Ember from 'ember';
import Message from 'hyperchannel/models/message';

export default Ember.Controller.extend({

  newMessage: null,
  space: Ember.inject.controller(),
  coms: Ember.inject.service(),
  storage: Ember.inject.service('remotestorage'),

  actions: {
    sendMessage: function(newMessage) {
      let message = Message.create({
        type: 'message-chat',
        date: new Date(),
        nickname: this.get('space.model.server.nickname'),
        content: newMessage
      });

      this.get('coms').transferMessage(
        this.get('space.model'),
        this.get('model.sockethubChannelId'),
        message.get('content')
      );

      this.get('model.messages').pushObject(message);
      this.set('newMessage', null);
    },

    executeCommand: function(newMessage) {
      const availableCommands = [
        "help",
        "join",
        "leave",
        "me",
        "msg",
        "part",
        "topic"
      ];
      let commandText = newMessage.substr(1);
      let commandSplitted = commandText.split(" ");
      let command = commandSplitted[0];

      if (availableCommands.includes(command.toLowerCase())) {
        this.send(command + 'Command', commandSplitted.slice(1));
      } else {
        Ember.Logger.warn('[channel]', 'Unknown command', commandText);
      }

      this.set('newMessage', null);
    },

    joinCommand: function(args) {
      let space = this.get('space.model');
      let channel = this.get('coms').createChannel(space, args[0]);
      this.get('storage').saveSpace(space);
      this.transitionToRoute('space.channel', space, channel);
    },

    partCommand: function() {
      let space = this.get('space.model');
      let channelName = this.get('model.name');
      this.get('coms').removeChannel(space, channelName);
      let lastChannel = space.get('channels.lastObject');
      this.transitionToRoute('space.channel', space, lastChannel);
    },

    leaveCommand: function() {
      this.send('partCommand');
    },

    helpCommand: function() {
    },

    meCommand: function(args) {
      let newMessage = args.join(' ');

      let message = Message.create({
        type: 'message-chat-me',
        date: new Date(),
        nickname: this.get('space.model.server.nickname'),
        content: newMessage
      });

      this.get('coms').transferMeMessage(
        this.get('space.model'),
        this.get('model.sockethubChannelId'),
        message.get('content')
      );

      this.get('model.messages').pushObject(message);
    },

    msgCommand: function(args) {
      let username = args.shift();
      this.get('coms').createUserChannel(this.get('space.model'), username);
      // TODO fix this, sockethub sends a failure event with error
      // "TypeError: Cannot read property 'indexOf' of undefined"
      // this.get('coms').transferMessage(this.get('space.model'), username, args.join(' '));
    },

    topicCommand: function(args) {
      let channel = this.get('model');
      let topic = args.join(' ');

      this.get('coms').changeTopic(this.get('space.model'), channel, topic);
    }
  }

});
<|endoftext|>


<commit_before>import React from 'react';
import moment from 'moment';
import {Link} from 'react-router';
import {LoadingPanel} from './loading_panel';

import interop from '../interop';

export class ReviewList extends React.Component {

	static propTypes = {
	};

	state = {
		loading: true,
		data: null,
		error: null,
	};

	async componentDidMount() {
		let state = {
			loading: false,
			data: null,
			error: null,
		};

		try {
			state.data = await $.ajax({
				method: 'get',
				url: '/api/encounters',
				headers: {Authorization: interop.auth.authHeader()},
			});
		} catch (err) {
			state.error = err;
		} finally {
			console.log(state);
			this.setState(state);
		}
	}

	msToString(ms) {
		if (typeof ms !== 'number') {
			return '';
		}
		let secs = Math.floor((ms / 1000) % 60);
		let mins = Math.floor(ms / 1000 / 60);
		return `${mins < 10 ? '0' : ''}${mins}:${secs < 10 ? '0' : ''}${secs}`;
	}

	errorToText(error) {
		if (!error.status) {
			return 'No network';
		} else {
			let text = error.statusText;
			try {
				text = JSON.parse(error.responseText).error;
			} catch (errIgnored) {
				// ignored
			}
			return `${error.status}: ${text}`;
		}
	}

	render() {
		return (

Recent Lessons

				<LoadingPanel loading={this.state.loading}>
					{this.state.error ? (

{this.errorToText(this.state.error)}

					) : (
						this.state.data && this.state.data.length ? (

										Date
										Partner
										Length

									{this.state.data.map(encounter => {
										return (

												<Link to={'/reviews/' + encounter.id}>{moment(encounter.date).format('lll')}</Link>
												{encounter.partnerName || '[kein Name]'}
												{this.msToString(encounter.length)}
												{this.myReview ? 'reviewed' : 'needs review'}

										);
									})}

						) : (

Haven't yet had any lessons. <Link to="/video">Start one now.</Link>

						)
					)}
				</LoadingPanel>

		);
	}
}
<commit_msg>Fixed review information on review list<commit_after>import React from 'react';
import moment from 'moment';
import {Link} from 'react-router';
import {LoadingPanel} from './loading_panel';

import interop from '../interop';

export class ReviewList extends React.Component {

	static propTypes = {
	};

	state = {
		loading: true,
		data: null,
		error: null,
	};

	async componentDidMount() {
		let state = {
			loading: false,
			data: null,
			error: null,
		};

		try {
			state.data = await $.ajax({
				method: 'get',
				url: '/api/encounters',
				headers: {Authorization: interop.auth.authHeader()},
			});
		} catch (err) {
			state.error = err;
		} finally {
			console.log(state);
			this.setState(state);
		}
	}

	msToString(ms) {
		if (typeof ms !== 'number') {
			return '';
		}
		let secs = Math.floor((ms / 1000) % 60);
		let mins = Math.floor(ms / 1000 / 60);
		return `${mins < 10 ? '0' : ''}${mins}:${secs < 10 ? '0' : ''}${secs}`;
	}

	errorToText(error) {
		if (!error.status) {
			return 'No network';
		} else {
			let text = error.statusText;
			try {
				text = JSON.parse(error.responseText).error;
			} catch (errIgnored) {
				// ignored
			}
			return `${error.status}: ${text}`;
		}
	}

	render() {
		return (

Recent Lessons

				<LoadingPanel loading={this.state.loading}>
					{this.state.error ? (

{this.errorToText(this.state.error)}

					) : (
						this.state.data && this.state.data.length ? (

										Date
										Partner
										Length

									{this.state.data.map(encounter => {
										return (

												<Link to={'/reviews/' + encounter.id}>{moment(encounter.date).format('lll')}</Link>
												{encounter.partnerName || '[kein Name]'}
												{this.msToString(encounter.length)}
												{encounter.myReview ? 'reviewed' : 'needs review'}

										);
									})}

						) : (

Haven't yet had any lessons. <Link to="/video">Start one now.</Link>

						)
					)}
				</LoadingPanel>

		);
	}
}
<|endoftext|>


<commit_before>'use strict'

const debug = require('debug')('redis-cache-decorator')
const stringify = require('json-stringify-safe')
const toArray = require('stream-to-array')
const Promise = require('bluebird')
const destroy = require('destroy')
const Stream = require('stream')
const crypto = require('crypto')
const assert = require('assert')

const ENCODINGS = require('./encodings')
const utils = require('./utils')

// create a base
module.exports = constructorOptions => {
  assert(constructorOptions, 'Constructor options are required!')
  const client = constructorOptions.client
  const subscriber = constructorOptions.subscriber
  assert(client, 'A redis client as `.client` is required!')
  assert(subscriber, 'A redis subscription client as `.subscriber` is required!')

  // easy way to disabled
  const disabled = constructorOptions.disabled || constructorOptions.disable || false
  // prefix
  const constructorNamespace = constructorOptions.namespace || ''
  const defaultEncoding = constructorOptions.encoding || 'json'
  assert(ENCODINGS.has(defaultEncoding), `Encoding is not supported: ${defaultEncoding}`)
  // 30 seconds
  const defaultTTL = utils.isNumberOrString(constructorOptions.ttl)
    ? utils.ms(constructorOptions.ttl)
    : utils.ms('30s')
  // prefix
  const defaultTimeout = utils.isNumberOrString(constructorOptions.timeout)
    ? utils.ms(constructorOptions.timeout)
    : utils.ms('30s')
  // onError
  const defaultOnError = constructorOptions.onError || utils._onError
  // default poll factor based on the timeout
  const defaultPollFactor = constructorOptions.pollFactor || (1 / 10)
  // default minimum poll interval in ms
  const defaultMinimumTimeoutPollInterval = utils.ms(constructorOptions.minimumPollInterval || 100)
  // function to create a time out error
  const defaultCreateTimeoutError = constructorOptions.createTimeoutError || utils._createTimeoutError

  // add decorator options
  return decoratorOptions => {
    if (typeof decoratorOptions !== 'object') throw new TypeError('Decorator options are required!')
    if (typeof decoratorOptions.namespace !== 'string') throw new TypeError('A .namespace is required for each decorator.')
    const namespace = [constructorNamespace, decoratorOptions.namespace].join(':')
    const encoding = decoratorOptions.encoding || defaultEncoding
    const encoder = ENCODINGS.get(encoding)
    assert(encoder, `Encoding is not supported: ${encoding}`)
    const ttl = utils.ms(utils.isNumberOrString(decoratorOptions.ttl)
      ? decoratorOptions.ttl
      : defaultTTL)
    const timeout = utils.ms(utils.isNumberOrString(decoratorOptions.timeout)
      ? decoratorOptions.timeout
      : defaultTimeout)
    assert(timeout > 0, 'The timeout must be > 0')
    const pollFactor = decoratorOptions.pollFactor || defaultPollFactor
    const minimumPollInterval = utils.ms(utils.isNumberOrString(decoratorOptions.minimumPollInterval)
      ? decoratorOptions.minimumPollInterval
      : defaultMinimumTimeoutPollInterval)
    const pollInterval = utils.ms(decoratorOptions.pollInterval || Math.max(timeout * pollFactor, minimumPollInterval))
    const onError = decoratorOptions.onError || defaultOnError
    const createTimeoutError = decoratorOptions.createTimeoutError || defaultCreateTimeoutError

    debug('options: %o', {
      disabled,
      namespace,
      ttl,
      timeout,
      pollFactor,
      minimumPollInterval,
      pollInterval,
    })

    // input the underlying function
    return fn => {
      if (typeof fn !== 'function') throw new TypeError('Decorated input must be a function!')
      // return the decorated version of the function

      return Promise.coroutine(function * () {
        // get the arguments
        const args = []
        for (let i = 0; i < arguments.length; i++) args.push(arguments[i])

        // bypass the cache
        if (disabled) return yield utils.executeFunction(fn, args)

        // create a hash of the arguments
        const hash = createHash(args)

        // check whether it's running or anything
        let state = yield getCurrentState()

        // return the cached version
        if (state.value != null) return encoder.decode(state.value)

        // cleanup listeners when listing for events
        let cleanupListeners = utils.noop
        // whether cleanup has already happened
        let cleaned = false
        // whether execution has occured already
        let executed = false
        // whether the result is as a stream
        let stream = null
        // if it's currently running, wait for the value
        if (state.running) return yield waitForResult()

        // execute - might need something like this for the redlock algorithm?
        const EXEC_ID = Date.now() + Math.random().toString(36)
        // note in redis that it's running
        // don't wait for a response - might avoid some race conditions
        const isSet = yield client.setnx(`${hash}:running`, EXEC_ID)
        // someone else is setting it
        if (!isSet) {
          // start listening for the result
          const resultPromise = waitForResult()
          // check whether the result has been saved in the mean time
          state = yield getCurrentState()
          // the chance of this happening (setting a result when executing SETNX) is very low
          /* istanbul ignore if */
          if (state.value != null) {
            cleanupListeners()
            resultPromise.catch(onError)  // always handle the promise
            return encoder.decode(state.value)
          }
          // if it's not running, execute again
          // but why would this happen?
          /* istanbul ignore next */
          if (!state.running) {
            resultPromise.catch(onError) // always handle the promise
            return yield execute()
          }
          return yield resultPromise
        }

        return yield execute()

        // if the current query is a stream, try to destroy it if we're returning data
        // TODO: tests
        function destroyCurrentStream () {
          if (stream) destroy(stream)
        }

        // executes the result
        function execute () {
          debug('executing')

          {
            // cleanup listeners just in case
            cleanupListeners()
            // if we're executing after a failed set,
            // set it again just in case
            const batch = client.multi()
            batch.setnx(`${hash}:running`, EXEC_ID)
            // set a timeout
            client.pexpire(`${hash}:running`, timeout)
            batch.exec().catch(onError)
          }

          let timeout_id
          const timeout_promise = new Promise((resolve, reject) => {
            timeout_id = pollCurrentState(resolve, reject)
          })

          const execution_promise = utils.executeFunction(fn, args)
          .then(value => {
            // handle streams
            /* istanbul ignore else */
            if (value && typeof value.pipe === 'function' && value._readableState) {
              // expose the stream
              stream = value

              switch (encoding) {
                case 'json': {
                  assert(value._readableState.objectMode, 'I do not know how to handle streams that are not in `objectMode` when saving in with encoding = `json`. Please change your `encoding=` option to `string` or `buffer`')
                  // just convert it to an array
                  return toArray(value)
                }
                case 'string': {
                  value.setEncoding('utf8')
                  return toArray(value).then(arr => arr.join(''))
                }
                case 'buffer': {
                  return toArray(value).then(arr => Buffer.concat(arr))
                }
              }
            } else if (value instanceof Stream) {
              throw new Error('I do not know how to handle this type of stream. It does not have a `.pipe()` function or it does not have a `._readableState.`')
            }

            return value
          })
          .then(value => {
            cleanupTimeout()
            debug('returned value: %o', value)
            const encodedValue = encoder.encode(value) // story it as a string
            debug('encoded value: %o', encodedValue)
            const batch = client.multi()
              .del(`${hash}:running`, `${hash}:error`)
              // NOTE: don't know how buffers transmit over pubsub
              .publish(`${hash}:value`, encoding === 'buffer' ? '1' : encodedValue) // publish the result to all listeners
            // only cache if a TTL is set
            if (ttl) {
              if (encoding === 'buffer') {
                client.set(`${hash}:value`, encodedValue, 'PX', ttl).catch(onError)
              } else {
                batch.set(`${hash}:value`, encodedValue, 'PX', ttl)
              }
            }
            batch.exec().catch(onError)
            return value
          }).catch(_err => {
            cleanupTimeout()
            // handle errors
            const err = utils.stringifyError(_err)
            client.multi()
              .del(`${hash}:running`, `${hash}:value`)
              // publish the error to all listeners
              .publish(`${hash}:error`, err)
              .exec().catch(onError)
            throw _err
          })

          return Promise.race([
            timeout_promise,
            execution_promise,
          ])

          function cleanupTimeout () {
            debug('execution is done!')
            executed = true
            clearInterval(timeout_id)
          }
        }

        function getCurrentState () {
          const formatResults = results => {
            const state = {
              value: results[0],
              running: results[1],
            }
            debug('state: %o', state)
            return state
          }

          if (encoding === 'buffer') {
            // TODO: should really be using `.multi()` here, but `getBuffer()` is broken in it
            return Promise.all([
              client.getBuffer(`${hash}:value`),
              client.get(`${hash}:running`),
            ]).then(formatResults)
          }

          return client.mget([
            `${hash}:value`,
            `${hash}:running`,
          ]).then(formatResults)
        }

        function pollCurrentState (resolve, reject) {
          return setInterval(() => {
            debug('polling for state')
            getCurrentState().then(val => {
              debug('polled for state')
              debug('cleaned: %s', cleaned)
              debug('executed: %s', executed)

              state = val
              // we check here incase cleanup happens during `getCurrentState()` is resolving
              // though I guess it really doesn't matter because resolve/reject is smart
              /* istanbul ignore if */
              if (cleaned || executed) return

              // set somehow, i guess if two functions were running concurrently
              /* istanbul ignore if */
              if (state.value != null) {
                cleanupListeners()
                destroyCurrentStream()
                try {
                  resolve(encoder.decode(state.value))
                } catch (err) {
                  /* istanbul ignore next */
                  reject(err)
                }
                return
              }

              // no longer running
              if (!state.running) {
                cleanupListeners()
                destroyCurrentStream()
                reject(createTimeoutError())
                return
              }
            }).catch(onError)
          }, pollInterval)
        }

        // wait for the result from redis channels
        function waitForResult () {
          debug('waiting for result')
          // subscribe to the channels
          const pattern = `${hash}:*`
          // timeout for polling
          let timeout_id

          return new Promise((resolve, reject) => {
            // expose the cleanup function outside the scope
            cleanupListeners = cleanup

            subscriber.psubscribe(pattern).catch(reject)

            // add a message handler
            subscriber.setMaxListeners(subscriber.getMaxListeners() + 1)
            subscriber.on('pmessage', listener)

            // poll to check the state
            // NOTE: was thinking of using keyevents,
            // but this is better because you need to access the key
            // to trigger an eviction anyways
            timeout_id = pollCurrentState(resolve, reject)

            function listener (pattern, channel, message) {
              if (channel === `${hash}:value`) {
                cleanup()
                debug('message: %s', message)

                // i don't know how to transfer buffer's as a message
                if (encoding === 'buffer') {
                  return getCurrentState().then(_val => {
                    state = _val
                    return encoder.decode(state.value)
                  }).then(resolve, reject)
                }

                try {
                  resolve(encoder.decode(message))
                } catch (err) {
                  // when would this happen?
                  /* istanbul ignore next */
                  reject(err)
                }
              } else if (channel === `${hash}:error`) {
                cleanup()
                try {
                  reject(utils.parseError(message))
                } catch (err) {
                  // when would this happen?
                  /* istanbul ignore next */
                  reject(err)
                }
              }
            }

            function cleanup () {
              debug('cleaning up waiting for the result')
              cleaned = true
              clearInterval(timeout_id)
              subscriber.punsubscribe(pattern).catch(reject)
              subscriber.removeListener('message', listener)
              subscriber.setMaxListeners(subscriber.getMaxListeners() - 1)
            }
          })
        }
      })
    }

    function createHash (args) {
      debug(args)
      return [
        namespace,
        crypto.createHash('sha256')
          .update(stringify(args))
          .digest('hex'),
      ].join(':')
    }
  }
}
<commit_msg>refactor: code + comments<commit_after>'use strict'

const debug = require('debug')('redis-cache-decorator')
const stringify = require('json-stringify-safe')
const toArray = require('stream-to-array')
const Promise = require('bluebird')
const destroy = require('destroy')
const Stream = require('stream')
const crypto = require('crypto')
const assert = require('assert')

const ENCODINGS = require('./encodings')
const utils = require('./utils')

// create a base
module.exports = constructorOptions => {
  assert(constructorOptions, 'Constructor options are required!')
  const client = constructorOptions.client
  const subscriber = constructorOptions.subscriber
  assert(client, 'A redis client as `.client` is required!')
  assert(subscriber, 'A redis subscription client as `.subscriber` is required!')

  // easy way to disabled
  const disabled = constructorOptions.disabled || constructorOptions.disable || false
  // prefix
  const constructorNamespace = constructorOptions.namespace || ''
  const defaultEncoding = constructorOptions.encoding || 'json'
  assert(ENCODINGS.has(defaultEncoding), `Encoding is not supported: ${defaultEncoding}`)
  // 30 seconds
  const defaultTTL = utils.isNumberOrString(constructorOptions.ttl)
    ? utils.ms(constructorOptions.ttl)
    : utils.ms('30s')
  // prefix
  const defaultTimeout = utils.isNumberOrString(constructorOptions.timeout)
    ? utils.ms(constructorOptions.timeout)
    : utils.ms('30s')
  // onError
  const defaultOnError = constructorOptions.onError || utils._onError
  // default poll factor based on the timeout
  const defaultPollFactor = constructorOptions.pollFactor || (1 / 10)
  // default minimum poll interval in ms
  const defaultMinimumTimeoutPollInterval = utils.ms(constructorOptions.minimumPollInterval || 100)
  // function to create a time out error
  const defaultCreateTimeoutError = constructorOptions.createTimeoutError || utils._createTimeoutError

  // add decorator options
  return decoratorOptions => {
    if (typeof decoratorOptions !== 'object') throw new TypeError('Decorator options are required!')
    if (typeof decoratorOptions.namespace !== 'string') throw new TypeError('A .namespace is required for each decorator.')
    const namespace = [constructorNamespace, decoratorOptions.namespace].join(':')
    const encoding = decoratorOptions.encoding || defaultEncoding
    const encoder = ENCODINGS.get(encoding)
    assert(encoder, `Encoding is not supported: ${encoding}`)
    const ttl = utils.ms(utils.isNumberOrString(decoratorOptions.ttl)
      ? decoratorOptions.ttl
      : defaultTTL)
    const timeout = utils.ms(utils.isNumberOrString(decoratorOptions.timeout)
      ? decoratorOptions.timeout
      : defaultTimeout)
    assert(timeout > 0, 'The timeout must be > 0')
    const pollFactor = decoratorOptions.pollFactor || defaultPollFactor
    const minimumPollInterval = utils.ms(utils.isNumberOrString(decoratorOptions.minimumPollInterval)
      ? decoratorOptions.minimumPollInterval
      : defaultMinimumTimeoutPollInterval)
    const pollInterval = utils.ms(decoratorOptions.pollInterval || Math.max(timeout * pollFactor, minimumPollInterval))
    const onError = decoratorOptions.onError || defaultOnError
    const createTimeoutError = decoratorOptions.createTimeoutError || defaultCreateTimeoutError

    debug('options: %o', {
      disabled,
      namespace,
      ttl,
      timeout,
      pollFactor,
      minimumPollInterval,
      pollInterval,
    })

    // input the underlying function
    return fn => {
      if (typeof fn !== 'function') throw new TypeError('Decorated input must be a function!')
      // return the decorated version of the function

      return Promise.coroutine(function * () {
        // get the arguments
        const args = []
        for (let i = 0; i < arguments.length; i++) args.push(arguments[i])

        // bypass the cache
        if (disabled) return yield utils.executeFunction(fn, args)

        // create a hash of the arguments
        const hash = createHash(args)

        // check whether it's running or anything
        let state = yield getCurrentState()

        // return the cached version
        if (state.value != null) return encoder.decode(state.value)

        // cleanup listeners when listing for events
        let cleanupListeners = utils.noop
        // whether cleanup has already happened
        let cleaned = false
        // whether execution has occured already
        let executed = false
        // whether the result is as a stream
        let stream = null
        // if it's currently running, wait for the value
        if (state.running) return yield waitForResult()

        // execute - might need something like this for the redlock algorithm?
        const EXEC_ID = Date.now() + Math.random().toString(36)
        // note in redis that it's running
        // don't wait for a response - might avoid some race conditions
        const isSet = yield client.setnx(`${hash}:running`, EXEC_ID)
        if (isSet) return yield execute() // we set it, so we execute

        /* someone else is setting it... */

        // start listening for the result
        const resultPromise = waitForResult()
        // check whether the result has been saved in the mean time
        state = yield getCurrentState()

        // the chance of this happening (setting a result when executing SETNX) is very low
        /* istanbul ignore if */
        if (state.value != null) {
          cleanupListeners()
          resultPromise.catch(onError)  // always handle the promise
          return encoder.decode(state.value)
        }

        // if it's not running, execute again
        // but why would this happen?
        /* istanbul ignore next */
        if (!state.running) {
          resultPromise.catch(onError) // always handle the promise
          return yield execute()
        }

        return yield resultPromise

        // if the current query is a stream, try to destroy it if we're returning data
        // TODO: tests
        function destroyCurrentStream () {
          if (stream) destroy(stream)
        }

        // executes the result
        function execute () {
          debug('executing')

          {
            // cleanup listeners just in case
            cleanupListeners()
            // if we're executing after a failed set,
            // set it again just in case
            const batch = client.multi()
            batch.setnx(`${hash}:running`, EXEC_ID)
            // set a timeout
            client.pexpire(`${hash}:running`, timeout)
            batch.exec().catch(onError)
          }

          // promise that polls whether the function has timed out
          let timeout_id
          const timeout_promise = new Promise((resolve, reject) => {
            timeout_id = pollCurrentState(resolve, reject)
          })

          // promise that actuall executes the function
          // NOTE: execution still completes and saves even if timed out
          const execution_promise = utils.executeFunction(fn, args)
          .then(streamToValue)
          .then(value => {
            cleanupTimeout()
            debug('returned value: %o', value)
            const encodedValue = encoder.encode(value) // story it as a string
            debug('encoded value: %o', encodedValue)
            const batch = client.multi()
              .del(`${hash}:running`, `${hash}:error`)
              // NOTE: don't know how buffers transmit over pubsub
              .publish(`${hash}:value`, encoding === 'buffer' ? '1' : encodedValue) // publish the result to all listeners
            // only cache if a TTL is set
            if (ttl) {
              if (encoding === 'buffer') {
                client.set(`${hash}:value`, encodedValue, 'PX', ttl).catch(onError)
              } else {
                batch.set(`${hash}:value`, encodedValue, 'PX', ttl)
              }
            }
            batch.exec().catch(onError)
            return value
          }).catch(_err => {
            cleanupTimeout()
            // handle errors
            const err = utils.stringifyError(_err)
            client.multi()
              .del(`${hash}:running`, `${hash}:value`)
              // publish the error to all listeners
              .publish(`${hash}:error`, err)
              .exec().catch(onError)
            throw _err
          })

          return Promise.race([
            timeout_promise,
            execution_promise,
          ])

          function cleanupTimeout () {
            debug('execution is done!')
            executed = true
            clearInterval(timeout_id)
          }
        }

        // converts a stream response into a value that can be saved in redis
        function streamToValue (value) {
          // handle streams
          if (value && typeof value.pipe === 'function' && value._readableState) {
            // expose the stream
            stream = value

            switch (encoding) {
              case 'json': {
                assert(value._readableState.objectMode, 'I do not know how to handle streams that are not in `objectMode` when saving in with encoding = `json`. Please change your `encoding=` option to `string` or `buffer`')
                // just convert it to an array
                return toArray(value)
              }
              case 'string': {
                value.setEncoding('utf8')
                return toArray(value).then(arr => arr.join(''))
              }
              case 'buffer': {
                return toArray(value).then(arr => Buffer.concat(arr))
              }
            }
          }

          /* istanbul ignore if */
          if (value instanceof Stream) {
            throw new Error('I do not know how to handle this type of stream. It does not have a `.pipe()` function or it does not have a `._readableState.`')
          }

          return value
        }

        // get whether there's a cached value and/or if a query is currently running
        function getCurrentState () {
          const formatResults = results => {
            const state = {
              value: results[0],
              running: results[1],
            }
            debug('state: %o', state)
            return state
          }

          if (encoding === 'buffer') {
            // TODO: should really be using `.multi()` here, but `getBuffer()` is broken in it
            return Promise.all([
              client.getBuffer(`${hash}:value`),
              client.get(`${hash}:running`),
            ]).then(formatResults)
          }

          return client.mget([
            `${hash}:value`,
            `${hash}:running`,
          ]).then(formatResults)
        }

        // poll for updates to the state
        function pollCurrentState (resolve, reject) {
          return setInterval(() => {
            debug('polling for state')
            getCurrentState().then(val => {
              debug('polled for state')
              debug('cleaned: %s', cleaned)
              debug('executed: %s', executed)

              state = val
              // we check here incase cleanup happens during `getCurrentState()` is resolving
              // though I guess it really doesn't matter because resolve/reject is smart
              /* istanbul ignore if */
              if (cleaned || executed) return

              // set somehow, i guess if two functions were running concurrently
              /* istanbul ignore if */
              if (state.value != null) {
                cleanupListeners()
                destroyCurrentStream()
                try {
                  resolve(encoder.decode(state.value))
                } catch (err) {
                  /* istanbul ignore next */
                  reject(err)
                }
                return
              }

              // no longer running
              if (!state.running) {
                cleanupListeners()
                destroyCurrentStream()
                reject(createTimeoutError())
                return
              }
            }).catch(onError)
          }, pollInterval)
        }

        // wait for the result from redis channels and polling
        function waitForResult () {
          debug('waiting for result')
          // subscribe to the channels
          const pattern = `${hash}:*`
          // timeout for polling
          let timeout_id

          return new Promise((resolve, reject) => {
            // expose the cleanup function outside the scope
            cleanupListeners = cleanup

            subscriber.psubscribe(pattern).catch(reject)

            // add a message handler
            subscriber.setMaxListeners(subscriber.getMaxListeners() + 1)
            subscriber.on('pmessage', listener)

            // poll to check the state
            // NOTE: was thinking of using keyevents,
            // but this is better because you need to access the key
            // to trigger an eviction anyways
            timeout_id = pollCurrentState(resolve, reject)

            function listener (pattern, channel, message) {
              if (channel === `${hash}:value`) {
                cleanup()
                debug('message: %s', message)

                // i don't know how to transfer buffer's as a message
                if (encoding === 'buffer') {
                  return getCurrentState().then(_val => {
                    state = _val
                    return encoder.decode(state.value)
                  }).then(resolve, reject)
                }

                try {
                  resolve(encoder.decode(message))
                } catch (err) {
                  // when would this happen?
                  /* istanbul ignore next */
                  reject(err)
                }
              } else if (channel === `${hash}:error`) {
                cleanup()
                try {
                  reject(utils.parseError(message))
                } catch (err) {
                  // when would this happen?
                  /* istanbul ignore next */
                  reject(err)
                }
              }
            }

            function cleanup () {
              debug('cleaning up waiting for the result')
              cleaned = true
              clearInterval(timeout_id)
              subscriber.punsubscribe(pattern).catch(reject)
              subscriber.removeListener('message', listener)
              subscriber.setMaxListeners(subscriber.getMaxListeners() - 1)
            }
          })
        }
      })
    }

    // create a caching hash for this function w/ the specified arguments
    function createHash (args) {
      debug(args)
      return [
        namespace,
        crypto.createHash('sha256')
          .update(stringify(args))
          .digest('hex'),
      ].join(':')
    }
  }
}
<|endoftext|>


<commit_before>const events = require('events');
const http = require('http');
const stream = require('stream');
const util = require('util');
const ws = require('ws');

const debug = util.debuglog('rdbg');

function Console(client) {
  stream.Readable.call(this, {
    objectMode: true
  });

  this.client = client;
  this.client.on('message', function(method, params) {
    if (method === 'Console.messageAdded') {
      this.push(params.message);
    } else if (method === 'Console.messagesCleared') {
      this.emit('clear');
    }
  }.bind(this));
}

util.inherits(Console, stream.Readable);

Console.prototype._read = function() {
};

Console.prototype.enable = function(callback) {
  this.client.request('Console.enable', callback);
};

Console.prototype.disable = function(callback) {
  this.client.request('Console.disable', callback);
};

function Debugger(client) {
  events.EventEmitter.call(this);

  this.client = client;
  this.client.on('message', function(method, params) {
    if (method === 'Debugger.scriptParsed') {
      this.emit('scriptParse', params);
    } else if (method === 'Debugger.scriptFailedToParse') {
      this.emit('scriptError', params);
    } else if (method === 'Debugger.globalObjectCleared') {
      this.emit('clear');
    } else if (method === 'Debugger.paused') {
      this.emit('pause');
    } else if (method === 'Debugger.resume') {
      this.emit('resume');
    }
  }.bind(this));
}

util.inherits(Debugger, events.EventEmitter);

Debugger.prototype.enable = function(callback) {
  this.client.request('Debugger.enable', callback);
};

Debugger.prototype.disable = function(callback) {
  this.client.request('Debugger.disable', callback);
};

Debugger.prototype.pause = function(callback) {
  this.client.request('Debugger.pause', callback);
};

Debugger.prototype.resume = function(callback) {
  this.client.request('Debugger.resume', callback);
};

Debugger.prototype.canSetScriptSource = function(callback) {
  this.client.request('Debugger.canSetScriptSource', function(error, result) {
    if (error) {
      return callback(error);
    }

    callback(null, result.result);
  });
};

Debugger.prototype.getScriptSource = function(script, callback) {
  this.client.request('Debugger.getScriptSource', {
    scriptId: script,
  }, function(error, result) {
    if (error) {
      return callback(error);
    }

    callback(null, result.scriptSource);
  });
};

Debugger.prototype.setScriptSource = function(script, source, callback) {
  if (typeof script === 'object') {
    script = script.scriptId;
  }

  this.client.request('Debugger.setScriptSource', {
    scriptId: script,
    scriptSource: source
  }, callback);
};

function Runtime(client) {
  this.client = client;

  this.client.on('message', function(method, params) {
  }.bind(this));
}

util.inherits(Runtime, events.EventEmitter);

Runtime.prototype.enable = function(callback) {
  this.client.request('Runtime.enable', callback);
};

Runtime.prototype.evaluate = function(cmd, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = undefined;
  }

  if (options == undefined) {
    options = {};
  }

  this.client.request('Runtime.evaluate', {
    expression: cmd,
    objectGroup: options.objectGroup,
    contextId: options.contextId,
  }, callback);
};

function Client() {
  events.EventEmitter.call(this);

  this._socket = null;

  this._callbacks = {};
  this._commands = {};
  this._counter = 0;
}

util.inherits(Client, events.EventEmitter);

Object.defineProperty(Client.prototype, 'socket', {
  get: function() {
    return this._socket;
  },
});

Object.defineProperty(Client.prototype, 'console', {
  get: function() {
    if (!this._console) {
      this._console = new Console(this);
    }

    return this._console;
  },
});

Object.defineProperty(Client.prototype, 'debugger', {
  get: function() {
    if (!this._debugger) {
      this._debugger = new Debugger(this);
    }

    return this._debugger;
  },
});

Object.defineProperty(Client.prototype, 'runtime', {
  get: function() {
    if (!this._runtime) {
      this._runtime = new Runtime(this);
    }

    return this._runtime;
  },
});

Client.prototype.request = function(method, params, id, callback) {
  if (typeof params === 'function') {
    callback = params;
    params = undefined;
  } else if (typeof id === 'function') {
    callback = id;
    id = undefined;
  }

  if (params === undefined) {
    params = {};
  }

  if (id === undefined) {
    id = this._counter++;
  }

  var request = {
    id: id,
    method: method,
    params: params
  };

  debug('request %s', util.inspect(request));
  this.emit('request', request);
  this._socket.send(JSON.stringify(request));

  this._callbacks[id] = callback;
  this._commands[id] = request;
};

Client.prototype.connect = function(target, callback) {
  if (typeof target === 'object') {
    target = target.webSocketDebuggerUrl;
  }

  if (callback) {
    this.on('connect', callback);
  }

  var socket = ws.connect(target);
  socket.on('open', function() {
    debug('connect');
    this.emit('connect');

    if (Object.keys(this._commands).length === 0) {
      this.emit('ready');
    }
  }.bind(this));

  socket.on('close', function() {
    debug('close');
    this.emit('close');
    this._socket = null;
  }.bind(this));

  socket.on('error', function(error) {
    debug('error %s', util.inspect(error));
    this.emit('error', error);
  }.bind(this));

  socket.on('message', function(data) {
    try {
      var message = JSON.parse(data);

      if (message.id !== undefined) {
        var command = this._commands[message.id];
        var callback = this._callbacks[message.id];

        debug('response %s, %s', util.inspect(command), util.inspect(message));
        this.emit('response', command, message);

        if (callback) {
          if (message.error) {
            callback(message.error);
          } else if (message.result) {
            callback(null, message.result);
          }

          delete this._callbacks[message.id];
        }

        delete this._commands[message.id];

        if (Object.keys(this._commands).length === 0) {
          this.emit('ready');
        }
      } else {
        debug('message %s', util.inspect(message));
        this.emit('message', message.method, message.params);
      }
    } catch (error) {
      this.emit('error', error);
    }
  }.bind(this));

  this._socket = socket;

  debug('socket');
  this.emit('socket');
};

Client.prototype.close = function() {
  if (this._socket) {
    this._socket.close();
  }
};

module.exports.Client = Client;

function createClient() {
  var client = new Client();
  return client;
}

module.exports.createClient = createClient;

function connect(target, callback) {
  var client = createClient();
  client.connect(target, callback);

  return client;
}

module.exports.connect = connect;

function get(port, host, callback) {
  if (typeof host === 'function') {
    callback = host;
    host = 'localhost';
  }

  var request = http.get({
    port: port,
    host: host,
    path: '/json'
  });

  request.on('response', function(response) {
    var body = '';

    response.on('data', function(chunk) {
      body += chunk;
    });

    response.on('end', function() {
      try {
        var targets = JSON.parse(body);
        return callback(null, targets);
      } catch (error) {
        return callback(error);
      }
    });
  });

  request.on('error', function(error) {
    return callback(error);
  });
};

module.exports.get = get;
<commit_msg>lib: use `scriptId` for script parameters<commit_after>const events = require('events');
const http = require('http');
const stream = require('stream');
const util = require('util');
const ws = require('ws');

const debug = util.debuglog('rdbg');

function Console(client) {
  stream.Readable.call(this, {
    objectMode: true
  });

  this.client = client;
  this.client.on('message', function(method, params) {
    if (method === 'Console.messageAdded') {
      this.push(params.message);
    } else if (method === 'Console.messagesCleared') {
      this.emit('clear');
    }
  }.bind(this));
}

util.inherits(Console, stream.Readable);

Console.prototype._read = function() {
};

Console.prototype.enable = function(callback) {
  this.client.request('Console.enable', callback);
};

Console.prototype.disable = function(callback) {
  this.client.request('Console.disable', callback);
};

function Debugger(client) {
  events.EventEmitter.call(this);

  this.client = client;
  this.client.on('message', function(method, params) {
    if (method === 'Debugger.scriptParsed') {
      this.emit('scriptParse', params);
    } else if (method === 'Debugger.scriptFailedToParse') {
      this.emit('scriptError', params);
    } else if (method === 'Debugger.globalObjectCleared') {
      this.emit('clear');
    } else if (method === 'Debugger.paused') {
      this.emit('pause');
    } else if (method === 'Debugger.resume') {
      this.emit('resume');
    }
  }.bind(this));
}

util.inherits(Debugger, events.EventEmitter);

Debugger.prototype.enable = function(callback) {
  this.client.request('Debugger.enable', callback);
};

Debugger.prototype.disable = function(callback) {
  this.client.request('Debugger.disable', callback);
};

Debugger.prototype.pause = function(callback) {
  this.client.request('Debugger.pause', callback);
};

Debugger.prototype.resume = function(callback) {
  this.client.request('Debugger.resume', callback);
};

Debugger.prototype.canSetScriptSource = function(callback) {
  this.client.request('Debugger.canSetScriptSource', function(error, result) {
    if (error) {
      return callback(error);
    }

    callback(null, result.result);
  });
};

Debugger.prototype.getScriptSource = function(scriptId, callback) {
  this.client.request('Debugger.getScriptSource', {
    scriptId: scriptId,
  }, function(error, result) {
    if (error) {
      return callback(error);
    }

    callback(null, result.scriptSource);
  });
};

Debugger.prototype.setScriptSource = function(scriptId, source, callback) {
  this.client.request('Debugger.setScriptSource', {
    scriptId: scriptId,
    scriptSource: source
  }, callback);
};

function Runtime(client) {
  this.client = client;

  this.client.on('message', function(method, params) {
  }.bind(this));
}

util.inherits(Runtime, events.EventEmitter);

Runtime.prototype.enable = function(callback) {
  this.client.request('Runtime.enable', callback);
};

Runtime.prototype.evaluate = function(cmd, options, callback) {
  if (typeof options === 'function') {
    callback = options;
    options = undefined;
  }

  if (options == undefined) {
    options = {};
  }

  this.client.request('Runtime.evaluate', {
    expression: cmd,
    objectGroup: options.objectGroup,
    contextId: options.contextId,
  }, callback);
};

function Client() {
  events.EventEmitter.call(this);

  this._socket = null;

  this._callbacks = {};
  this._commands = {};
  this._counter = 0;
}

util.inherits(Client, events.EventEmitter);

Object.defineProperty(Client.prototype, 'socket', {
  get: function() {
    return this._socket;
  },
});

Object.defineProperty(Client.prototype, 'console', {
  get: function() {
    if (!this._console) {
      this._console = new Console(this);
    }

    return this._console;
  },
});

Object.defineProperty(Client.prototype, 'debugger', {
  get: function() {
    if (!this._debugger) {
      this._debugger = new Debugger(this);
    }

    return this._debugger;
  },
});

Object.defineProperty(Client.prototype, 'runtime', {
  get: function() {
    if (!this._runtime) {
      this._runtime = new Runtime(this);
    }

    return this._runtime;
  },
});

Client.prototype.request = function(method, params, id, callback) {
  if (typeof params === 'function') {
    callback = params;
    params = undefined;
  } else if (typeof id === 'function') {
    callback = id;
    id = undefined;
  }

  if (params === undefined) {
    params = {};
  }

  if (id === undefined) {
    id = this._counter++;
  }

  var request = {
    id: id,
    method: method,
    params: params
  };

  debug('request %s', util.inspect(request));
  this.emit('request', request);
  this._socket.send(JSON.stringify(request));

  this._callbacks[id] = callback;
  this._commands[id] = request;
};

Client.prototype.connect = function(target, callback) {
  if (typeof target === 'object') {
    target = target.webSocketDebuggerUrl;
  }

  if (callback) {
    this.on('connect', callback);
  }

  var socket = ws.connect(target);
  socket.on('open', function() {
    debug('connect');
    this.emit('connect');

    if (Object.keys(this._commands).length === 0) {
      this.emit('ready');
    }
  }.bind(this));

  socket.on('close', function() {
    debug('close');
    this.emit('close');
    this._socket = null;
  }.bind(this));

  socket.on('error', function(error) {
    debug('error %s', util.inspect(error));
    this.emit('error', error);
  }.bind(this));

  socket.on('message', function(data) {
    try {
      var message = JSON.parse(data);

      if (message.id !== undefined) {
        var command = this._commands[message.id];
        var callback = this._callbacks[message.id];

        debug('response %s, %s', util.inspect(command), util.inspect(message));
        this.emit('response', command, message);

        if (callback) {
          if (message.error) {
            callback(message.error);
          } else if (message.result) {
            callback(null, message.result);
          }

          delete this._callbacks[message.id];
        }

        delete this._commands[message.id];

        if (Object.keys(this._commands).length === 0) {
          this.emit('ready');
        }
      } else {
        debug('message %s', util.inspect(message));
        this.emit('message', message.method, message.params);
      }
    } catch (error) {
      this.emit('error', error);
    }
  }.bind(this));

  this._socket = socket;

  debug('socket');
  this.emit('socket');
};

Client.prototype.close = function() {
  if (this._socket) {
    this._socket.close();
  }
};

module.exports.Client = Client;

function createClient() {
  var client = new Client();
  return client;
}

module.exports.createClient = createClient;

function connect(target, callback) {
  var client = createClient();
  client.connect(target, callback);

  return client;
}

module.exports.connect = connect;

function get(port, host, callback) {
  if (typeof host === 'function') {
    callback = host;
    host = 'localhost';
  }

  var request = http.get({
    port: port,
    host: host,
    path: '/json'
  });

  request.on('response', function(response) {
    var body = '';

    response.on('data', function(chunk) {
      body += chunk;
    });

    response.on('end', function() {
      try {
        var targets = JSON.parse(body);
        return callback(null, targets);
      } catch (error) {
        return callback(error);
      }
    });
  });

  request.on('error', function(error) {
    return callback(error);
  });
};

module.exports.get = get;
<|endoftext|>


<commit_before>'use strict';

var protocol = {
  http: require('http'),
  https: require('https')
};

var url = require('url');

function corsHeaders(overrides) {
  return [
    'Access-Control-Allow-Origin',
    'Access-Control-Request-Method',
    'Access-Control-Allow-Methods',
    'Access-Control-Allow-Headers'
  ].reduce(function (headers, method) {
    headers[method] = overrides[method] || '*';

    return headers;
  }, {});
}

function PicoProxy(options) {
  options = options || {};

  if (!(this instanceof PicoProxy)) {
    return new PicoProxy(options);
  }

  this._target = url.parse(options.target || 'http://127.0.0.1');
  this._protocol = options.protocol || 'http';
  this._targetProtocol = this._target.protocol.slice(0, -1);
  this._cors = options.cors || true;
  this._corsOverrides = {
    'Access-Control-Allow-Headers': options.allowHeaders || '*',
    'Access-Control-Allow-Methods': options.allowMethods || '*',
  };

  this._proxy = this.createServer(function (req, res) {
    var request = protocol[this._protocol].request(this.createRequestOptions(req), function (serverRes) {
      if (this._cors) {
        serverRes.headers['Access-Control-Allow-Origin'] = '*'
      }

      res.writeHead(serverRes.statusCode, serverRes.headers);
      serverRes.pipe(res, { end: true });
    }.bind(this));

    req.pipe(request, { end: true });
  }.bind(this));

  return this;
}

PicoProxy.prototype.createRequestOptions = function (req) {
  var requestUrl = url.parse(req.url);

  return {
    method: req.method,
    hostname: this._target.hostname,
    path: requestUrl.path,
    headers: Object.keys(req.headers).reduce(function (reqHeaders, header) {
      reqHeaders[header] = header === 'host' ? this._target.hostname : req.headers[header];

      return reqHeaders;
    }.bind(this), {})
  };
};

PicoProxy.prototype.listen = function (port, cb) {
  port = port || 8080;
  this._proxy.listen(port, cb);

  return this;
};

PicoProxy.prototype.close = function () {
  this._proxy.close();
};

PicoProxy.prototype.createServer = function (cb) {
  return protocol[this._protocol].createServer(function (req, res) {
    if (this._cors) {
      res.writeHead(200, corsHeaders(this._corsOverrides));
    }

    if (this._cors && req.method.toLowerCase() === 'options') {
      return res.end();
    }

    cb(req, res);
  }.bind(this));
};

exports = module.exports = PicoProxy;
<commit_msg>Parse and consume target port number<commit_after>'use strict';

var protocol = {
  http: require('http'),
  https: require('https')
};

var url = require('url');

function corsHeaders(overrides) {
  return [
    'Access-Control-Allow-Origin',
    'Access-Control-Request-Method',
    'Access-Control-Allow-Methods',
    'Access-Control-Allow-Headers'
  ].reduce(function (headers, method) {
    headers[method] = overrides[method] || '*';

    return headers;
  }, {});
}

function PicoProxy(options) {
  options = options || {};

  if (!(this instanceof PicoProxy)) {
    return new PicoProxy(options);
  }

  this._target = url.parse(options.target || 'http://127.0.0.1');
  this._protocol = options.protocol || 'http';
  this._targetProtocol = this._target.protocol.slice(0, -1);
  this._cors = options.cors || true;
  this._corsOverrides = {
    'Access-Control-Allow-Headers': options.allowHeaders || '*',
    'Access-Control-Allow-Methods': options.allowMethods || '*',
  };

  this._proxy = this.createServer(function (req, res) {
    var request = protocol[this._protocol].request(this.createRequestOptions(req), function (serverRes) {
      if (this._cors) {
        serverRes.headers['Access-Control-Allow-Origin'] = '*'
      }

      res.writeHead(serverRes.statusCode, serverRes.headers);
      serverRes.pipe(res, { end: true });
    }.bind(this));

    req.pipe(request, { end: true });
  }.bind(this));

  return this;
}

PicoProxy.prototype.createRequestOptions = function (req) {
  var requestUrl = url.parse(req.url);

  return {
    method: req.method,
    hostname: this._target.hostname,
    port: this._target.port,
    path: requestUrl.path,
    headers: Object.keys(req.headers).reduce(function (reqHeaders, header) {
      reqHeaders[header] = header === 'host' ? this._target.hostname : req.headers[header];

      return reqHeaders;
    }.bind(this), {})
  };
};

PicoProxy.prototype.listen = function (port, cb) {
  port = port || 8080;
  this._proxy.listen(port, cb);

  return this;
};

PicoProxy.prototype.close = function () {
  this._proxy.close();
};

PicoProxy.prototype.createServer = function (cb) {
  return protocol[this._protocol].createServer(function (req, res) {
    if (this._cors) {
      res.writeHead(200, corsHeaders(this._corsOverrides));
    }

    if (this._cors && req.method.toLowerCase() === 'options') {
      return res.end();
    }

    cb(req, res);
  }.bind(this));
};

exports = module.exports = PicoProxy;
<|endoftext|>


<commit_before>var TAPPED_OUT_HOSTNAME = "tappedout.net";
var EDHREC_API_URL = "http://edhrec.com/rec";
var API_REF = "kevin";
var LAND_TYPE = "Land";
var CREATURE_TYPE = "Creature";
var MAX_RECOMMENDATIONS_PER_CATEGORY = 15;

app.service("recommendationService", function($http, $q) {
  this.isValidDeckUrl_ = function(deckUrl) {
    var parser = document.createElement("a");
    parser.href = deckUrl;
    return parser.hostname === TAPPED_OUT_HOSTNAME;
  };

  // Sorts cards by score in descending order.
  this.cardSortFunction_ = function(card1, card2) {
    return card2.score - card1.score;
  }

  this.isLand_ = function(card) {
    return $.inArray(LAND_TYPE, card.card_info.types) > -1;
  }

  this.isCreature_ = function(card) {
    return $.inArray(CREATURE_TYPE, card.card_info.types) > -1;
  }

  this.getRecommendations = function(deckUrl) {
    var deferred = $q.defer();

    if (!this.isValidDeckUrl_(deckUrl)) {
      deferred.reject("Invalid deck URL.");
      return deferred.promise;
    }

    var url = EDHREC_API_URL + "?to=" + deckUrl + "&ref=" + API_REF;
    $http.get(url).then($.proxy(function(result) {
      var recs = result.data.recs.sort(this.cardSortFunction_);

      var recommendations = {
        top: [],
        creatures: [],
        nonCreatures: [],
        lands: [],
        // Deliberately not sorting cuts since a lot of them end up with the same score.
        cuts: result.data.cuts
      };

      for (var i = 0; i < recs.length; i++) {
        var card = recs[i];
        var land = this.isLand_(card);
        var creature = this.isCreature_(card);

        if (recommendations.top.length < 12 && !land) {
          recommendations.top.push(card);
        } else {
          if (land) {
            recommendations.lands.push(card);
          } else if (creature) {
            recommendations.creatures.push(card);
          } else {
            recommendations.nonCreatures.push(card);
          }
        }
      }

      recommendations.creatures = recommendations.creatures.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY);
      recommendations.nonCreatures = recommendations.nonCreatures.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY);
      recommendations.lands = recommendations.lands.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY);
      recommendations.cuts = recommendations.cuts.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY);

      deferred.resolve(recommendations);
    }, this), function(error) {
      deferred.reject("Error generating recommendations. Status code: " + error.status);
    });

    return deferred.promise;
  };
});<commit_msg>Refactor recommendationService callback<commit_after>var TAPPED_OUT_HOSTNAME = "tappedout.net";
var EDHREC_API_URL = "http://edhrec.com/rec";
var API_REF = "kevin";
var LAND_TYPE = "Land";
var CREATURE_TYPE = "Creature";
var MAX_TOP_RECOMMENDATIONS = 12;
var MAX_RECOMMENDATIONS_PER_CATEGORY = 15;

app.service("recommendationService", function($http, $q) {
  this.isValidDeckUrl_ = function(deckUrl) {
    var parser = document.createElement("a");
    parser.href = deckUrl;
    return parser.hostname === TAPPED_OUT_HOSTNAME;
  };

  // Sorts cards by score in descending order.
  this.cardSortFunction_ = function(card1, card2) {
    return card2.score - card1.score;
  }

  this.isLand_ = function(card) {
    return $.inArray(LAND_TYPE, card.card_info.types) > -1;
  }

  this.isCreature_ = function(card) {
    return $.inArray(CREATURE_TYPE, card.card_info.types) > -1;
  }

  this.parseResponse_ = function(data) {
    var recs = data.recs.sort(this.cardSortFunction_);
    var cuts = data.cuts; // Deliberately not sorting since most have the same score.
    var top = [];
    var creatures = [];
    var nonCreatures = [];
    var lands = [];

    for (var i = 0; i < recs.length; i++) {
      var card = recs[i];
      var land = this.isLand_(card);
      var creature = this.isCreature_(card);

      if (top.length < MAX_TOP_RECOMMENDATIONS && !land) {
        top.push(card);
      } else {
        if (land) {
          lands.push(card);
        } else if (creature) {
          creatures.push(card);
        } else {
          nonCreatures.push(card);
        }
      }
    }

    return {
      top: top,
      creatures: creatures.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY),
      nonCreatures: nonCreatures.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY),
      lands: lands.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY),
      cuts: cuts.slice(0, MAX_RECOMMENDATIONS_PER_CATEGORY)
    };
  }

  this.getRecommendations = function(deckUrl) {
    var deferred = $q.defer();
    if (!this.isValidDeckUrl_(deckUrl)) {
      deferred.reject("Invalid deck URL.");
      return deferred.promise;
    }

    var url = EDHREC_API_URL + "?to=" + deckUrl + "&ref=" + API_REF;
    $http.get(url).then($.proxy(function(result) {
      deferred.resolve(this.parseResponse_(result.data));
    }, this), function(error) {
      deferred.reject("Error generating recommendations. Status code: " + error.status);
    });

    return deferred.promise;
  };
});<|endoftext|>


<commit_before>var yargs = require('yargs');
var argv = require('yargs').argv;
var combiner = require('stream-combiner2');
var fs = require('fs');
var Path = require('path');
var gulpUtil = require('gulp-util');
var runSequence = require('run-sequence');
var del = require('del');

/**
 * test task arguments
 * grep: grep string
 * d (boolean): allow debugger breakpoints (using node-inspector)
 */
module.exports = function(gulp, options) {
  var separateTests = options.separateTests = !!options.rootTestsDir;
  var scriptsDirName = options.scriptsDirName || 'js';
  var taskName = options.taskName || 'test';
  var testsDirName = options.testsDirName || 'tests';

  options = Object.assign({}, options, {
    taskName: taskName,
    scriptsDirName: scriptsDirName,
    testFilePattern: options.testFilePattern || '{name}-test',
    separateTests: separateTests,
    testsDirName: options.testsDirName || (separateTests ? 'tests' : '_tests'),
    glob: separateTests ? [scriptsDirName + '/**/*', testsDirName + '/**/*'] : scriptsDirName + '/**/*',
    initFunction: options.init ? ('(' + options.init + ')();') : '',
    outputPath: './.test',
    gulp: gulp
  });
  options.mochaOptions = getMochaOptions(options);
  options.debugMode = options.mochaOptions['debug-brk'];
  options.testsDirName = options.testsDirName || testsDirName;

  // don't do coverage if we are using grep
  if ((argv.grep || options.debugMode) && options.istanbul) {
    delete options.istanbul;
  }

  // define task names
  var prepareAssetsTask = taskName + '-prepare-assets';
  var istanbulTask = taskName + '-istanbul';
  var watchTask = taskName + '-watch';
  var cleanTask = taskName + '-clean';
  var executeTask = taskName + '-execute';

  function combine(streams, watch) {
    var pipeline = streams[0];
    for (var i = 1; i < streams.length; i++) {
      pipeline = pipeline.pipe(streams[i]);
      pipeline = pipeline.on('error', function (err) {
        gulpUtil.log(gulpUtil.colors.red(err.message));
        if (!watch) {
          gulpUtil.log(err.stack);
          process.exit(1);
        } else if (options.readyForTesting) {
          process.stdout.write('\033c');
          gulpUtil.log('=======================\n');
          gulpUtil.log(err.stack);
          gulpUtil.beep();
        }
      });
    }
    return pipeline;
  }

  /**
   * WATCHER TASK
   */
  gulp.task(watchTask, [cleanTask], function () {
    delete options.istanbul;
    return combine(require('./tasks/watching-test-task')(options), true);
  });

  /**
   * CLEAN TEMP DIR
   */
  gulp.task(cleanTask, function (cb) {
    return del([options.outputPath + '/**/*']);
  });

  /**
   * PREPARE FILES FOR TESTING
   */
  gulp.task(prepareAssetsTask, function () {
    return combine(require('./tasks/prepare-assets-task')(options));
  });

  /**
   * PROCESS FILES FOR ISTANBUL
   */
  gulp.task(istanbulTask, function () {
    return combine(require('./tasks/prepare-istanbul-task')(options));
  });

  /**
   * RUN THE TEST
   */
  gulp.task(executeTask, function () {
    return combine(require('./tasks/run-test-task')(options));
  });

  gulp.task(taskName, function (cb) {
    var tasks = [
      cleanTask,
      prepareAssetsTask,
      options.istanbul && istanbulTask,
      executeTask
    ].filter(function (task) { return !!task });

    var args = tasks.concat([cb]);
    var context = runSequence.use(gulp);

    context.apply(context, args);
  });
}

function getMochaOptions(options) {
  var mochaArgs = Object.assign({}, argv, {
    R: 'spec',
    'debug-brk': argv.d
  }, options.mocha);
  return mochaArgs;
}
<commit_msg>Support configurable output path<commit_after>var yargs = require('yargs');
var argv = require('yargs').argv;
var combiner = require('stream-combiner2');
var fs = require('fs');
var Path = require('path');
var gulpUtil = require('gulp-util');
var runSequence = require('run-sequence');
var del = require('del');

/**
 * test task arguments
 * grep: grep string
 * d (boolean): allow debugger breakpoints (using node-inspector)
 */
module.exports = function(gulp, options) {
  var separateTests = options.separateTests = !!options.rootTestsDir;
  var scriptsDirName = options.scriptsDirName || 'js';
  var taskName = options.taskName || 'test';
  var testsDirName = options.testsDirName || 'tests';

  options = Object.assign({}, options, {
    taskName: taskName,
    scriptsDirName: scriptsDirName,
    testFilePattern: options.testFilePattern || '{name}-test',
    separateTests: separateTests,
    testsDirName: options.testsDirName || (separateTests ? 'tests' : '_tests'),
    glob: separateTests ? [scriptsDirName + '/**/*', testsDirName + '/**/*'] : scriptsDirName + '/**/*',
    initFunction: options.init ? ('(' + options.init + ')();') : '',
    outputPath: options.outputPath || './.test',
    gulp: gulp
  });
  options.mochaOptions = getMochaOptions(options);
  options.debugMode = options.mochaOptions['debug-brk'];
  options.testsDirName = options.testsDirName || testsDirName;

  // don't do coverage if we are using grep
  if ((argv.grep || options.debugMode) && options.istanbul) {
    delete options.istanbul;
  }

  // define task names
  var prepareAssetsTask = taskName + '-prepare-assets';
  var istanbulTask = taskName + '-istanbul';
  var watchTask = taskName + '-watch';
  var cleanTask = taskName + '-clean';
  var executeTask = taskName + '-execute';

  function combine(streams, watch) {
    var pipeline = streams[0];
    for (var i = 1; i < streams.length; i++) {
      pipeline = pipeline.pipe(streams[i]);
      pipeline = pipeline.on('error', function (err) {
        gulpUtil.log(gulpUtil.colors.red(err.message));
        if (!watch) {
          gulpUtil.log(err.stack);
          process.exit(1);
        } else if (options.readyForTesting) {
          process.stdout.write('\033c');
          gulpUtil.log('=======================\n');
          gulpUtil.log(err.stack);
          gulpUtil.beep();
        }
      });
    }
    return pipeline;
  }

  /**
   * WATCHER TASK
   */
  gulp.task(watchTask, [cleanTask], function () {
    delete options.istanbul;
    return combine(require('./tasks/watching-test-task')(options), true);
  });

  /**
   * CLEAN TEMP DIR
   */
  gulp.task(cleanTask, function (cb) {
    return del([options.outputPath + '/**/*']);
  });

  /**
   * PREPARE FILES FOR TESTING
   */
  gulp.task(prepareAssetsTask, function () {
    return combine(require('./tasks/prepare-assets-task')(options));
  });

  /**
   * PROCESS FILES FOR ISTANBUL
   */
  gulp.task(istanbulTask, function () {
    return combine(require('./tasks/prepare-istanbul-task')(options));
  });

  /**
   * RUN THE TEST
   */
  gulp.task(executeTask, function () {
    return combine(require('./tasks/run-test-task')(options));
  });

  gulp.task(taskName, function (cb) {
    var tasks = [
      cleanTask,
      prepareAssetsTask,
      options.istanbul && istanbulTask,
      executeTask
    ].filter(function (task) { return !!task });

    var args = tasks.concat([cb]);
    var context = runSequence.use(gulp);

    context.apply(context, args);
  });
}

function getMochaOptions(options) {
  var mochaArgs = Object.assign({}, argv, {
    R: 'spec',
    'debug-brk': argv.d
  }, options.mocha);
  return mochaArgs;
}
<|endoftext|>


<commit_before>const responses = {};

const catchers  = {
	debug:  log,
	info:   log,
	warn:   log,
	error:  log,
	fatal:  log,
};

const errorLevel = {
	debug: 0,
	info:  1,
	warn:  2,
	error: 3,
	fatal: 4,
};

const statuses = { };

var minErrorLevel = 0;

function logger(level) {
	return function (code, reasons, meta) {
		var err = new CuvvaError(code, reasons, meta);

		propagateError(level, err);

		return err;
	};
}

function log(level, err) {
	// Pad so the codes of error/fatal line up with that of info and warn
	// TODO: print out inner errors instead of swallowing them (just verbose mode?)
	//       possibly not necessary as the errors are likely created with log.error anyway(?)
	var errorString = message(level, err);

	f = level == 'fatal' ? 'error' : level;
	if (f in console) {
		console[f](errorString);
	}
	else {
		console.log(errorString);
	}
}

function message(level, err) {
	var errorString = pad(level, 5) + ': ' + err.code;
	const desc = err.meta;

	if (desc)
		errorString += '\n' + JSON.stringify(desc);

	return errorString;
}

function pad(str, len) {
	if (str.length < len)
		str += new Array(len - str.length + 1).join(' ');

	return str;
}

function description(err) {
	const response = responses[err.code];

	if (typeof response === 'undefined')
		return '';

	return response(err.meta);
}

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);

	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	this.message =
		this.code = code;
	this.reasons = reasons;
	this.meta = meta;
}

CuvvaError.prototype = Object.create(Error.prototype, {
	constructor: { value: CuvvaError }
});

function propagateError(level, err) {
	if (!(level in catchers) ||
		errorLevel[level] < minErrorLevel)
		return;

	catchers[level](level, err);
}

function handler(level, catcher) {
	if (typeof catcher === 'undefined') {
		catcher = level;

		if (typeof catcher !== 'function')
			throw new Error('Catcher is not a function');

		for (var prop in catchers)
			catchers[prop] = catcher;

		return;
	}

	if (typeof catcher !== 'function')
		throw new Error('Catcher is not a function');

	catchers[level] = catcher;
}

function setLogLevel(n) {
	minErrorLevel = errorLevel[n];
}

function status(err) {
	if (typeof err === 'string')
		return statuses[err];

	return statuses[err.code];
}

function setStatuses(s) {
	for (var o in s)
		statuses[o] = s[o];
}

module.exports = {
	debug:       logger('debug'),
	info:        logger('info'),
	warn:        logger('warn'),
	error:       logger('error'),
	fatal:       logger('fatal'),
	addHandler:  handler,
	Error:       CuvvaError,
	setLevel:    setLogLevel,
	status:      status,
	setStatuses: setStatuses,
	levels:      errorLevel,
};
<commit_msg>Add stack tracing to CuvvaError's<commit_after>const responses = {};

const catchers  = {
	debug:  log,
	info:   log,
	warn:   log,
	error:  log,
	fatal:  log,
};

const errorLevel = {
	debug: 0,
	info:  1,
	warn:  2,
	error: 3,
	fatal: 4,
};

const statuses = { };

var minErrorLevel = 0;

function logger(level) {
	return function (code, reasons, meta) {
		var err = new CuvvaError(code, reasons, meta);

		propagateError(level, err);

		return err;
	};
}

function log(level, err) {
	// Pad so the codes of error/fatal line up with that of info and warn
	// TODO: print out inner errors instead of swallowing them (just verbose mode?)
	//       possibly not necessary as the errors are likely created with log.error anyway(?)
	var errorString = message(level, err);

	f = level == 'fatal' ? 'error' : level;
	if (f in console) {
		console[f](errorString);
	}
	else {
		console.log(errorString);
	}
}

function message(level, err) {
	var errorString = pad(level, 5) + ': ' + err.code;
	const desc = err.meta;

	if (desc)
		errorString += '\n' + JSON.stringify(desc);

	return errorString;
}

function pad(str, len) {
	if (str.length < len)
		str += new Array(len - str.length + 1).join(' ');

	return str;
}

function description(err) {
	const response = responses[err.code];

	if (typeof response === 'undefined')
		return '';

	return response(err.meta);
}

function CuvvaError(code, reasons, meta) {
	if (!(this instanceof CuvvaError))
		return new CuvvaError(code, reasons, meta);
	Error.call(this, code);
	if (!Array.isArray(reasons)) {
		meta = reasons;
		reasons = void 0;
	}

	this.code =    this.message;
	this.reasons = reasons;
	this.meta =    meta;
}

CuvvaError.prototype = Object.create(Error.prototype, {
	constructor: { value: CuvvaError }
});

function propagateError(level, err) {
	if (!(level in catchers) ||
		errorLevel[level] < minErrorLevel)
		return;

	catchers[level](level, err);
}

function handler(level, catcher) {
	if (typeof catcher === 'undefined') {
		catcher = level;

		if (typeof catcher !== 'function')
			throw new Error('Catcher is not a function');

		for (var prop in catchers)
			catchers[prop] = catcher;

		return;
	}

	if (typeof catcher !== 'function')
		throw new Error('Catcher is not a function');

	catchers[level] = catcher;
}

function setLogLevel(n) {
	minErrorLevel = errorLevel[n];
}

function status(err) {
	if (typeof err === 'string')
		return statuses[err];

	return statuses[err.code];
}

function setStatuses(s) {
	for (var o in s)
		statuses[o] = s[o];
}

module.exports = {
	debug:       logger('debug'),
	info:        logger('info'),
	warn:        logger('warn'),
	error:       logger('error'),
	fatal:       logger('fatal'),
	addHandler:  handler,
	Error:       CuvvaError,
	setLevel:    setLogLevel,
	status:      status,
	setStatuses: setStatuses,
	levels:      errorLevel,
};
<|endoftext|>


<commit_before>'use strict';

var Entities = require('html-entities').AllHtmlEntities;
var entities = new Entities();

var config = require('../config/configuration.js');

function htmlReplace(str) {
  return entities.decode(str
    .replace(/