<commit_before>
// CommonJS require()

function require(p){
    var path = require.resolve(p)
      , mod = require.modules[path];
    if (!mod) throw new Error('failed to require "' + p + '"');
    if (!mod.exports) {
      mod.exports = {};
      mod.call(mod.exports, mod, mod.exports, require.relative(path));
    }
    return mod.exports;
  }

require.modules = {};

require.resolve = function (path){
    var orig = path
      , reg = path + '.js'
      , index = path + '/index.js';
    return require.modules[reg] && reg
      || require.modules[index] && index
      || orig;
  };

require.register = function (path, fn){
    require.modules[path] = fn;
  };

require.relative = function (parent) {
    return function(p){
      if ('.' != p[0]) return require(p);

      var path = parent.split('/')
        , segs = p.split('/');
      path.pop();

      for (var i = 0; i < segs.length; i++) {
        var seg = segs[i];
        if ('..' == seg) path.pop();
        else if ('.' != seg) path.push(seg);
      }

      return require(path.join('/'));
    };
  };

require.register("assertion.js", function(module, exports, require){

var AssertionError = require('./error');

module.exports = Assertion;

function inspect (val) {
  return (val ? val.toString() : 'null');
}

function Assertion (obj, msg) {
  this.obj = obj;
  this.msg = msg;
}

Assertion.prototype.assert = function (expr, msg, negateMsg) {
  var msg = (this.msg ? this.msg + ': ' : '') + (this.negate ? negateMsg : msg)
    , ok = this.negate ? !expr : expr;

  if (!ok) {
    throw new AssertionError({
      message: msg,
      startStackFunction: this.assert
    });
  }
};

Assertion.prototype.__defineGetter__('inspect', function () {
  return inspect(this.obj);
});

Assertion.prototype.__defineGetter__('to', function () {
  return this;
});

Assertion.prototype.__defineGetter__('be', function () {
  return this;
});

Assertion.prototype.__defineGetter__('an', function () {
  return this;
});

Assertion.prototype.__defineGetter__('is', function () {
  return this;
});

Assertion.prototype.__defineGetter__('and', function () {
  return this;
});

Assertion.prototype.__defineGetter__('have', function () {
  return this;
});

Assertion.prototype.__defineGetter__('include', function () {
  this.include = true;
  return this;
});

Assertion.prototype.__defineGetter__('not', function () {
  this.negate = true;
  return this;
});

Assertion.prototype.__defineGetter__('ok', function () {
  this.assert(
      this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('true', function () {
  this.assert(
      true === this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('false', function () {
  this.assert(
      false === this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('exist', function () {
  this.assert(
      null != this.obj
    , 'expected ' + this.inspect + ' to exist'
    , 'expected ' + this.inspect + ' to not exist');

  return this;
});

Assertion.prototype.__defineGetter__('empty', function () {
  new Assertion(this.obj).to.have.property('length');

  this.assert(
      0 === this.obj.length
    , 'expected ' + this.inspect + ' to exist'
    , 'expected ' + this.inspect + ' to not exist');

  return this;
});

Assertion.prototype.equal = function (val) {
  this.assert(
      val === this.obj
    , 'expected ' + this.inspect + ' to equal ' + inspect(val)
    , 'expected ' + this.inspect + ' to not equal ' + inspect(val));

  return this;
};

Assertion.prototype.eql = function (obj) {

  return this;
};

Assertion.prototype.above = function (val) {
  this.assert(
      this.obj > val
    , 'expected ' + this.inspect + ' to be above ' + val
    , 'expected ' + this.inspect + ' to be below' + val);

  return this;
};

Assertion.prototype.below = function (val) {
  this.assert(
      this.obj < val
    , 'expected ' + this.inspect + ' to be below ' + val
    , 'expected ' + this.inspect + ' to be above ' + val);

  return this;
};

Assertion.prototype.a = function (type) {
  this.assert(
      type == typeof this.obj
    , 'expected ' + this.inspect + ' to be a ' + type
    , 'expected ' + this.inspect + ' to not be a ' + type);

  return this;
};

Assertion.prototype.instanceof = function (constructor) {
  var name = constructor.name;
  this.assert(
      this.obj instanceof constructor
    , 'expected ' + this.inspect + ' to be an instance of ' + name
    , 'expected ' + this.inspect + ' to not be an instance of ' + name);

  return this;
};

Assertion.prototype.property = function (name) {
  this.assert(
      undefined !== this.obj[name]
    , 'expected ' + this.inspect + ' to have property ' + name
    , 'expected ' + this.inspect + ' to not have property ' + name);

  this.obj = this.obj[name];
  return this;
};

Assertion.prototype.length = function (n) {
  new Assertion(this.obj).to.have.property('length');
  var len = this.obj.length;

  this.assert(
      len == n
    , 'expected ' + this.inspect + ' to be an length of ' + n + ' bug got ' + len
    , 'expected ' + this.inspect + ' to not have a length of ' + len);

  return this;
};

Assertion.prototype.match = function (re) {
  this.assert(
      re.exec(this.obj)
    , 'expected ' + this.inspect + ' to match ' + re
    , 'expected ' + this.inspect + ' to not match ' + re);

  return this;
};

Assertion.prototype.contain = function (obj) {
  new Assertion(this.obj).to.be.an.instanceof(Array);

  this.assert(
      ~this.obj.indexOf(obj)
    , 'expected ' + this.inspect + ' to contain ' + inspect(obj)
    , 'expected ' + this.inspect + ' to not contain ' + inspect(obj));

  return this;
};

Assertion.prototype.string = function (str) {
  new Assertion(this.obj).is.a('string');

  this.assert(
      ~this.obj.indexOf(str)
    , 'expected ' + this.inspect + ' to include ' + str
    , 'expected ' + this.inspect + ' to not include ' + str);

  return this;
};

Assertion.prototype.throw = function (constructor) {
  new Assertion(this.obj).is.a('function');

  constructor = constructor || Error;
  var name = constructor.name
    , thrown = false;

  try {
    this.obj();
  } catch (err) {
    thrown = true;
    this.assert(
        err instanceof constructor
      , 'expected ' + this.inspect + ' to throw ' + name
      , 'expected ' + this.inspect + ' to not throw ' + name);
    return this;
  }

  this.assert(
      thrown === true
    , 'expected ' + this.inspect + ' to throw ' + name
    , 'expected ' + this.inspect + ' to not throw ' + name);
};
}); // module: assertion.js

require.register("chai.js", function(module, exports, require){

var exports = module.exports = {};

exports.version = '0.0.2';

exports.expect = function (val, message) {
  return new exports.Assertion(val, message);
};

exports.assert = require('./interface/assert');

exports.Assertion = require('./assertion');
exports.AssertionError = require('./error');
}); // module: chai.js

require.register("error.js", function(module, exports, require){

module.exports = AssertionError;

function AssertionError (options) {
  options = options || {};
  this.name = 'AssertionError';
  this.message = options.message;
  this.actual = options.actual;
  this.expected = options.expected;
  this.operator = options.operator || options.stackStartFunction.name;
  var stackStartFunction = options.stackStartFunction;

  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, stackStartFunction);
  }
};

AssertionError.prototype.summary = function() {
  return this.name + (this.message ? ': ' + this.message : '');
};

AssertionError.prototype.details = function() {
  return 'In "' + this.operator + '":\n\tExpected: ' + this.expected + '\n\tFound: ' + this.actual;
};

AssertionError.prototype.toString = function() {
  return this.summary();
};

}); // module: error.js

require.register("interface/assert.js", function(module, exports, require){
var Assertion = require('../assertion');

var assert = module.exports = {};

assert.ok = function (val, msg) {
  new Assertion(val, msg).is.ok;
};

assert.equal = function (act, exp, msg) {
  new Assertion(act, msg).to.equal(exp);
};

assert.notEqual = function (act, exp, msg) {
  new Assertion(act, msg).to.not.equal(exp);
};

assert.strictEqual = function (act, exp, msg) {

};

assert.strictNotEqual = function (Act, exp, msg) {

};

assert.deepEqual = function (act, exp, msg) {

};

assert.notDeepEqual = function (act, exp, msg) {

};

assert.isTrue = function (val, msg) {
  new Assertion(val, msg).is.true;
};

assert.isFalse = function (val, msg) {
  new Assertion(val, msg).is.false;
};

assert.isNull = function (val, msg) {
  new Assertion(val, msg).to.not.exist;
};

assert.isNotNull = function (val, msg) {
  new Assertion(val, msg).to.exist;
};

assert.isUndefined = function (val, msg) {
  new Assertion(val, msg).to.equal(undefined);
};

assert.isNan = function (val, msg) {
  new Assertion(val, msg).to.not.equal(val);
};

assert.isFunction = function (val, msg) {
  new Assertion(val, msg).to.be.a('function');
};

assert.isObject = function (val, msg) {
  new Assertion(val, msg).to.be.an('object');
};

assert.isString = function (val, msg) {
  new Assertion(val, msg).to.be.a('string');
};

assert.isArray = function (val, msg) {
  new Assertion(val, msg).to.be.instanceof(Array);
};

assert.isNumber = function (val, msg) {
  new Assertion(val, msg).to.be.instanceof(Number);
};

assert.isBoolean = function (val, msg) {
  new Assertion(val, msg).to.be.a('boolean');
};

assert.typeOf = function (val, type, msg) {
  new Assertion(val, msg).to.be.a(type);
};

assert.instanceOf = function (val, type, msg) {
  new Assertion(val, msg).to.be.instanceof(type);
};

assert.include = function (exp, inc, msg) {
  new Assertion(exp, msg).to.include(inc);
};

assert.match = function (exp, re, msg) {
  new Assertion(exp, msg).to.match(re);
};

assert.length = function (exp, len, msg) {
  new Assertion(exp, msg).length(len);
};

assert.throws = function (fn, type, msg) {
  new Assertions(fn, msg).to.throw(type);
};
}); // module: interface/assert.js
chai = require('chai');

expect = chai.expect;
assert = chai.assert;

<commit_msg>browser build for current api<commit_after>
// CommonJS require()

function require(p){
    var path = require.resolve(p)
      , mod = require.modules[path];
    if (!mod) throw new Error('failed to require "' + p + '"');
    if (!mod.exports) {
      mod.exports = {};
      mod.call(mod.exports, mod, mod.exports, require.relative(path));
    }
    return mod.exports;
  }

require.modules = {};

require.resolve = function (path){
    var orig = path
      , reg = path + '.js'
      , index = path + '/index.js';
    return require.modules[reg] && reg
      || require.modules[index] && index
      || orig;
  };

require.register = function (path, fn){
    require.modules[path] = fn;
  };

require.relative = function (parent) {
    return function(p){
      if ('.' != p[0]) return require(p);

      var path = parent.split('/')
        , segs = p.split('/');
      path.pop();

      for (var i = 0; i < segs.length; i++) {
        var seg = segs[i];
        if ('..' == seg) path.pop();
        else if ('.' != seg) path.push(seg);
      }

      return require(path.join('/'));
    };
  };

require.register("assertion.js", function(module, exports, require){

var AssertionError = require('./error')
  , eql = require('./utils');

module.exports = Assertion;

function inspect (val) {
  return (val ? JSON.stringify(val) : 'null');
}

function Assertion (obj, msg) {
  this.obj = obj;
  this.msg = msg;
}

Assertion.prototype.assert = function (expr, msg, negateMsg) {
  var msg = (this.msg ? this.msg + ': ' : '') + (this.negate ? negateMsg : msg)
    , ok = this.negate ? !expr : expr;

  if (!ok) {
    throw new AssertionError({
      message: msg,
      startStackFunction: this.assert
    });
  }
};

Assertion.prototype.__defineGetter__('inspect', function () {
  return inspect(this.obj);
});

Assertion.prototype.__defineGetter__('to', function () {
  return this;
});

Assertion.prototype.__defineGetter__('be', function () {
  return this;
});

Assertion.prototype.__defineGetter__('an', function () {
  return this;
});

Assertion.prototype.__defineGetter__('is', function () {
  return this;
});

Assertion.prototype.__defineGetter__('and', function () {
  return this;
});

Assertion.prototype.__defineGetter__('have', function () {
  return this;
});

Assertion.prototype.__defineGetter__('include', function () {
  this.include = true;
  return this;
});

Assertion.prototype.__defineGetter__('not', function () {
  this.negate = true;
  return this;
});

Assertion.prototype.__defineGetter__('ok', function () {
  this.assert(
      this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('true', function () {
  this.assert(
      true === this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('false', function () {
  this.assert(
      false === this.obj
    , 'expected ' + this.inspect + ' to be truthy'
    , 'expected ' + this.inspect + ' to be falsey');

  return this;
});

Assertion.prototype.__defineGetter__('exist', function () {
  this.assert(
      null != this.obj
    , 'expected ' + this.inspect + ' to exist'
    , 'expected ' + this.inspect + ' to not exist');

  return this;
});

Assertion.prototype.__defineGetter__('empty', function () {
  new Assertion(this.obj).to.have.property('length');

  this.assert(
      0 === this.obj.length
    , 'expected ' + this.inspect + ' to exist'
    , 'expected ' + this.inspect + ' to not exist');

  return this;
});

Assertion.prototype.equal = function (val) {
  this.assert(
      val === this.obj
    , 'expected ' + this.inspect + ' to equal ' + inspect(val)
    , 'expected ' + this.inspect + ' to not equal ' + inspect(val));

  return this;
};

Assertion.prototype.eql = function (obj) {
  this.assert(
      eql(obj, this.obj)
    , 'expected ' + this.inspect + ' to be deeply equal ' + inspect(obj)
    , 'expected ' + this.inspect + ' to be below' + inspect(obj));
  return this;
};

Assertion.prototype.above = function (val) {
  this.assert(
      this.obj > val
    , 'expected ' + this.inspect + ' to be above ' + val
    , 'expected ' + this.inspect + ' to be below' + val);

  return this;
};

Assertion.prototype.below = function (val) {
  this.assert(
      this.obj < val
    , 'expected ' + this.inspect + ' to be below ' + val
    , 'expected ' + this.inspect + ' to be above ' + val);

  return this;
};

Assertion.prototype.a = function (type) {
  this.assert(
      type == typeof this.obj
    , 'expected ' + this.inspect + ' to be a ' + type
    , 'expected ' + this.inspect + ' to not be a ' + type);

  return this;
};

Assertion.prototype.instanceof = function (constructor) {
  var name = constructor.name;
  this.assert(
      this.obj instanceof constructor
    , 'expected ' + this.inspect + ' to be an instance of ' + name
    , 'expected ' + this.inspect + ' to not be an instance of ' + name);

  return this;
};

Assertion.prototype.property = function (name, val) {
  if (val) {
    this.assert(
        val === this.obj[name]
      , 'expected ' + this.inspect + ' to have property ' + name + ' with value ' + inspect(val)
      , 'expected ' + this.inspect + ' to not have property ' + name + ' with value ' +  inspect(val));
  } else {
    this.assert(
        undefined !== this.obj[name]
      , 'expected ' + this.inspect + ' to have property ' + name
      , 'expected ' + this.inspect + ' to not have property ' + name);
  }

  this.obj = this.obj[name];
  return this;
};

Assertion.prototype.length = function (n) {
  new Assertion(this.obj).to.have.property('length');
  var len = this.obj.length;

  this.assert(
      len == n
    , 'expected ' + this.inspect + ' to be an length of ' + n + ' bug got ' + len
    , 'expected ' + this.inspect + ' to not have a length of ' + len);

  return this;
};

Assertion.prototype.match = function (re) {
  this.assert(
      re.exec(this.obj)
    , 'expected ' + this.inspect + ' to match ' + re
    , 'expected ' + this.inspect + ' to not match ' + re);

  return this;
};

Assertion.prototype.contain = function (obj) {
  new Assertion(this.obj).to.be.an.instanceof(Array);

  this.assert(
      ~this.obj.indexOf(obj)
    , 'expected ' + this.inspect + ' to contain ' + inspect(obj)
    , 'expected ' + this.inspect + ' to not contain ' + inspect(obj));

  return this;
};

Assertion.prototype.string = function (str) {
  new Assertion(this.obj).is.a('string');

  this.assert(
      ~this.obj.indexOf(str)
    , 'expected ' + this.inspect + ' to include ' + str
    , 'expected ' + this.inspect + ' to not include ' + str);

  return this;
};

Assertion.prototype.throw = function (constructor) {
  new Assertion(this.obj).is.a('function');

  constructor = constructor || Error;
  var name = constructor.name
    , thrown = false;

  try {
    this.obj();
  } catch (err) {
    thrown = true;
    this.assert(
        err instanceof constructor
      , 'expected ' + this.inspect + ' to throw ' + name
      , 'expected ' + this.inspect + ' to not throw ' + name);
    return this;
  }

  this.assert(
      thrown === true
    , 'expected ' + this.inspect + ' to throw ' + name
    , 'expected ' + this.inspect + ' to not throw ' + name);
};
}); // module: assertion.js

require.register("chai.js", function(module, exports, require){

var exports = module.exports = {};

exports.version = '0.0.2';

exports.expect = function (val, message) {
  return new exports.Assertion(val, message);
};

exports.assert = require('./interface/assert');

exports.Assertion = require('./assertion');
exports.AssertionError = require('./error');
}); // module: chai.js

require.register("error.js", function(module, exports, require){

module.exports = AssertionError;

function AssertionError (options) {
  options = options || {};
  this.name = 'AssertionError';
  this.message = options.message;
  this.actual = options.actual;
  this.expected = options.expected;
  this.operator = options.operator || options.stackStartFunction.name;
  var stackStartFunction = options.stackStartFunction;

  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, stackStartFunction);
  }
};

AssertionError.prototype.summary = function() {
  return this.name + (this.message ? ': ' + this.message : '');
};

AssertionError.prototype.details = function() {
  return 'In "' + this.operator + '":\n\tExpected: ' + this.expected + '\n\tFound: ' + this.actual;
};

AssertionError.prototype.toString = function() {
  return this.summary();
};

}); // module: error.js

require.register("interface/assert.js", function(module, exports, require){
var Assertion = require('../assertion');

var assert = module.exports = {};

assert.ok = function (val, msg) {
  new Assertion(val, msg).is.ok;
};

assert.equal = function (act, exp, msg) {
  new Assertion(act, msg).to.equal(exp);
};

assert.notEqual = function (act, exp, msg) {
  new Assertion(act, msg).to.not.equal(exp);
};

assert.strictEqual = function (act, exp, msg) {

};

assert.strictNotEqual = function (Act, exp, msg) {

};

assert.deepEqual = function (act, exp, msg) {

};

assert.notDeepEqual = function (act, exp, msg) {

};

assert.isTrue = function (val, msg) {
  new Assertion(val, msg).is.true;
};

assert.isFalse = function (val, msg) {
  new Assertion(val, msg).is.false;
};

assert.isNull = function (val, msg) {
  new Assertion(val, msg).to.not.exist;
};

assert.isNotNull = function (val, msg) {
  new Assertion(val, msg).to.exist;
};

assert.isUndefined = function (val, msg) {
  new Assertion(val, msg).to.equal(undefined);
};

assert.isNan = function (val, msg) {
  new Assertion(val, msg).to.not.equal(val);
};

assert.isFunction = function (val, msg) {
  new Assertion(val, msg).to.be.a('function');
};

assert.isObject = function (val, msg) {
  new Assertion(val, msg).to.be.an('object');
};

assert.isString = function (val, msg) {
  new Assertion(val, msg).to.be.a('string');
};

assert.isArray = function (val, msg) {
  new Assertion(val, msg).to.be.instanceof(Array);
};

assert.isNumber = function (val, msg) {
  new Assertion(val, msg).to.be.instanceof(Number);
};

assert.isBoolean = function (val, msg) {
  new Assertion(val, msg).to.be.a('boolean');
};

assert.typeOf = function (val, type, msg) {
  new Assertion(val, msg).to.be.a(type);
};

assert.instanceOf = function (val, type, msg) {
  new Assertion(val, msg).to.be.instanceof(type);
};

assert.include = function (exp, inc, msg) {
  new Assertion(exp, msg).to.include(inc);
};

assert.match = function (exp, re, msg) {
  new Assertion(exp, msg).to.match(re);
};

assert.length = function (exp, len, msg) {
  new Assertion(exp, msg).length(len);
};

assert.throws = function (fn, type, msg) {
  new Assertions(fn, msg).to.throw(type);
};
}); // module: interface/assert.js

require.register("utils.js", function(module, exports, require){
// Most of this is directly from
// https://github.com/joyent/node/blob/master/lib/assert.js

module.exports = _deepEqual;

// For browser implementation
if (!Buffer) {
  var Buffer = {
    isBuffer: function () {
      return false;
    }
  };
}
function _deepEqual(actual, expected) {
  // 7.1. All identical values are equivalent, as determined by ===.
  if (actual === expected) {
    return true;

  } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) {
    if (actual.length != expected.length) return false;

    for (var i = 0; i < actual.length; i++) {
      if (actual[i] !== expected[i]) return false;
    }

    return true;

  // 7.2. If the expected value is a Date object, the actual value is
  // equivalent if it is also a Date object that refers to the same time.
  } else if (actual instanceof Date && expected instanceof Date) {
    return actual.getTime() === expected.getTime();

  // 7.3. Other pairs that do not both pass typeof value == 'object',
  // equivalence is determined by ==.
  } else if (typeof actual != 'object' && typeof expected != 'object') {
    return actual == expected;

  // 7.4. For all other Object pairs, including Array objects, equivalence is
  // determined by having the same number of owned properties (as verified
  // with Object.prototype.hasOwnProperty.call), the same set of keys
  // (although not necessarily the same order), equivalent values for every
  // corresponding key, and an identical 'prototype' property. Note: this
  // accounts for both named and indexed properties on Arrays.
  } else {
    return objEquiv(actual, expected);
  }
}

function isUndefinedOrNull(value) {
  return value === null || value === undefined;
}

function isArguments(object) {
  return Object.prototype.toString.call(object) == '[object Arguments]';
}

function objEquiv(a, b) {
  if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
    return false;
  // an identical 'prototype' property.
  if (a.prototype !== b.prototype) return false;
  //~~~I've managed to break Object.keys through screwy arguments passing.
  //   Converting to array solves the problem.
  if (isArguments(a)) {
    if (!isArguments(b)) {
      return false;
    }
    a = pSlice.call(a);
    b = pSlice.call(b);
    return _deepEqual(a, b);
  }
  try {
    var ka = Object.keys(a),
        kb = Object.keys(b),
        key, i;
  } catch (e) {//happens when one is a string literal and the other isn't
    return false;
  }
  // having the same number of owned properties (keys incorporates
  // hasOwnProperty)
  if (ka.length != kb.length)
    return false;
  //the same set of keys (although not necessarily the same order),
  ka.sort();
  kb.sort();
  //~~~cheap key test
  for (i = ka.length - 1; i >= 0; i--) {
    if (ka[i] != kb[i])
      return false;
  }
  //equivalent values for every corresponding key, and
  //~~~possibly expensive deep test
  for (i = ka.length - 1; i >= 0; i--) {
    key = ka[i];
    if (!_deepEqual(a[key], b[key])) return false;
  }
  return true;
}
}); // module: utils.js
chai = require('chai');

expect = chai.expect;
assert = chai.assert;

<|endoftext|>


<commit_before>import { inspect } from 'util'
import { fetchJSON } from './util/api'
import { debug } from './util/logging'
import { blue } from 'chalk'
import { find, forEach, values, get, has, omit } from 'lodash'
import { _PENDING, SET_STATE, addDataToStore } from './actions'

// TODO cache expiration
export function cacheMiddleware (store) {
  return next => action => {
    if (action.type.endsWith(_PENDING)) return next(action)

    let { cache } = action.meta || {}
    let { bucket, id, match, array, limit, offset, requiredProp, refresh } = cache || {}
    if (!bucket) return next(action)
    let state = store.getState()
    if (!state[bucket]) return next(action)

    let hit = refresh
      ? null
      : (match
        ? find(values(state[bucket]), match)
        : (id
          ? state[bucket][id]
          : state[bucket]))

    if (array) {
      if (hit && hit.length > offset) {
        debug(`cache hit: ${bucket}[${id}][${offset}] + ${limit}`)
        return Promise.resolve({...action, payload: hit, cacheHit: true})
      }
    } else {
      if (hit && !requiredProp || has(hit, requiredProp)) {
        debug(`cache hit: ${bucket}[${id}]`)
        return Promise.resolve({...action, payload: hit, cacheHit: true})
      }
    }

    return next(action)
  }
}

export const addDataToStoreMiddleware = store => next => action => {
  const { type, payload, meta } = action
  if (type.endsWith(_PENDING)) return next(action)

  if (meta && meta.addDataToStore) {
    if (isPromise(payload)) {
      const promise = payload.then(data => {
        forEach(meta.addDataToStore, (fn, bucket) =>
          store.dispatch(addDataToStore(bucket, fn(data))))
        return data
      })
      return next({...action, payload: promise})
    }

    forEach(meta.addDataToStore, (fn, bucket) =>
      store.dispatch(addDataToStore(bucket, fn(payload))))
  }

  return next(action)
}

export function apiMiddleware (req) {
  return store => next => action => {
    const { payload, meta } = action
    if (!payload || !payload.api) return next(action)

    const { path, params, method } = payload
    const cookie = req && req.headers.cookie
    let promise = fetchJSON(path, params, {method, cookie})

    if (meta && meta.then) {
      promise = promise.then(meta.then)
    }

    return next({...action, payload: promise})
  }
}

export function serverLogger (store) {
  return next => action => {
    let { payload } = action

    if (!payload || !payload.api) {
      debug(blue('action:'), inspect(omit(action, 'payload')))
    } else {
      debug(blue('action:'), inspect({api: true, ...omit(action, 'payload')}))
    }

    return next(action)
  }
}

function isPromise (value) {
  return value && typeof value.then === 'function'
}

export function pendingPromiseMiddleware (store) {
  return next => action => {
    let { type, payload } = action
    if (isPromise(payload)) {
      store.dispatch({...action, type: type + _PENDING, payload: null})
    }
    return next(action)
  }
}

export function optimisticMiddleware (store) {
  return next => action => {
    let { payload, meta } = action
    if (get(meta, 'optimistic') && isPromise(payload)) {
      const prevState = store.getState()
      action.payload = action.payload.then(
        result => result,
        error => {
          store.dispatch({type: SET_STATE, payload: prevState})
          throw error
        }
      )
    }
    return next(action)
  }
}
<commit_msg>don't run addDataToStoreMiddleware twice<commit_after>import { inspect } from 'util'
import { fetchJSON } from './util/api'
import { debug } from './util/logging'
import { blue } from 'chalk'
import { find, forEach, values, get, has, omit } from 'lodash'
import { _PENDING, SET_STATE, addDataToStore } from './actions'

// TODO cache expiration
export function cacheMiddleware (store) {
  return next => action => {
    if (action.type.endsWith(_PENDING)) return next(action)

    let { cache } = action.meta || {}
    let { bucket, id, match, array, limit, offset, requiredProp, refresh } = cache || {}
    if (!bucket) return next(action)
    let state = store.getState()
    if (!state[bucket]) return next(action)

    let hit = refresh
      ? null
      : (match
        ? find(values(state[bucket]), match)
        : (id
          ? state[bucket][id]
          : state[bucket]))

    if (array) {
      if (hit && hit.length > offset) {
        debug(`cache hit: ${bucket}[${id}][${offset}] + ${limit}`)
        return Promise.resolve({...action, payload: hit, cacheHit: true})
      }
    } else {
      if (hit && !requiredProp || has(hit, requiredProp)) {
        debug(`cache hit: ${bucket}[${id}]`)
        return Promise.resolve({...action, payload: hit, cacheHit: true})
      }
    }

    return next(action)
  }
}

export const addDataToStoreMiddleware = store => next => action => {
  const { type, payload, meta } = action
  if (type.endsWith(_PENDING) || isPromise(payload)) return next(action)

  if (meta && meta.addDataToStore) {
    forEach(meta.addDataToStore, (fn, bucket) =>
      store.dispatch(addDataToStore(bucket, fn(payload), type)))
  }

  return next(action)
}

export function apiMiddleware (req) {
  return store => next => action => {
    const { payload, meta } = action
    if (!payload || !payload.api) return next(action)

    const { path, params, method } = payload
    const cookie = req && req.headers.cookie
    let promise = fetchJSON(path, params, {method, cookie})

    if (meta && meta.then) {
      promise = promise.then(meta.then)
    }

    return next({...action, payload: promise})
  }
}

export function serverLogger (store) {
  return next => action => {
    let { payload } = action

    if (!payload || !payload.api) {
      debug(blue('action:'), inspect(omit(action, 'payload')))
    } else {
      debug(blue('action:'), inspect({api: true, ...omit(action, 'payload')}))
    }

    return next(action)
  }
}

function isPromise (value) {
  return value && typeof value.then === 'function'
}

export function pendingPromiseMiddleware (store) {
  return next => action => {
    let { type, payload } = action
    if (isPromise(payload)) {
      store.dispatch({...action, type: type + _PENDING, payload: null})
    }
    return next(action)
  }
}

export function optimisticMiddleware (store) {
  return next => action => {
    let { payload, meta } = action
    if (get(meta, 'optimistic') && isPromise(payload)) {
      const prevState = store.getState()
      action.payload = action.payload.then(
        result => result,
        error => {
          store.dispatch({type: SET_STATE, payload: prevState})
          throw error
        }
      )
    }
    return next(action)
  }
}
<|endoftext|>


<commit_before>var mongoose  = require('mongoose')
  , elastical = require('elastical')
  , esClient  = new(require('elastical').Client)
  , should    = require('should')
  , config    = require('./config')
  , Schema    = mongoose.Schema
  , ObjectId  = Schema.ObjectId
  , async     = require('async')
  , mongoosastic = require('../lib/mongoosastic');

var BookSchema = new Schema({
  title: String
});
BookSchema.plugin(mongoosastic);

var Book = mongoose.model('Book', BookSchema);

describe('Synchronize', function(){
  var books = null;

  before(function(done){
    config.deleteIndexIfExists(['books'], function(){
      mongoose.connect(config.mongoUrl, function(){
        var client = mongoose.connections[0].db;
        client.collection('books', function(err, _books){
          books = _books;
          Book.remove(done);
        });
      });
    });
  });
  describe('existing collection', function(){
    before(function(done){
      async.forEach(bookTitles()
          , function(title, cb){
        books.insert({title:title}, cb);
      }, done);
    });
    it('should index all existing objects', function(done){
      var stream = Book.synchronize()
        , count = 0;

      stream.on('data', function(err, doc){
        count++;
      });

      stream.on('close', function(){
        count.should.eql(53);
        setTimeout(function(){
          Book.search({query:'American'}, function(err, results){
            results.hits.total.should.eql(2);
            done();
          });
        }, 1100);
      });
    });
  });
});
function bookTitles(){
  var books = [
    'American Gods',
    'Gods of the Old World',
    'American Gothic'
  ];
  for(var i = 0; i < 50; i++){
    books.push('ABABABA'+i);
  }
  return books;
}
<commit_msg>Fix test for synchronize<commit_after>var mongoose  = require('mongoose')
  , elastical = require('elastical')
  , esClient  = new(require('elastical').Client)
  , should    = require('should')
  , config    = require('./config')
  , Schema    = mongoose.Schema
  , ObjectId  = Schema.ObjectId
  , async     = require('async')
  , mongoosastic = require('../lib/mongoosastic');

var BookSchema = new Schema({
  title: String
});
BookSchema.plugin(mongoosastic);

var Book = mongoose.model('Book', BookSchema);

describe('Synchronize', function(){
  var books = null;

  before(function(done){
    config.deleteIndexIfExists(['books'], function(){
      mongoose.connect(config.mongoUrl, function(){
        var client = mongoose.connections[0].db;
        client.collection('books', function(err, _books){
          books = _books;
          Book.remove(done);
        });
      });
    });
  });
  describe('existing collection', function(){
    before(function(done){
      async.forEach(bookTitles()
          , function(title, cb){
        books.insert({title:title}, cb);
      }, done);
    });
    it('should index all existing objects', function(done){
      var stream = Book.synchronize()
        , count = 0;

      stream.on('data', function(err, doc){
        count++;
      });

      stream.on('close', function(){
        setTimeout(function(){
          count.should.eql(53);
          Book.search({query:'American'}, function(err, results){
            results.hits.total.should.eql(2);
            done();
          });
        }, 1100);
      });
    });
  });
});
function bookTitles(){
  var books = [
    'American Gods',
    'Gods of the Old World',
    'American Gothic'
  ];
  for(var i = 0; i < 50; i++){
    books.push('ABABABA'+i);
  }
  return books;
}
<|endoftext|>


<commit_before>'use strict';

var assert = require('chai').assert,
    ST = require('../subtask.js');

describe('predefined asynchronize subtask', function () {
    var timeTask = function (start, end) {
            return ST({
                start: start,
                end: end,
                valid: validateTask(start, end)
            });
        },

        validateTask = function (start, end) {
            return ST(function (cb) {
                setTimeout(function () {
                    cb(start < end);
                }, 10);
            });
        };

    it('should return a subtask', function (done) {
        assert.equal('function', (typeof timeTask(0, 1).execute));
        done();
    });

    it('should executed correct', function (done) {
        timeTask(0, 1).execute(function (D) {
            assert.deepEqual({
                start: 0,
                end: 1,
                valid: true
            }, D);
            done();
        });
    });

    it('should executed correct with different input', function (done) {
        timeTask(3, 2).execute(function (D) {
            assert.deepEqual({
                start: 3,
                end: 2,
                valid: false
            }, D);
            done();
        });
    });

    it('should cached naturally', function (done) {
        timeTask(3, 2).execute().execute(function (D) {
            // this increase coverage
            done();
        });
    });

    it('should .execute() by order', function (done) {
        var exec = 0;

        timeTask(3, 2).execute(function () {
            exec++;
            assert.equal(1, exec);
        }).execute(function () {
            exec++;
            assert.equal(2, exec);
        }).execute(function () {
            exec++;
            assert.equal(3, exec);
            done();
        });
    });
});
<commit_msg>fix test for async task<commit_after>'use strict';

var assert = require('chai').assert,
    ST = require('../subtask.js');

describe('predefined asynchronize subtask', function () {
    var timeTask = function (start, end) {
            return ST({
                start: start,
                end: end,
                valid: validateTask(start, end)
            });
        },

        validateTask = function (start, end) {
            return ST(function (cb) {
                setTimeout(function () {
                    cb(start < end);
                }, 10);
            });
        };

    it('should return a subtask', function (done) {
        assert.equal('function', (typeof timeTask(0, 1).then));
        done();
    });

    it('should be correct', function (done) {
        timeTask(0, 1).then(function (D) {
            assert.deepEqual({
                start: 0,
                end: 1,
                valid: true
            }, D);
            done();
        });
    });

    it('should then correct with different input', function (done) {
        timeTask(3, 2).then(function (D) {
            assert.deepEqual({
                start: 3,
                end: 2,
                valid: false
            }, D);
            done();
        });
    });

    it('should be cached naturally', function (done) {
        var T = timeTask(3, 2);

        T.then();
        T.then(function (D) {
            // this increase coverage
            done();
        });
    });

    it('should .then() by order', function (done) {
        var exec = 0,
            T = timeTask(3, 2);

        T.then(function () {
            exec++;
            assert.equal(1, exec);
        }).then(function () {
            exec++;
            assert.equal(2, exec);
        }).then(function () {
            exec++;
            assert.equal(3, exec);
            done();
        });
    });
});
<|endoftext|>


<commit_before>var request = require('supertest'),
    express = require('express'),
    log4js = require('log4js'),
    should = require('chai').should();

describe('routes', function(){
    var routes, app;

    log4js.configure({
        appenders: [
            { type: 'console',
              category: 'test'
            }
        ]
    });

    var logger = log4js.getLogger('test'),
        Mail;
    logger.setLevel('ERROR');

    beforeEach(function() {
        app = express();
        routes = require('../../routes/routes')(app, logger);
    });

    describe('GET /headers', function() {

        it('should respond with JSON', function(done) {
            request(app)
                .get('/headers/1/1')
                .set('Accept', 'application/json')
                .expect('Content-Type', /json/)
                .expect(200, done);
        });

        it('should handle wrong parameters', function(done) {
            request(app)
                .get('/headers/0/1')
                .expect(500, done);
        });
    });
});<commit_msg>Added test case for routes<commit_after>var request = require('supertest'),
    express = require('express'),
    log4js = require('log4js');

describe('routes', function(){
    var routes, app;

    log4js.configure({
        appenders: [
            { type: 'console',
              category: 'test'
            }
        ]
    });

    var logger = log4js.getLogger('test'),
        Mail;
    logger.setLevel('ERROR');

    beforeEach(function() {
        app = express();
        app.configure(function() {
            app.use(express.static(__dirname + '/../../app'));
        });
        routes = require('../../routes/routes')(app, logger);
    });

    describe('GET /', function() {

        it('should respond with index.html', function(done) {
            request(app)
                .get('/')
                .expect('Content-Type', /html/)
                .expect(200, done);
        });
    });

    describe('GET /headers', function() {

        it('should respond with JSON', function(done) {
            request(app)
                .get('/headers/1/1')
                .set('Accept', 'application/json')
                .expect('Content-Type', /json/)
                .expect(200, done);
        });

        it('should handle wrong parameters', function(done) {
            request(app)
                .get('/headers/0/1')
                .expect(500, done);
        });
    });
});<|endoftext|>


<commit_before>import pg from 'pg';
import SQL from 'sql-template-strings';

const config = {
  max: 10, // max number of clients in the pool
  idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
};
const pool = new pg.Pool(config);
pool.on('error', err =>
  console.error('idle client error', err.message, err.stack),
);

class Images {
  constructor(boardgameID) {
    this.boardgameID = boardgameID;
  }
  get() {
    if (this.result) {
      return this.result;
    }
    const query = SQL`SELECT id, uri, type FROM image WHERE boardgame_id=${this.boardgameID}`;
    this.result = pool.query(query).then(result => result.rows);
    return this.result;
  }
  getByType(type) {
    return this.get().then(imgs => imgs.filter(img => img.type === type));
  }
}

function parseIntRange(rangeString) {
  // slice to remove brackets
  const array = rangeString.slice(1, rangeString.length - 1).split(',');
  return { from: array[0] || null, to: array[1] || null };
}

function getInstructions(boardgameID) {
  const query = SQL`
    SELECT i.id, i.text_uri, v.id video_id, v.uri video_uri FROM instruction i
    LEFT OUTER JOIN video v ON (i.video_id = v.id)
    WHERE i.boardgame_id=${boardgameID}`;
  return pool.query(query).then((result) => {
    const instructions = [];
    for (let i = 0; i < result.rows.length; i++) {
      const instruction = Object.assign({}, result.rows[i]);
      if (instruction.video_id) {
        instruction.video = { id: instruction.video_id, uri: instruction.video_uri };
      }
      instructions.push(instruction);
    }
    return instructions;
  });
}

function getVideo(videoID) {
  const query = SQL`SELECT id, uri FROM video WHERE id=${videoID}`;
  return pool.query(query).then(result => result.rows[0]);
}

function boardgamesResolver(publisherID, designerID) {
  return (args) => {
    const fragments = [];
    const query = SQL`SELECT * FROM boardgame`;
    if (publisherID) {
      fragments.push(SQL`publisher_id=${publisherID}`);
    }
    if (designerID) {
      fragments.push(SQL`designer_id=${designerID}`);
    }
    if (args.search) {
      const search = `%${args.search}%`;
      fragments.push(SQL`name ILIKE ${search}`);
    }
    if (args.ids) {
      fragments.push(SQL`id = ANY(${args.ids}::int[])`);
    }

    if (fragments.length > 0) {
      query.append(SQL` WHERE `);
      fragments.forEach((val, idx) => {
        if (idx > 0) {
          query.append(SQL` AND `);
        }
        query.append(val);
      });
    }
    return pool.query(query).then((result) => {
      const boardgames = [];
      for (let i = 0; i < result.rows.length; i++) {
        const boardgame = Object.assign({}, result.rows[i]);
        const images = new Images(boardgame.id);
        boardgame.photos = images.getByType('photo');
        boardgame.cover_image = images.getByType('cover').then(imgs => imgs[0]);
        boardgame.box_image = images.getByType('box').then(imgs => imgs[0]);
        boardgame.table_image = images.getByType('table').then(imgs => imgs[0]);
        boardgame.age_restriction = parseIntRange(boardgame.age_restriction);
        boardgame.players_number = parseIntRange(boardgame.players_number);
        boardgame.playing_time = parseIntRange(boardgame.playing_time);
        boardgame.bgg_rating = boardgame.bgg_rating || '';
        boardgame.instructions = () => getInstructions(boardgame.id);
        if (boardgame.review_video_id) {
          boardgame.review_video = () => getVideo(boardgame.review_video_id);
        }
        if (boardgame.publisher_id) {
          // TODO: Below is causing N+1 queries.
          // Optimize by passing all board game ids.
          // Make the first resolve evalute it lazily.
          boardgame.publisher = () => publishersResolver(boardgame.publisher_id)().then(
            publishers => publishers[0]);
        }
        if (boardgame.designer_id) {
          // TODO: ditto
          boardgame.designer = () => designersResolver(boardgame.designer_id)().then(
            designers => designers[0]);
        }
        boardgames.push(boardgame);
      }
      return boardgames;
    });
  };
}

function designersResolver(designerID) {
  const query = SQL`SELECT id, name, website_uri FROM designer`;
  if (designerID) {
    query.append(SQL` WHERE id=${designerID}`);
  }
  return () => pool.query(query).then((result) => {
    const designers = [];
    for (let i = 0; i < result.rows.length; i++) {
      const designer = Object.assign({}, result.rows[i]);
      // TODO: Below is causing N+1 queries.
      // Optimize by passing all designer ids.
      // Make the first resolve evalute it lazily.
      designer.boardgames = boardgamesResolver(null, designer.id);
      designers.push(designer);
    }
    return designers;
  });
}

function publishersResolver(publisherID) {
  const query = SQL`SELECT id, name, website_uri FROM publisher`;
  if (publisherID) {
    query.append(SQL` WHERE id=${publisherID}`);
  }
  return () => pool.query(query).then((result) => {
    const publishers = [];
    for (let i = 0; i < result.rows.length; i++) {
      const publisher = Object.assign({}, result.rows[i]);
      // TODO: See designersResolver
      publisher.boardgames = boardgamesResolver(publisher.id, null);
      publishers.push(publisher);
    }
    return publishers;
  });
}

const root = {
  boardgames: boardgamesResolver(null, null),
  publishers: publishersResolver(null),
  designers: designersResolver(null),
};

export default root;
<commit_msg>don't use SELECT *<commit_after>import pg from 'pg';
import SQL from 'sql-template-strings';

const config = {
  max: 10, // max number of clients in the pool
  idleTimeoutMillis: 30000, // how long a client is allowed to remain idle before being closed
};
const pool = new pg.Pool(config);
pool.on('error', err =>
  console.error('idle client error', err.message, err.stack),
);

class Images {
  constructor(boardgameID) {
    this.boardgameID = boardgameID;
  }
  get() {
    if (this.result) {
      return this.result;
    }
    const query = SQL`SELECT id, uri, type FROM image WHERE boardgame_id=${this.boardgameID}`;
    this.result = pool.query(query).then(result => result.rows);
    return this.result;
  }
  getByType(type) {
    return this.get().then(imgs => imgs.filter(img => img.type === type));
  }
}

function parseIntRange(rangeString) {
  // slice to remove brackets
  const array = rangeString.slice(1, rangeString.length - 1).split(',');
  return { from: array[0] || null, to: array[1] || null };
}

function getInstructions(boardgameID) {
  const query = SQL`
    SELECT i.id, i.text_uri, v.id video_id, v.uri video_uri FROM instruction i
    LEFT OUTER JOIN video v ON (i.video_id = v.id)
    WHERE i.boardgame_id=${boardgameID}`;
  return pool.query(query).then((result) => {
    const instructions = [];
    for (let i = 0; i < result.rows.length; i++) {
      const instruction = Object.assign({}, result.rows[i]);
      if (instruction.video_id) {
        instruction.video = { id: instruction.video_id, uri: instruction.video_uri };
      }
      instructions.push(instruction);
    }
    return instructions;
  });
}

function getVideo(videoID) {
  const query = SQL`SELECT id, uri FROM video WHERE id=${videoID}`;
  return pool.query(query).then(result => result.rows[0]);
}

function boardgamesResolver(publisherID, designerID) {
  return (args) => {
    const fragments = [];
    const query = SQL`
      SELECT
        id, name, slug, subtitle, description, review_video_id, age_restriction,
        players_number, playing_time, publisher_id, designer_id, difficulty, randomness,
        popularity, bgg_rating
      FROM boardgame`;
    if (publisherID) {
      fragments.push(SQL`publisher_id=${publisherID}`);
    }
    if (designerID) {
      fragments.push(SQL`designer_id=${designerID}`);
    }
    if (args.search) {
      const search = `%${args.search}%`;
      fragments.push(SQL`name ILIKE ${search}`);
    }
    if (args.ids) {
      fragments.push(SQL`id = ANY(${args.ids}::int[])`);
    }

    if (fragments.length > 0) {
      query.append(SQL` WHERE `);
      fragments.forEach((val, idx) => {
        if (idx > 0) {
          query.append(SQL` AND `);
        }
        query.append(val);
      });
    }
    return pool.query(query).then((result) => {
      const boardgames = [];
      for (let i = 0; i < result.rows.length; i++) {
        const boardgame = Object.assign({}, result.rows[i]);
        const images = new Images(boardgame.id);
        boardgame.photos = images.getByType('photo');
        boardgame.cover_image = images.getByType('cover').then(imgs => imgs[0]);
        boardgame.box_image = images.getByType('box').then(imgs => imgs[0]);
        boardgame.table_image = images.getByType('table').then(imgs => imgs[0]);
        boardgame.age_restriction = parseIntRange(boardgame.age_restriction);
        boardgame.players_number = parseIntRange(boardgame.players_number);
        boardgame.playing_time = parseIntRange(boardgame.playing_time);
        boardgame.bgg_rating = boardgame.bgg_rating || '';
        boardgame.instructions = () => getInstructions(boardgame.id);
        if (boardgame.review_video_id) {
          boardgame.review_video = () => getVideo(boardgame.review_video_id);
        }
        if (boardgame.publisher_id) {
          // TODO: Below is causing N+1 queries.
          // Optimize by passing all board game ids.
          // Make the first resolve evalute it lazily.
          boardgame.publisher = () => publishersResolver(boardgame.publisher_id)().then(
            publishers => publishers[0]);
        }
        if (boardgame.designer_id) {
          // TODO: ditto
          boardgame.designer = () => designersResolver(boardgame.designer_id)().then(
            designers => designers[0]);
        }
        boardgames.push(boardgame);
      }
      return boardgames;
    });
  };
}

function designersResolver(designerID) {
  const query = SQL`SELECT id, name, website_uri FROM designer`;
  if (designerID) {
    query.append(SQL` WHERE id=${designerID}`);
  }
  return () => pool.query(query).then((result) => {
    const designers = [];
    for (let i = 0; i < result.rows.length; i++) {
      const designer = Object.assign({}, result.rows[i]);
      // TODO: Below is causing N+1 queries.
      // Optimize by passing all designer ids.
      // Make the first resolve evalute it lazily.
      designer.boardgames = boardgamesResolver(null, designer.id);
      designers.push(designer);
    }
    return designers;
  });
}

function publishersResolver(publisherID) {
  const query = SQL`SELECT id, name, website_uri FROM publisher`;
  if (publisherID) {
    query.append(SQL` WHERE id=${publisherID}`);
  }
  return () => pool.query(query).then((result) => {
    const publishers = [];
    for (let i = 0; i < result.rows.length; i++) {
      const publisher = Object.assign({}, result.rows[i]);
      // TODO: See designersResolver
      publisher.boardgames = boardgamesResolver(publisher.id, null);
      publishers.push(publisher);
    }
    return publishers;
  });
}

const root = {
  boardgames: boardgamesResolver(null, null),
  publishers: publishersResolver(null),
  designers: designersResolver(null),
};

export default root;
<|endoftext|>


<commit_before>// Implementation of the Greiner-Hormann polygon clipping algorithm
//

var segseg = require('segseg');
var preprocessPolygon = require("point-in-big-polygon")

function Node(vec, alpha, intersection) {
  this.vec = vec;
  this.alpha = alpha || 0;
  this.intersect = !!intersection;
}

Node.prototype = {
  vec: null,
  next: null,
  next: null,
  prev: null,
  nextPoly: null,
  neighbor: null,
  intersect: null,
  entry: null,
  visited : false,
  alpha : 0,

  nextNonIntersection : function nodeNextNonIntersection() {
    var a = this;
    while(a && a.intersect) {
      a = a.next;
    }
    return a;
  },

  last : function nodeLast() {
    var a = this;
    while (a.next && a.next !== this) {
      a = a.next;
    }
    return a;
  },

  createLoop : function nodeCreateLoop() {
    var last = this.last();
    last.prev.next = this;
    this.prev = last.prev;
  },

  firstNodeOfInterest : function nodeFirstNodeOfInterest() {
    var a = this;

    if (a) {
      do {
        a=a.next;
      } while(a!==this && (!a.intersect || a.intersect && a.visited));
    }

    return a;
  },

  insertBetween : function nodeInsertBetween(first, last) {
    var a = first;
    while(a !== last && a.alpha < this.alpha) {
      a = a.next;
    }

    this.next = a;
    this.prev = a.prev;
    if (this.prev) {
      this.prev.next = this;
    }

    this.next.prev = this;
  }
};

function createLinkedList(vecs) {
  var l = vecs.length;
  var ret, where;
  for (var i=0; i<l; i++) {
    var current = vecs[i];
    if (!ret) {
      where = ret = new Node(current);
    } else {
      where.next = new Node(current);
      where.next.prev = where;
      where = where.next;
    }
  }

  return ret;
}

function distance(v1, v2) {
  var x = v1[0] - v2[0];
  var y = v1[1] - v2[1];
  return Math.sqrt(x*x + y*y);
}

function dedupe(array) {
  var seen = {};
  return array.filter(function trackSeen(vec) {
    var key = vec.toString();
    if (seen[key]) {
      return false;
    }
    seen[key] = true;
    return true;
  });
}

function identifyIntersections(subjectList, clipList) {
  var subject, clip;
  var auxs = subjectList.last();
  auxs.next = new Node(subjectList.vec, auxs);
  auxs.next.prev = auxs;

  var auxc = clipList.last();
  auxc.next = new Node(clipList.vec, auxc);
  auxc.next.prev = auxc;

  for(subject = subjectList; subject.next; subject = subject.next) {
    if(!subject.intersect) {
      for(clip = clipList; clip.next; clip = clip.next) {
        if(!clip.intersect) {

          var a = subject.vec,
              b = subject.next.nextNonIntersection().vec,
              c = clip.vec,
              d = clip.next.nextNonIntersection().vec;

          var i = segseg(a, b, c, d);

          if(i && i !== true) {
            var intersectionSubject = new Node(i, distance(a, i) / distance(a, b), true);
            var intersectionClip = new Node(i, distance(c, i) / distance(c, d), true);
            intersectionSubject.neighbor = intersectionClip;
            intersectionClip.neighbor = intersectionSubject;
            intersectionSubject.insertBetween(subject, subject.next.nextNonIntersection());
            intersectionClip.insertBetween(clip, clip.next.nextNonIntersection());
          }
        }
      }
    }
  }
};

function identifyIntersectionType(subjectList, clipList, clipTest, subjectTest, type) {
  var subject, clip;
  var se = clipTest(subjectList.vec);
  if (type === 'union') {
    se = !se;
  }

  for(subject = subjectList; subject.next; subject = subject.next) {
    if(subject.intersect) {
      subject.entry = se;
      se = !se;
    }
  }

  var ce = !subjectTest(clipList.vec);
  for(clip = clipList; clip.next; clip = clip.next) {
    if(clip.intersect) {
      clip.entry = ce;
      ce = !ce;
    }
  }
};

function collectClipResults(subjectList, clipList) {
  subjectList.createLoop();
  clipList.createLoop();

  var crt, results = [], result;

  while ((crt = subjectList.firstNodeOfInterest()) !== subjectList) {
    result = [];
    for (; !crt.visited; crt = crt.neighbor) {

      result.push(crt.vec);
      var forward = crt.entry
      while(true) {
        crt.visited = true;
        crt = forward ? crt.next : crt.prev;

        if(crt.intersect) {
          crt.visited = true;
          break;
        } else {
          result.push(crt.vec);
        }
      }
    }

    results.push(dedupe(result));
    break;
  }

  return results;
};

function clip(subjectPoly, clipPoly, type) {

  var subjectList = createLinkedList(subjectPoly);
  var clipList = createLinkedList(clipPoly);
  var clipContains = preprocessPolygon([clipPoly]);
  var subjectContains = preprocessPolygon([subjectPoly]);

  var subject, clip;

  type = type || 'difference';

  // Phase 1: Identify and store intersections between the subject
  //          and clip polygons
  var isects = identifyIntersections(subjectList, clipList);

  // Phase 2: walk the resulting linked list and mark each intersection
  //          as entering or exiting
  identifyIntersectionType(
    subjectList,
    clipList,
    clipContains,
    subjectContains,
    type
  );

  // Phase 3: collect resulting polygons
  return collectClipResults(subjectList, clipList);
};

module.exports = clip;
<commit_msg>proper point in polygon test<commit_after>// Implementation of the Greiner-Hormann polygon clipping algorithm
//

var segseg = require('segseg');
var preprocessPolygon = require("point-in-big-polygon")

function Node(vec, alpha, intersection) {
  this.vec = vec;
  this.alpha = alpha || 0;
  this.intersect = !!intersection;
}

Node.prototype = {
  vec: null,
  next: null,
  next: null,
  prev: null,
  nextPoly: null,
  neighbor: null,
  intersect: null,
  entry: null,
  visited : false,
  alpha : 0,

  nextNonIntersection : function nodeNextNonIntersection() {
    var a = this;
    while(a && a.intersect) {
      a = a.next;
    }
    return a;
  },

  last : function nodeLast() {
    var a = this;
    while (a.next && a.next !== this) {
      a = a.next;
    }
    return a;
  },

  createLoop : function nodeCreateLoop() {
    var last = this.last();
    last.prev.next = this;
    this.prev = last.prev;
  },

  firstNodeOfInterest : function nodeFirstNodeOfInterest() {
    var a = this;

    if (a) {
      do {
        a=a.next;
      } while(a!==this && (!a.intersect || a.intersect && a.visited));
    }

    return a;
  },

  insertBetween : function nodeInsertBetween(first, last) {
    var a = first;
    while(a !== last && a.alpha < this.alpha) {
      a = a.next;
    }

    this.next = a;
    this.prev = a.prev;
    if (this.prev) {
      this.prev.next = this;
    }

    this.next.prev = this;
  }
};

function createLinkedList(vecs) {
  var l = vecs.length;
  var ret, where;
  for (var i=0; i<l; i++) {
    var current = vecs[i];
    if (!ret) {
      where = ret = new Node(current);
    } else {
      where.next = new Node(current);
      where.next.prev = where;
      where = where.next;
    }
  }

  return ret;
}

function distance(v1, v2) {
  var x = v1[0] - v2[0];
  var y = v1[1] - v2[1];
  return Math.sqrt(x*x + y*y);
}

function dedupe(array) {
  var seen = {};
  return array.filter(function trackSeen(vec) {
    var key = vec.toString();
    if (seen[key]) {
      return false;
    }
    seen[key] = true;
    return true;
  });
}

function identifyIntersections(subjectList, clipList) {
  var subject, clip;
  var auxs = subjectList.last();
  auxs.next = new Node(subjectList.vec, auxs);
  auxs.next.prev = auxs;

  var auxc = clipList.last();
  auxc.next = new Node(clipList.vec, auxc);
  auxc.next.prev = auxc;

  for(subject = subjectList; subject.next; subject = subject.next) {
    if(!subject.intersect) {
      for(clip = clipList; clip.next; clip = clip.next) {
        if(!clip.intersect) {

          var a = subject.vec,
              b = subject.next.nextNonIntersection().vec,
              c = clip.vec,
              d = clip.next.nextNonIntersection().vec;

          var i = segseg(a, b, c, d);

          if(i && i !== true) {
            var intersectionSubject = new Node(i, distance(a, i) / distance(a, b), true);
            var intersectionClip = new Node(i, distance(c, i) / distance(c, d), true);
            intersectionSubject.neighbor = intersectionClip;
            intersectionClip.neighbor = intersectionSubject;
            intersectionSubject.insertBetween(subject, subject.next.nextNonIntersection());
            intersectionClip.insertBetween(clip, clip.next.nextNonIntersection());
          }
        }
      }
    }
  }
};

function identifyIntersectionType(subjectList, clipList, clipTest, subjectTest, type) {
  var subject, clip;
  var se = clipTest(subjectList.vec) < 0;
  if (type === 'union') {
    se = !se;
  }

  for(subject = subjectList; subject.next; subject = subject.next) {
    if(subject.intersect) {
      subject.entry = se;
      se = !se;
    }
  }

  var ce = subjectTest(clipList.vec) > 0;
  for(clip = clipList; clip.next; clip = clip.next) {
    if(clip.intersect) {
      clip.entry = ce;
      ce = !ce;
    }
  }
};

function collectClipResults(subjectList, clipList) {
  subjectList.createLoop();
  clipList.createLoop();

  var crt, results = [], result;

  while ((crt = subjectList.firstNodeOfInterest()) !== subjectList) {
    result = [];
    for (; !crt.visited; crt = crt.neighbor) {

      result.push(crt.vec);
      var forward = crt.entry
      while(true) {
        crt.visited = true;
        crt = forward ? crt.next : crt.prev;

        if(crt.intersect) {
          crt.visited = true;
          break;
        } else {
          result.push(crt.vec);
        }
      }
    }

    results.push(dedupe(result));
    break;
  }

  return results;
};

function clip(subjectPoly, clipPoly, type) {

  var subjectList = createLinkedList(subjectPoly);
  var clipList = createLinkedList(clipPoly);
  var clipContains = preprocessPolygon([clipPoly]);
  var subjectContains = preprocessPolygon([subjectPoly]);

  var subject, clip;

  type = type || 'difference';

  // Phase 1: Identify and store intersections between the subject
  //          and clip polygons
  var isects = identifyIntersections(subjectList, clipList);

  // Phase 2: walk the resulting linked list and mark each intersection
  //          as entering or exiting
  identifyIntersectionType(
    subjectList,
    clipList,
    clipContains,
    subjectContains,
    type
  );

  // Phase 3: collect resulting polygons
  return collectClipResults(subjectList, clipList);
};

module.exports = clip;
<|endoftext|>


<commit_before>'use strict'

module.exports = function (protocol, key) {
  describe('remove', function () {
    var server, receiver, receiver2 //eslint-disable-line
    var Promise = require('bluebird')
    var util = require('./util')
    var setup

    it('can create and connect to multiple hubs', function (done) {
      setup = util.setup({
        protocol: protocol,
        key: key,
        receivers: 2,
        log: true
      })
      server = setup.server
      receiver = setup[1]
      receiver2 = setup[2]
      setup.connected.done(function () {
        done()
      })
    })

  })
}
<commit_msg>added remove tests<commit_after>'use strict'

module.exports = function (protocol, key) {
  describe('remove', function () {
    var server, receiver, receiver2 //eslint-disable-line
    var Promise = require('bluebird')
    var util = require('./util')
    var setup

    it('can create and connect to multiple hubs', function (done) {
      setup = util.setup({
        protocol: protocol,
        key: key,
        receivers: 2,
        log: true
      })
      server = setup.server
      receiver = setup[1]
      receiver2 = setup[2]
      setup.connected.done(function () {
        done()
      })
    })

    it('can set any subscriotions on the recievers', function (done) {
      var pattern = {
        shows: {
          $any: {
            title: true
          }
        }
      }
      receiver.subscribe(pattern)
      receiver2.subscribe(pattern)

      Promise.all([
        receiver2.shows.get('a.title').is('a'),
        receiver2.shows.get('b.title').is('b'),
        receiver2.shows.get('c.title').is('c'),
        receiver2.shows.get('d.title').is('d')
      ]).done(function () {
        done()
      })

      receiver.set({
        shows: {
          a: { title: 'a' },
          b: { title: 'b' },
          c: { title: 'c' },
          d: { title: 'd'}
        }
      })
    })

  })
}
<|endoftext|>


<commit_before>(function() {

//  ---------------------------------------------------------------------------------------------------------------  //
//  no.request
//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Делает запрос моделей с сервера.
 * Аргументы можно передавать в 3 форматах:
 *   - string item, params - одна модель и опциональные параметры для нее
 *   - array item[], params - массив моделей и опциональные единые для всех параметры
 *   - array item[] - массив моделей вида {id: modelName, params: modelParams}
 * @param {String|Array|Object} items Массив названий моделей.
 * @param {Object} [params] Параметры моделей.
 * @return {no.Promise}
 */
no.request = function(items, params) {
    // приводим к формату №2
    if (typeof items === 'string') {
        items = [ items ];
    }

    // приводим №2 к формату №3
    if (typeof items[0] === 'string') {
        params = params || {};
        items = normalizeItems(items, params);
    }

    var models = [];
    for (var i = 0, l = items.length; i < l; i++) {
        var item = items[i];

        // можно не использовать if (!model.get()) { model.create() }
        // model.create все это умеет делать
        models.push(no.Model.create(item.id, item.params));
    }

    return no.request.models(models);
};

/**
 * Делает запрос моделей с сервера.
 * @param {no.Model[]} models Массив моделей.
 * @return {no.Promise}
 */
no.request.models = function(models) {
    var request = new Request(models);

    return request.start();
};

//  ---------------------------------------------------------------------------------------------------------------  //

var Request = function(models) {
    this.models = models;

    this.promise = new no.Promise();
};

// ------------------------------------------------------------------------------------------------------------- //

Request.prototype.start = function() {
    var loading = [];
    var requesting = [];

    var models = this.models;
    for (var i = 0, l = models.length; i < l; i++) {
        var model = models[i];
        var status = model.status;

        if (status === model.STATUS_OK || status === model.STATUS_ERROR) {
            //  Либо все загрузили успешно, либо кончились ретраи.
            //  Ничего не делаем в этом случае.
        } else if (status === model.STATUS_LOADING) {
            //  Уже грузится.
            loading.push(model);
        } else {
            //  Проверяем, нужно ли (можно ли) запрашивает этот ключ.
            if (status === model.STATUS_FAILED) {
                if (!model.canRetry()) {
                    //  Превышен лимит перезапросов или же модель говорит, что с такой ошибкой перезапрашиваться не нужно.
                    model.status = model.STATUS_ERROR;
                    continue;
                }
            }

            model.retries++;

            model.promise = new no.Promise();
            //  Ключ будет (пере)запрошен.
            model.status = model.STATUS_LOADING;

            requesting.push(model);
        }
    }

    this.request(loading, requesting);

    return this.promise;
};

Request.prototype.request = function(loading, requesting) {
    var all = [];

    if (requesting.length) {
        //  Запрашиваем модели, которые нужно запросить.
        var params = models2params(requesting);
        all.push( no.http('/models/', params) ); // FIXME: Урл к серверной ручке.
    }

    if (loading.length) {
        //  Ждем все остальные модели, которые должны загрузиться (уже были запрошены).
        var promises = no.array.map(loading, function(model) {
            return model.promise;
        });
        all.push( no.Promise.wait(promises) );
    }

    //  Мы ждём какие-то данные:
    //    * либо мы запросили какие-то новые модели;
    //    * либо мы ждем ранее запрошенные модели.
    if (all.length) {
        var that = this;

        //  В r должен быть массив из одного или двух элементов.
        //  Если мы делали http-запрос, то в r[0] должен быть его результат.
        no.Promise.wait(all).then(function(r) {
            if (requesting.length) {
                that.extract(requesting, r[0]);
            }

            //  "Повторяем" запрос. Если какие-то ключи не пришли, они будут перезапрошены.
            //  Если же все получено, то будет выполнен: that.promise.resolve();
            that.start();
        });

    } else {
        this.promise.resolve(this.models);
    }
};

Request.prototype.extract = function(models, results) {
    for (var i = 0, l = models.length; i < l; i++) {
        var model = models[i];
        var result = results[i];

        var data, error;
        if (!result) {
            error = {
                id: 'NO_DATA',
                reason: 'Server returned no data'
            };
        } else {
            data = model.extractData(result);
            if (!data) {
                error = model.extractError(result);
                if (!error) {
                    error = {
                        id: 'INVALID_FORMAT',
                        reason: 'response should contain result or error'
                    };
                }
            }
        }

        if (data) {
            model.setData(data);
        } else {
            model.setError(error);
        }

        no.Model.store(model);

        model.promise.resolve();
    }
};

function models2params(models) {
    var params = {};

    for (var i = 0, l = models.length; i < l; i++) {
        var suffix = '.' + i; // Чтобы не путать параметры с одинаковыми именами разных моделей,
                              // добавляем к именам параметров специальный суффикс.
        var model = models[i];

        //  Добавляем служебный параметр, содержащий id модели, которую мы хотим запросить.
        params[ '_model' + suffix ] = model.id;

        //  Каждая модель прокидывает в params все свои параметры.
        //  При этом к имени параметра добавляется суффикс.
        var mParams = model.getRequestParams();
        for (var name in mParams) {
            params[name + suffix] = mParams[name];
        }

    }

    return params;
};

    /**
     * Приводит запрашиваемые модели к формату №3 из no.request.
     * @param items Массив названией моделей.
     * @param params Параметры моделей.
     * @return {Array}
     */
    function normalizeItems(items, params) {
        var _items = [];
        for (var i = 0, l = items.length; i < l; i++) {
            _items.push({
                id: items[i],
                params: params
            });
        }

        return _items;
    }

})();

<commit_msg>#8<commit_after>(function() {

//  ---------------------------------------------------------------------------------------------------------------  //
//  no.request
//  ---------------------------------------------------------------------------------------------------------------  //

/**
 * Делает запрос моделей с сервера.
 * Аргументы можно передавать в 3 форматах:
 *   - string item, params - одна модель и опциональные параметры для нее
 *   - array item[], params - массив моделей и опциональные единые для всех параметры
 *   - array item[] - массив моделей вида {id: modelName, params: modelParams}
 * @param {String|Array|Object} items Массив названий моделей.
 * @param {Object} [params] Параметры моделей.
 * @return {no.Promise}
 */
no.request = function(items, params) {
    // приводим к формату №2
    if (typeof items === 'string') {
        items = [ items ];
    }

    // приводим №2 к формату №3
    if (typeof items[0] === 'string') {
        params = params || {};
        items = normalizeItems(items, params);
    }

    var models = [];
    for (var i = 0, l = items.length; i < l; i++) {
        var item = items[i];

        // можно не использовать if (!model.get()) { model.create() }
        // model.create все это умеет делать
        models.push(no.Model.create(item.id, item.params));
    }

    return no.request.models(models);
};

/**
 * Делает запрос моделей с сервера.
 * @param {no.Model[]} models Массив моделей.
 * @return {no.Promise}
 */
no.request.models = function(models) {
    var request = new Request(models);

    return request.start();
};

//  ---------------------------------------------------------------------------------------------------------------  //

var Request = function(models) {
    /**
     * Массив запрашиваемых моделей
     * @type {no.Model[]}
     * @private
     */
    this.models = models;

    this.promise = new no.Promise();
};

// ------------------------------------------------------------------------------------------------------------- //

Request.prototype.start = function() {
    var loading = [];
    var requesting = [];

    var models = this.models;
    for (var i = 0, l = models.length; i < l; i++) {
        var model = models[i];
        var status = model.status;

        if (status === model.STATUS_OK || status === model.STATUS_ERROR) {
            //  Либо все загрузили успешно, либо кончились ретраи.
            //  Ничего не делаем в этом случае.
        } else if (status === model.STATUS_LOADING) {
            //  Уже грузится.
            loading.push(model);
        } else {
            //  Проверяем, нужно ли (можно ли) запрашивает этот ключ.
            if (status === model.STATUS_FAILED) {
                if (!model.canRetry()) {
                    //  Превышен лимит перезапросов или же модель говорит, что с такой ошибкой перезапрашиваться не нужно.
                    model.status = model.STATUS_ERROR;
                    continue;
                }
            }

            model.retries++;

            model.promise = new no.Promise();
            //  Ключ будет (пере)запрошен.
            model.status = model.STATUS_LOADING;

            requesting.push(model);
        }
    }

    this.request(loading, requesting);

    return this.promise;
};

Request.prototype.request = function(loading, requesting) {
    var all = [];

    if (requesting.length) {
        //  Запрашиваем модели, которые нужно запросить.
        var params = models2params(requesting);
        all.push( no.http('/models/', params) ); // FIXME: Урл к серверной ручке.
    }

    if (loading.length) {
        //  Ждем все остальные модели, которые должны загрузиться (уже были запрошены).
        var promises = no.array.map(loading, model2Promise);
        all.push( no.Promise.wait(promises) );
    }

    //  Мы ждём какие-то данные:
    //    * либо мы запросили какие-то новые модели;
    //    * либо мы ждем ранее запрошенные модели.
    if (all.length) {
        var that = this;

        //  В r должен быть массив из одного или двух элементов.
        //  Если мы делали http-запрос, то в r[0] должен быть его результат.
        no.Promise.wait(all).then(function(r) {
            if (requesting.length) {
                that.extract(requesting, r[0]);
            }

            //  "Повторяем" запрос. Если какие-то ключи не пришли, они будут перезапрошены.
            //  Если же все получено, то будет выполнен: that.promise.resolve();
            that.start();
        });

    } else {
        this.promise.resolve(this.models);
    }
};

Request.prototype.extract = function(models, results) {
    for (var i = 0, l = models.length; i < l; i++) {
        var model = models[i];
        var result = results[i];

        var data, error;
        if (!result) {
            error = {
                id: 'NO_DATA',
                reason: 'Server returned no data'
            };
        } else {
            data = model.extractData(result);
            if (!data) {
                error = model.extractError(result);
                if (!error) {
                    error = {
                        id: 'INVALID_FORMAT',
                        reason: 'response should contain result or error'
                    };
                }
            }
        }

        if (data) {
            model.setData(data);
        } else {
            model.setError(error);
        }

        no.Model.store(model);

        model.promise.resolve();
    }
};

function models2params(models) {
    var params = {};

    for (var i = 0, l = models.length; i < l; i++) {
        var suffix = '.' + i; // Чтобы не путать параметры с одинаковыми именами разных моделей,
                              // добавляем к именам параметров специальный суффикс.
        var model = models[i];

        //  Добавляем служебный параметр, содержащий id модели, которую мы хотим запросить.
        params[ '_model' + suffix ] = model.id;

        //  Каждая модель прокидывает в params все свои параметры.
        //  При этом к имени параметра добавляется суффикс.
        var mParams = model.getRequestParams();
        for (var name in mParams) {
            params[name + suffix] = mParams[name];
        }

    }

    return params;
};

    /**
     * Приводит запрашиваемые модели к формату №3 из no.request.
     * @param items Массив названией моделей.
     * @param params Параметры моделей.
     * @return {Array}
     */
    function normalizeItems(items, params) {
        var _items = [];
        for (var i = 0, l = items.length; i < l; i++) {
            _items.push({
                id: items[i],
                params: params
            });
        }

        return _items;
    }

    /**
     * Возвращает promise из model
     * @param {no.Model} model Модель
     * @return {no.Promise}
     */
    function model2Promise(model) {
        return model.promise;
    }

})();
<|endoftext|>


<commit_before>import './ga';
import QuoteBackground from './quote';
import followThread from './followThread';
import startCleanTracker from './followThread/cleanTracker';
import startServices from './services';
import { injectOptionalCSS } from './optionalCSS';

const quoteBackground = new QuoteBackground();

followThread();
startCleanTracker();
chrome.runtime.setUninstallURL('https://goo.gl/forms/hA9IzC8XRvJH7pxj2'); // eslint-disable-line no-undef
startServices();

chrome.tabs.onCreated.addListener(injectOptionalCSS);
chrome.tabs.onUpdated.addListener((tabId, info, tab) => {
  if (info.status && info.status === 'loading') injectOptionalCSS(tab);
});

export {
  quoteBackground,
  peerChartBackground,
};
<commit_msg>remove peerchat leftover<commit_after>import './ga';
import QuoteBackground from './quote';
import followThread from './followThread';
import startCleanTracker from './followThread/cleanTracker';
import startServices from './services';
import { injectOptionalCSS } from './optionalCSS';

const quoteBackground = new QuoteBackground();

followThread();
startCleanTracker();
chrome.runtime.setUninstallURL('https://goo.gl/forms/hA9IzC8XRvJH7pxj2'); // eslint-disable-line no-undef
startServices();

chrome.tabs.onCreated.addListener(injectOptionalCSS);
chrome.tabs.onUpdated.addListener((tabId, info, tab) => {
  if (info.status && info.status === 'loading') injectOptionalCSS(tab);
});

export {
  quoteBackground,
};
<|endoftext|>


<commit_before>var assert = require('assert'),
    ltsv = require('../');

suite('ltsvのテスト', function() {

  suite('parse関数のテスト', function() {

    test('パースできること', function() {
      var result = ltsv.parse([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\t'));

      assert.deepEqual(result, {
        aaa: 'bbb',
        ccc: 'ddd',
        eee: 'fff'
      }, 'result has any records');
    });

  });

  suite('parseLines関数のテスト', function() {

    test('LFで区切られた文字列がパースできること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\n'));

      assert.deepEqual(result[0], {aaa: 'bbb'},
          'result[0] has {aaa: "bbb"}');
      assert.deepEqual(result[1], {ccc: 'ddd'},
          'result[1] has {ccc: "ddd"}');
      assert.deepEqual(result[2], {eee: 'fff'},
          'result[2] has {eee: "fff"}');
    });

    test('CRLFで区切られた文字列がパースできること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\r\n'));

      assert.deepEqual(result[0], {aaa: 'bbb'},
          'result[0] has {aaa: "bbb"}');
      assert.deepEqual(result[1], {ccc: 'ddd'},
          'result[1] has {ccc: "ddd"}');
      assert.deepEqual(result[2], {eee: 'fff'},
          'result[2] has {eee: "fff"}');
    });

    test('CRで区切られた文字列が一行でパースされること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\r'));

      assert.deepEqual(result[0], {
        aaa: 'bbb\rccc:ddd\reee:fff'
      }, 'result[0] has {aaa: "bbb\rccc:ddd\reee:fff"}');
    });

  });

});
<commit_msg>例外のテストを追加<commit_after>var assert = require('assert'),
    ltsv = require('../');

suite('ltsvのテスト', function() {

  suite('parse関数のテスト', function() {

    test('パースできること', function() {
      var result = ltsv.parse([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\t'));

      assert.deepEqual(result, {
        aaa: 'bbb',
        ccc: 'ddd',
        eee: 'fff'
      }, 'result has any records');
    });

    test('":"を含んでいない場合は例外が投げられること', function() {
      assert.throws(function() {
        ltsv.parse('aaa');
      }, '"aaa" has not field separator');
    });

  });

  suite('parseLines関数のテスト', function() {

    test('LFで区切られた文字列がパースできること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\n'));

      assert.deepEqual(result[0], {aaa: 'bbb'},
          'result[0] has {aaa: "bbb"}');
      assert.deepEqual(result[1], {ccc: 'ddd'},
          'result[1] has {ccc: "ddd"}');
      assert.deepEqual(result[2], {eee: 'fff'},
          'result[2] has {eee: "fff"}');
    });

    test('CRLFで区切られた文字列がパースできること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\r\n'));

      assert.deepEqual(result[0], {aaa: 'bbb'},
          'result[0] has {aaa: "bbb"}');
      assert.deepEqual(result[1], {ccc: 'ddd'},
          'result[1] has {ccc: "ddd"}');
      assert.deepEqual(result[2], {eee: 'fff'},
          'result[2] has {eee: "fff"}');
    });

    test('CRで区切られた文字列が一行でパースされること', function() {
      var result = ltsv.parseLines([
        'aaa:bbb',
        'ccc:ddd',
        'eee:fff'
      ].join('\r'));

      assert.deepEqual(result[0], {
        aaa: 'bbb\rccc:ddd\reee:fff'
      }, 'result[0] has {aaa: "bbb\rccc:ddd\reee:fff"}');
    });

  });

});
<|endoftext|>


<commit_before>define(['./namespace'], function (namespace) {

    /**
     * set "nested" object property
     */
    function set(obj, prop, val){
        var parts = (/^(.+)\.(.+)$/).exec(prop);
        if (parts){
            namespace(obj, parts[1])[parts[2]] = val;
        } else {
            obj[prop] = val;
        }
    }

    return set;

});
<commit_msg>fixed prototype pollution<commit_after>define(['./namespace'], function (namespace) {

    /**
     * set "nested" object property
     */
    function set(obj, prop, val){
        // prototype pollution mitigation
        if(prop.includes('__proto__') || prop.includes('prototype') || prop.includes('constructor')) {
            return false;
        }
        var parts = (/^(.+)\.(.+)$/).exec(prop);
        if (parts){
            namespace(obj, parts[1])[parts[2]] = val;
        } else {
            obj[prop] = val;
        }
    }

    return set;

});
<|endoftext|>


<commit_before>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        expect(fs.existsSync(__dirname + '/../LICENSE'), 'ERROR: LICENSE needs to exist! Please create one.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<commit_msg>update basic package-file testing<commit_after>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<|endoftext|>


<commit_before>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version).to.exist;
        expect(npmPackage.version).to.exist;

        if (!expect(ioPackage.common.version).to.be.equal(npmPackage.version)) {
            console.log('ERROR: Version numbers in package.json and io-package.json differ!!');
        }

        if (!ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
        }

        done();
    });
});
<commit_msg>add basic package-file testing<commit_after>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version).to.exist;
        expect(npmPackage.version).to.exist;

        if (!expect(ioPackage.common.version).to.be.equal(npmPackage.version)) {
            console.log('ERROR: Version numbers in package.json and io-package.json differ!!');
        }

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
        }

        done();
    });
});
<|endoftext|>