<commit_before>'use strict';

import {expect} from 'chai';
import YAWN from '../src/index.js';

describe('preserves comments and styling when', ()=> {

  describe('JSON is an array and', ()=> {
    // debugger
    it('transformed to an object', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      yawn.json = {val1: 1, val2: 2};

      expect(yawn.yaml).to.equal(`
        # leading comment
        val1: 1
        val2: 2
        # trailing comment`);
    });

    it('one item in array is changed', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json[0] = 'value0';
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value2
        - value0
        # trailing comment`);
    });

    xit('TODO: two items in array are changed', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json[0] = 'value0';
      json[1] = 'value3';
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value3
        - value0
        # trailing comment`);
    });

    it('one item is deleted', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json.shift();
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value2
        # trailing comment`);
    });

    xit('TODO: one item in middle is deleted', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        - value3
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json = json.slice(0, 1).concat(json.slice(2));
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
        - value1 # inline comment

        - value3
        # trailing comment`);
    });

    it('one item is added', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json.push('value3');
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
        - value1 # inline comment
        - value2
        - value3
        # trailing comment`);
    });
  });
});
<commit_msg>Fix array tests<commit_after>'use strict';

import {expect} from 'chai';
import YAWN from '../src/index.js';

describe('preserves comments and styling when', ()=> {

  describe('JSON is an array and', ()=> {
    // debugger
    it('transformed to an object', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      yawn.json = {val1: 1, val2: 2};

      expect(yawn.yaml).to.equal(`
        # leading comment
        val1: 1
        val2: 2
        # trailing comment`);
    });

    it('one item in array is changed', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json[0] = 'value0';
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value2
        - value0
        # trailing comment`);
    });

    it('one item is added to the array', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json.push('value3');
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
        - value1 # inline comment
        - value2
        - value3
        # trailing comment`);
    });

    it('two items in array are changed', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json[0] = 'value0';
      json[1] = 'value3';
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value3
        - value0
        # trailing comment`);
    });

    it('one item is deleted', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json.shift();
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
         # inline comment
        - value2
        # trailing comment`);
    });

    it('one item in middle is deleted', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        - value3
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json = json.slice(0, 1).concat(json.slice(2));
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
        - value1 # inline comment
${'        '}
        - value3
        # trailing comment`);
    });

    it('one item is added', ()=> {
      let str = `
        # leading comment
        - value1 # inline comment
        - value2
        # trailing comment`;

      let yawn = new YAWN(str);
      let json = yawn.json;
      json.push('value3');
      yawn.json = json;

      expect(yawn.yaml).to.equal(`
        # leading comment
        - value1 # inline comment
        - value2
        - value3
        # trailing comment`);
    });
  });
});
<|endoftext|>


<commit_before>import * as R from 'ramda';
import { assert } from 'chai';

import eq from './shared/eq';
import * as RA from '../src';

describe('async', function() {
  context('given wrapping of generator', function() {
    specify('should mimic async/await behavior', async function() {
      const asyncFn = RA.async(function* generator(val1, val2) {
        const a = yield RA.resolveP(val1);
        const b = yield RA.resolveP(val2);

        return a + b;
      });
      const expected = await asyncFn(1, 2);

      eq(expected, 3);
    });

    context('and the generator throw Error as the last statement', function() {
      specify('should resolve with rejection', async function() {
        const asyncFn = RA.async(function* generator(val1, val2) {
          yield RA.resolveP(val1);
          yield RA.resolveP(val2);

          throw new Error('generator error');
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });

    context('and the generator throw Error as the first statement', function() {
      specify('should resolve with rejection', async function() {
        // eslint-disable-next-line require-yield
        const asyncFn = RA.async(function* generator() {
          throw new Error('generator error');
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });

    context('and the generator contains rejection', function() {
      specify('should resolve with rejection', async function() {
        const asyncFn = RA.async(function* generator(val) {
          yield RA.resolveP(val);
          yield RA.rejectP(new Error('generator error'));
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });
  });

  it('should support yield delegation', async function() {
    const foo = function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);

      return a + b;
    };
    const bar = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);
      const c = yield* foo(a, b);

      return c + 3;
    });

    eq(await bar(1, 2), 6);
  });

  it('should support async delegation', async function() {
    const foo = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);

      return a + b;
    });
    const bar = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);
      const c = yield foo(a, b);

      return c + 3;
    });

    eq(await bar(1, 2), 6);
  });

  it('should support recursion delegation', async function() {
    const async = RA.async(function* generator(val) {
      let newVal = val;

      if (val > 1) {
        newVal = yield async(val - 1);
      }

      return yield newVal;
    });

    eq(await async(10), 1);
  });

  it('should curry', async function() {
    const async = RA.async(R.__);
    const asyncFn = async(function* generator() {
      yield RA.resolveP(1);
      return 2;
    });
    const expected = await asyncFn();

    eq(expected, 2);
  });

  context('given wrapping of generator with arity of 2', function() {
    let asyncFn;

    beforeEach(function() {
      // eslint-disable-next-line require-yield
      asyncFn = RA.async(function* generator(a, b) {
        return a + b;
      });
    });

    specify('should translate generator arity to wrapper', function() {
      eq(asyncFn.length, 2);
    });

    specify('should curry wrapper to appropriate arity', async function() {
      eq(await asyncFn(1, 2), 3);
      eq(await asyncFn(1)(2), 3);
    });
  });

  context('given wrapping of generator with arity of 0', function() {
    context('then the resulting wrapper', function() {
      let asyncFn;

      beforeEach(function() {
        // eslint-disable-next-line require-yield
        asyncFn = RA.async(function* generator() {
          return 1;
        });
      });

      specify('should not support placeholder', async function() {
        const expected = await asyncFn(R.__);

        eq(expected, 1);
      });

      specify('should support call without arguments', async function() {
        const expected = await asyncFn();

        eq(expected, 1);
      });
    });
  });
});
<commit_msg>test(async): add tests for handling nested generator/async errors<commit_after>import * as R from 'ramda';
import { assert } from 'chai';

import eq from './shared/eq';
import * as RA from '../src';

describe('async', function() {
  context('given wrapping of generator', function() {
    specify('should mimic async/await behavior', async function() {
      const asyncFn = RA.async(function* generator(val1, val2) {
        const a = yield RA.resolveP(val1);
        const b = yield RA.resolveP(val2);

        return a + b;
      });
      const expected = await asyncFn(1, 2);

      eq(expected, 3);
    });

    context('and the generator throw Error as the last statement', function() {
      specify('should resolve with rejection', async function() {
        const asyncFn = RA.async(function* generator(val1, val2) {
          yield RA.resolveP(val1);
          yield RA.resolveP(val2);

          throw new Error('generator error');
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });

    context('and the generator throw Error as the first statement', function() {
      specify('should resolve with rejection', async function() {
        // eslint-disable-next-line require-yield
        const asyncFn = RA.async(function* generator() {
          throw new Error('generator error');
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });

    context('and the generator contains rejection', function() {
      specify('should resolve with rejection', async function() {
        const asyncFn = RA.async(function* generator(val) {
          yield RA.resolveP(val);
          yield RA.rejectP(new Error('generator error'));
        });

        try {
          await asyncFn(1, 2);
          throw new Error('fulfilling should fail');
        } catch (error) {
          assert.instanceOf(error, Error);
          eq(error.message, 'generator error');
        }
      });
    });

    context(
      'and the generator handles error for another generator',
      function() {
        specify('should not throw Error', async function() {
          const foo = function* generator(val) {
            yield RA.resolveP(val);
            throw new Error('generator foo error');
          };
          const bar = RA.async(function* generator(val1, val2) {
            const a = yield RA.resolveP(val1);
            const b = yield RA.resolveP(val2);
            let c;
            try {
              c = yield* foo(a, b);
            } catch (error) {
              c = 6;
            }

            return c + 3;
          });

          eq(await bar(1, 2), 9);
        });
      }
    );

    context('and the generator handles error for another async', function() {
      specify('should not throw Error', async function() {
        const foo = RA.async(function* generator(val) {
          yield RA.resolveP(val);
          throw new Error('generator foo error');
        });
        const bar = RA.async(function* generator(val1, val2) {
          const a = yield RA.resolveP(val1);
          const b = yield RA.resolveP(val2);
          let c;
          try {
            c = yield foo(a, b);
          } catch (error) {
            c = 6;
          }

          return c + 3;
        });

        eq(await bar(1, 2), 9);
      });
    });
  });

  it('should support yield delegation', async function() {
    const foo = function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);

      return a + b;
    };
    const bar = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);
      const c = yield* foo(a, b);

      return c + 3;
    });

    eq(await bar(1, 2), 6);
  });

  it('should support async delegation', async function() {
    const foo = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);

      return a + b;
    });
    const bar = RA.async(function* generator(val1, val2) {
      const a = yield RA.resolveP(val1);
      const b = yield RA.resolveP(val2);
      const c = yield foo(a, b);

      return c + 3;
    });

    eq(await bar(1, 2), 6);
  });

  it('should support recursion delegation', async function() {
    const async = RA.async(function* generator(val) {
      let newVal = val;

      if (val > 1) {
        newVal = yield async(val - 1);
      }

      return yield newVal;
    });

    eq(await async(10), 1);
  });

  it('should curry', async function() {
    const async = RA.async(R.__);
    const asyncFn = async(function* generator() {
      yield RA.resolveP(1);
      return 2;
    });
    const expected = await asyncFn();

    eq(expected, 2);
  });

  context('given wrapping of generator with arity of 2', function() {
    let asyncFn;

    beforeEach(function() {
      // eslint-disable-next-line require-yield
      asyncFn = RA.async(function* generator(a, b) {
        return a + b;
      });
    });

    specify('should translate generator arity to wrapper', function() {
      eq(asyncFn.length, 2);
    });

    specify('should curry wrapper to appropriate arity', async function() {
      eq(await asyncFn(1, 2), 3);
      eq(await asyncFn(1)(2), 3);
    });
  });

  context('given wrapping of generator with arity of 0', function() {
    context('then the resulting wrapper', function() {
      let asyncFn;

      beforeEach(function() {
        // eslint-disable-next-line require-yield
        asyncFn = RA.async(function* generator() {
          return 1;
        });
      });

      specify('should not support placeholder', async function() {
        const expected = await asyncFn(R.__);

        eq(expected, 1);
      });

      specify('should support call without arguments', async function() {
        const expected = await asyncFn();

        eq(expected, 1);
      });
    });
  });
});
<|endoftext|>


<commit_before>var fs = require('fs')
var parseTorrent = require('parse-torrent')
var test = require('tape')
var WebTorrent = require('../')

var leaves = fs.readFileSync(__dirname + '/torrents/leaves.torrent')
var leavesTorrent = parseTorrent(leaves)
var leavesBook = fs.readFileSync(__dirname + '/content/Leaves of Grass by Walt Whitman.epub')

var leavesMagnetURI = 'magnet:?xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36&dn=Leaves+of+Grass+by+Walt+Whitman.epub&tr=http%3A%2F%2Ftracker.thepiratebay.org%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F%2Ftracker.ccc.de%3A80&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80&tr=udp%3A%2F%2Ffr33domtracker.h33t.com%3A3310%2Fannounce&tr=http%3A%2F%2Ftracker.bittorrent.am%2Fannounce'

test('client.add (magnet uri, torrent file, info hash, and parsed torrent)', function (t) {
  // magnet uri (utf8 string)
  var client1 = new WebTorrent({ dht: false, tracker: false })
  var torrent1 = client1.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  t.equal(torrent1.infoHash, leavesTorrent.infoHash)
  t.equal(torrent1.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client1.destroy()

  // torrent file (buffer)
  var client2 = new WebTorrent({ dht: false, tracker: false })
  var torrent2 = client2.add(leaves)
  t.equal(torrent2.infoHash, leavesTorrent.infoHash)
  t.equal(torrent2.magnetURI, leavesMagnetURI)
  client2.destroy()

  // info hash (hex string)
  var client3 = new WebTorrent({ dht: false, tracker: false })
  var torrent3 = client3.add(leavesTorrent.infoHash)
  t.equal(torrent3.infoHash, leavesTorrent.infoHash)
  t.equal(torrent3.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client3.destroy()

  // info hash (buffer)
  var client4 = new WebTorrent({ dht: false, tracker: false })
  var torrent4 = client4.add(new Buffer(leavesTorrent.infoHash, 'hex'))
  t.equal(torrent4.infoHash, leavesTorrent.infoHash)
  t.equal(torrent4.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client4.destroy()

  // parsed torrent (from parse-torrent)
  var client5 = new WebTorrent({ dht: false, tracker: false })
  var torrent5 = client5.add(leavesTorrent)
  t.equal(torrent5.infoHash, leavesTorrent.infoHash)
  t.equal(torrent5.magnetURI, leavesMagnetURI)
  client5.destroy()

  t.end()
})

test('client.seed (Buffer, Blob)', function (t) {
  t.plan(global.Blob !== undefined ? 4 : 2)

  var opts = {
    name: 'Leaves of Grass by Walt Whitman.epub',
    announce: [
      'http://tracker.thepiratebay.org/announce',
      'udp://tracker.openbittorrent.com:80',
      'udp://tracker.ccc.de:80',
      'udp://tracker.publicbt.com:80',
      'udp://fr33domtracker.h33t.com:3310/announce',
      'http://tracker.bittorrent.am/announce'
    ]
  }

  // torrent file (Buffer)
  var client1 = new WebTorrent({ dht: false, tracker: false })
  client1.seed(leavesBook, opts, function (torrent1) {
    t.equal(torrent1.infoHash, leavesTorrent.infoHash)
    t.equal(torrent1.magnetURI, leavesMagnetURI)
    client1.destroy()
  })

  // Blob
  if (global.Blob !== undefined) {
    var client2 = new WebTorrent({ dht: false, tracker: false })
    client2.seed(new global.Blob([ leavesBook ]), opts, function (torrent2) {
      t.equal(torrent2.infoHash, leavesTorrent.infoHash)
      t.equal(torrent2.magnetURI, leavesMagnetURI)
      client2.destroy()
    })
  } else {
    console.log('Skipping Blob test because missing `Blob` constructor')
  }
})

test('after client.destroy(), throw on client.add() or client.seed()', function (t) {
  t.plan(3)

  var client = new WebTorrent({ dht: false, tracker: false })
  client.destroy(function () {
    t.pass('client destroyed')
  })
  t.throws(function () {
    client.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  })
  t.throws(function () {
    client.seed(new Buffer('sup'))
  })
})

test('after client.destroy(), no "torrent" or "ready" events emitted', function (t) {
  t.plan(1)

  var client = new WebTorrent({ dht: false, tracker: false })
  client.add(leaves, function () {
    t.fail('unexpected "torrent" event (from add)')
  })
  client.seed(leavesBook, function () {
    t.fail('unexpected "torrent" event (from seed)')
  })
  client.on('ready', function () {
    t.fail('unexpected "ready" event')
  })
  client.destroy(function () {
    t.pass('client destroyed')
  })
})
<commit_msg>test: add tests for client.remove<commit_after>var fs = require('fs')
var parseTorrent = require('parse-torrent')
var test = require('tape')
var WebTorrent = require('../')

var leaves = fs.readFileSync(__dirname + '/torrents/leaves.torrent')
var leavesTorrent = parseTorrent(leaves)
var leavesBook = fs.readFileSync(__dirname + '/content/Leaves of Grass by Walt Whitman.epub')

var leavesMagnetURI = 'magnet:?xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36&dn=Leaves+of+Grass+by+Walt+Whitman.epub&tr=http%3A%2F%2Ftracker.thepiratebay.org%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=udp%3A%2F%2Ftracker.ccc.de%3A80&tr=udp%3A%2F%2Ftracker.publicbt.com%3A80&tr=udp%3A%2F%2Ffr33domtracker.h33t.com%3A3310%2Fannounce&tr=http%3A%2F%2Ftracker.bittorrent.am%2Fannounce'

test('client.add/remove (magnet uri, torrent file, info hash, and parsed torrent)', function (t) {
  // magnet uri (utf8 string)
  var client1 = new WebTorrent({ dht: false, tracker: false })
  var torrent1 = client1.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  t.equal(client1.torrents.length, 1)
  t.equal(torrent1.infoHash, leavesTorrent.infoHash)
  t.equal(torrent1.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client1.remove('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  t.equal(client1.torrents.length, 0)
  client1.destroy()

  // torrent file (buffer)
  var client2 = new WebTorrent({ dht: false, tracker: false })
  var torrent2 = client2.add(leaves)
  t.equal(client2.torrents.length, 1)
  t.equal(torrent2.infoHash, leavesTorrent.infoHash)
  t.equal(torrent2.magnetURI, leavesMagnetURI)
  client2.remove(leaves)
  t.equal(client2.torrents.length, 0)
  client2.destroy()

  // info hash (hex string)
  var client3 = new WebTorrent({ dht: false, tracker: false })
  var torrent3 = client3.add(leavesTorrent.infoHash)
  t.equal(client3.torrents.length, 1)
  t.equal(torrent3.infoHash, leavesTorrent.infoHash)
  t.equal(torrent3.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client3.remove(leavesTorrent.infoHash)
  t.equal(client3.torrents.length, 0)
  client3.destroy()

  // info hash (buffer)
  var client4 = new WebTorrent({ dht: false, tracker: false })
  var torrent4 = client4.add(new Buffer(leavesTorrent.infoHash, 'hex'))
  t.equal(client4.torrents.length, 1)
  t.equal(torrent4.infoHash, leavesTorrent.infoHash)
  t.equal(torrent4.magnetURI, 'magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  client4.remove(new Buffer(leavesTorrent.infoHash, 'hex'))
  t.equal(client4.torrents.length, 0)
  client4.destroy()

  // parsed torrent (from parse-torrent)
  var client5 = new WebTorrent({ dht: false, tracker: false })
  var torrent5 = client5.add(leavesTorrent)
  t.equal(client5.torrents.length, 1)
  t.equal(torrent5.infoHash, leavesTorrent.infoHash)
  t.equal(torrent5.magnetURI, leavesMagnetURI)
  client5.remove(leavesTorrent)
  t.equal(client5.torrents.length, 0)
  client5.destroy()

  t.end()
})

test('client.seed (Buffer, Blob)', function (t) {
  t.plan(global.Blob !== undefined ? 8 : 4)

  var opts = {
    name: 'Leaves of Grass by Walt Whitman.epub',
    announce: [
      'http://tracker.thepiratebay.org/announce',
      'udp://tracker.openbittorrent.com:80',
      'udp://tracker.ccc.de:80',
      'udp://tracker.publicbt.com:80',
      'udp://fr33domtracker.h33t.com:3310/announce',
      'http://tracker.bittorrent.am/announce'
    ]
  }

  // torrent file (Buffer)
  var client1 = new WebTorrent({ dht: false, tracker: false })
  client1.seed(leavesBook, opts, function (torrent1) {
    t.equal(client1.torrents.length, 1)
    t.equal(torrent1.infoHash, leavesTorrent.infoHash)
    t.equal(torrent1.magnetURI, leavesMagnetURI)
    client1.remove(torrent1)
    t.equal(client1.torrents.length, 0)
    client1.destroy()
  })

  // Blob
  if (global.Blob !== undefined) {
    var client2 = new WebTorrent({ dht: false, tracker: false })
    client2.seed(new global.Blob([ leavesBook ]), opts, function (torrent2) {
      t.equal(client2.torrents.length, 1)
      t.equal(torrent2.infoHash, leavesTorrent.infoHash)
      t.equal(torrent2.magnetURI, leavesMagnetURI)
      client2.remove(torrent2)
      t.equal(client2.torrents.length, 0)
      client2.destroy()
    })
  } else {
    console.log('Skipping Blob test because missing `Blob` constructor')
  }
})

test('after client.destroy(), throw on client.add() or client.seed()', function (t) {
  t.plan(3)

  var client = new WebTorrent({ dht: false, tracker: false })
  client.destroy(function () {
    t.pass('client destroyed')
  })
  t.throws(function () {
    client.add('magnet:?xt=urn:btih:' + leavesTorrent.infoHash)
  })
  t.throws(function () {
    client.seed(new Buffer('sup'))
  })
})

test('after client.destroy(), no "torrent" or "ready" events emitted', function (t) {
  t.plan(1)

  var client = new WebTorrent({ dht: false, tracker: false })
  client.add(leaves, function () {
    t.fail('unexpected "torrent" event (from add)')
  })
  client.seed(leavesBook, function () {
    t.fail('unexpected "torrent" event (from seed)')
  })
  client.on('ready', function () {
    t.fail('unexpected "ready" event')
  })
  client.destroy(function () {
    t.pass('client destroyed')
  })
})
<|endoftext|>


<commit_before>var fs = require('fs')
var http = require('http')
var loadIPSet = require('../')
var test = require('tape')
var zlib = require('zlib')

test('array of IPs', function (t) {
  t.plan(5)
  loadIPSet([ '1.2.3.4' ], function (err, ipSet) {
    if (err) throw err
    t.ok(ipSet.contains('1.2.3.4'))
    t.ok(!ipSet.contains('1.1.1.1'))
  })
  loadIPSet([ '1.2.3.4', '5.6.7.8' ], function (err, ipSet) {
    if (err) throw err
    t.ok(ipSet.contains('1.2.3.4'))
    t.ok(ipSet.contains('5.6.7.8'))
    t.ok(!ipSet.contains('1.1.1.1'))
  })
})

function checkList (t, ipSet) {
  t.ok(ipSet.contains('1.2.3.0'))
  t.ok(ipSet.contains('1.2.3.1'))
  t.ok(ipSet.contains('1.2.3.254'))
  t.ok(ipSet.contains('1.2.3.255'))
  t.ok(ipSet.contains('5.6.7.0'))
  t.ok(ipSet.contains('5.6.7.128'))
  t.ok(ipSet.contains('5.6.7.255'))
  t.ok(!ipSet.contains('1.1.1.1'))
  t.ok(!ipSet.contains('2.2.2.2'))
}

test('array of IP ranges', function (t) {
  t.plan(9)
  loadIPSet([
    { start: '1.2.3.0', end: '1.2.3.255' },
    { start: '5.6.7.0', end: '5.6.7.255' }
  ], function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})

test('http url', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url (with custom user agent)', function (t) {
  t.plan(10)
  var server = http.createServer(function (req, res) {
    t.equal(req.headers['user-agent'], 'WebTorrent (http://webtorrent.io)')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, {
      headers: { 'user-agent': 'WebTorrent (http://webtorrent.io)'}
    }, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url with gzip encoding', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    res.setHeader('content-encoding', 'gzip')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(zlib.createGzip())
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url with deflate encoding', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    res.setHeader('content-encoding', 'deflate')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(zlib.createDeflate())
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('fs path', function (t) {
  t.plan(9)
  loadIPSet(__dirname + '/list.txt', function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})

test('fs path with gzip', function (t) {
  t.plan(9)
  loadIPSet(__dirname + '/list.txt.gz', function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})
<commit_msg>standard<commit_after>var fs = require('fs')
var http = require('http')
var loadIPSet = require('../')
var test = require('tape')
var zlib = require('zlib')

test('array of IPs', function (t) {
  t.plan(5)
  loadIPSet([ '1.2.3.4' ], function (err, ipSet) {
    if (err) throw err
    t.ok(ipSet.contains('1.2.3.4'))
    t.ok(!ipSet.contains('1.1.1.1'))
  })
  loadIPSet([ '1.2.3.4', '5.6.7.8' ], function (err, ipSet) {
    if (err) throw err
    t.ok(ipSet.contains('1.2.3.4'))
    t.ok(ipSet.contains('5.6.7.8'))
    t.ok(!ipSet.contains('1.1.1.1'))
  })
})

function checkList (t, ipSet) {
  t.ok(ipSet.contains('1.2.3.0'))
  t.ok(ipSet.contains('1.2.3.1'))
  t.ok(ipSet.contains('1.2.3.254'))
  t.ok(ipSet.contains('1.2.3.255'))
  t.ok(ipSet.contains('5.6.7.0'))
  t.ok(ipSet.contains('5.6.7.128'))
  t.ok(ipSet.contains('5.6.7.255'))
  t.ok(!ipSet.contains('1.1.1.1'))
  t.ok(!ipSet.contains('2.2.2.2'))
}

test('array of IP ranges', function (t) {
  t.plan(9)
  loadIPSet([
    { start: '1.2.3.0', end: '1.2.3.255' },
    { start: '5.6.7.0', end: '5.6.7.255' }
  ], function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})

test('http url', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url (with custom user agent)', function (t) {
  t.plan(10)
  var server = http.createServer(function (req, res) {
    t.equal(req.headers['user-agent'], 'WebTorrent (http://webtorrent.io)')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, {
      headers: { 'user-agent': 'WebTorrent (http://webtorrent.io)' }
    }, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url with gzip encoding', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    res.setHeader('content-encoding', 'gzip')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(zlib.createGzip())
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('http url with deflate encoding', function (t) {
  t.plan(9)
  var server = http.createServer(function (req, res) {
    res.setHeader('content-encoding', 'deflate')
    fs.createReadStream(__dirname + '/list.txt')
      .pipe(zlib.createDeflate())
      .pipe(res)
  })
  server.listen(0, function () {
    var url = 'http://127.0.0.1:' + server.address().port
    loadIPSet(url, function (err, ipSet) {
      if (err) throw err
      checkList(t, ipSet)
      server.close()
    })
  })
})

test('fs path', function (t) {
  t.plan(9)
  loadIPSet(__dirname + '/list.txt', function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})

test('fs path with gzip', function (t) {
  t.plan(9)
  loadIPSet(__dirname + '/list.txt.gz', function (err, ipSet) {
    if (err) throw err
    checkList(t, ipSet)
  })
})
<|endoftext|>


<commit_before>/* jslint node: true */
/* jshint esversion: 6 */
'use strict';
var express  = require('express');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

/**
 * Class definition for httpServer
 * @constructor
 * TODO finish commenting
 */
class HttpServer {

  constructor(settings){
    this.url = settings.url;
    this.path = settings.path;
  }

  /**
   * Prepare and start httpServer app
   * TODO finish commenting
   */
  run() {
    var self = this;
    mongoose.connect(self.url);     // connect to mongoDB database on modulus.io

    app.use(express.static(self.path + '/public'));               // set the static files location /public/img will be /img for users
    app.use(morgan('dev'));                                         // log every request to the console
    app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
    app.use(bodyParser.json());                                     // parse application/json
    app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
    app.use(methodOverride());

    self.defineAPI();
    self.defineRoute();
    /**
     * Start App and listen on given port
     */
    app.listen(8080, function(){
      console.log("FatCatsJS HTTP listening on port 8080");
    });

  }

  defineAPI() {
    var FatCats = mongoose.model('feeding', {datetime : {type: Date, required: true}});

    //GET
    app.get('/api/feedings', function(req, res){
      FatCats.find().sort({_id:-1}).exec(function(err, feedings) {
        if (err) {
          res.send(err);
        }
        res.json(feedings);
      });
    });

    //POST
    app.post('/api/feedings', function(req, res) {
      FatCats.create({
        datetime : req.body.text,
        type : req.body.text,
        amount : req.body.text
      }, function(err, feeding) {
        if (err) {
          res.send(err);
        }
        FatCats.find(function(err, feedings) {
          if (err){
            res.send(err);
          }
          res.json(feedings);
        });
      });
    });

    //DELETE
    app.delete('/api/feedings/:feeding_id', function(req, res){
      FatCats.remove({
        _id : req.params.feeding_id
      }, function(err, todo) {
        if (err) {
          res.send(err);
        }
        FatCats.find(function(err, feedings){
          if (err) {
            res.send(err);
          }
          res.json(feedings);
        });
      });
    });
  }

  defineRoute() {
    var self = this;

    router.use(function (req,res,next) {
      console.log("/" + req.method);
      next();
    });

    router.get("/",function(req,res){
      res.sendFile("/public/index.html" , {root : self.path});
    });

    app.use("/",router);

    app.use("*",function(req,res){
      res.sendFile("public/404.html", {root : self.path});
    });
  }
}

module.exports = HttpServer;
<commit_msg>Added api get for catfood mongo collection<commit_after>/* jslint node: true */
/* jshint esversion: 6 */
'use strict';
var express  = require('express');
var app = express();
var router = express.Router();
var mongoose = require('mongoose');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');

/**
 * Class definition for httpServer
 * @constructor
 * TODO finish commenting
 */
class HttpServer {

  constructor(settings){
    this.url = settings.url;
    this.path = settings.path;
  }

  /**
   * Prepare and start httpServer app
   * TODO finish commenting
   */
  run() {
    var self = this;
    mongoose.connect(self.url);

    app.use(express.static(self.path + '/public'));               // set the static files location
    app.use(morgan('dev'));                                         // log every request to the console
    app.use(bodyParser.urlencoded({'extended':'true'}));            // parse application/x-www-form-urlencoded
    app.use(bodyParser.json());                                     // parse application/json
    app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
    app.use(methodOverride());

    self.defineAPI();
    self.defineRoute();
    /**
     * Start App and listen on given port
     */
    app.listen(8080, function(){
      console.log("FatCatsJS HTTP listening on port 8080");
    });

  }

  defineAPI() {
    var FatCats = mongoose.model('feeding', {
      datetime : {type: Date, required: true}
    },'feedings');

    var CatFood = mongoose.model('catfood', {
      brand : {type : String},
      name : {type : String},
      consistency : {type : String},
      kcal : {type : Number},
      measurement : {type : String}
    }, 'catfood');
    //GET
    app.get('/api/feedings', function(req, res){
      FatCats.find().sort({"datetime":-1}).exec(function(err, feedings) {
        if (err) {
          res.send(err);
        }
        res.json(feedings);
      });
    });
    app.get('/api/catfood', function(req, res){
      CatFood.find(function(err, catfood) {
        if (err) {
          res.send(err);
        }
        res.json(catfood);
      });
    });

    //POST
    app.post('/api/feedings', function(req, res) {
      FatCats.create({
        datetime : req.body.text,
        type : req.body.text,
        amount : req.body.text
      }, function(err, feeding) {
        if (err) {
          res.send(err);
        }
        FatCats.find(function(err, feedings) {
          if (err){
            res.send(err);
          }
          res.json(feedings);
        });
      });
    });

    //DELETE
    app.delete('/api/feedings/:feeding_id', function(req, res){
      FatCats.remove({
        _id : req.params.feeding_id
      }, function(err, todo) {
        if (err) {
          res.send(err);
        }
        FatCats.find(function(err, feedings){
          if (err) {
            res.send(err);
          }
          res.json(feedings);
        });
      });
    });
  }

  defineRoute() {
    var self = this;

    router.use(function (req,res,next) {
      console.log("/" + req.method);
      next();
    });

    router.get("/",function(req,res){
      res.sendFile("/public/index.html" , {root : self.path});
    });

    app.use("/",router);

    app.use("*",function(req,res){
      res.sendFile("public/404.html", {root : self.path});
    });
  }
}

module.exports = HttpServer;
<|endoftext|>


<commit_before>'use strict'

const buildConfig = require('../config')
const defaultConfig = require('../config/default.server')
const config = buildConfig(defaultConfig)

const Hapi = require('hapi')
const server = new Hapi.Server()

server.connection({
  port: Number(config.get('hapi.port')),
  host: config.get('hapi.host'),
  routes: {
    cors: true
  }
})

server.register(
  [
    {
      register: require('hapi-pino'),
      options: config.get('logger.pino') || {}
    },
    {
      register: require('inert')
    },
    {
      register: require('vision')
    },
    {
      register: require('hapi-swagger'),
      options: require('../plugin/config/swagger')
    },
    {
      register: require('../plugin'),
      options: {config}
    }
  ],
  function (err) {
    if (err) {
      throw err
    }
  }
)

module.exports = server
<commit_msg>Explicitly add 'org' header for CORS<commit_after>'use strict'

const buildConfig = require('../config')
const defaultConfig = require('../config/default.server')
const config = buildConfig(defaultConfig)

const Hapi = require('hapi')
const server = new Hapi.Server()

server.connection({
  port: Number(config.get('hapi.port')),
  host: config.get('hapi.host'),
  routes: {
    cors: {
      additionalHeaders: ['org']
    }
  }
})

server.register(
  [
    {
      register: require('hapi-pino'),
      options: config.get('logger.pino') || {}
    },
    {
      register: require('inert')
    },
    {
      register: require('vision')
    },
    {
      register: require('hapi-swagger'),
      options: require('../plugin/config/swagger')
    },
    {
      register: require('../plugin'),
      options: {config}
    }
  ],
  function (err) {
    if (err) {
      throw err
    }
  }
)

module.exports = server
<|endoftext|>


<commit_before>'use strict';

const data = require('./data/data');
const constants = require('./data/constants');

describe('entry reads', function () {
    before(data);
    it('should grant read access to read-group member', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should grant read access to owner', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should grant read access to entry with anonymous read', function () {
        return couch.getEntryById('anonymousEntry', 'anonymous').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should get entry by uuid', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            return couch.getEntryByUuid(doc._id, 'b@b.com').then(doc => {
                doc.should.be.an.instanceOf(Object);
            });
        }) ;
    });

    it('should not find document', function () {
        return couch.getEntryByUuid('inexistant', 'b@b.com').should.be.rejectedWith(/not found/);
    });

    it('should get all readable entries for a user', function () {
        return couch.getEntriesByUserAndRights('b@b.com', 'read').then(entries => {
            entries.should.have.length(5);
        });
    });
});

describe('entry creation and editions', function () {
    beforeEach(data);

    it('create a new entry', function() {
        return couch.createEntry('myid', 'a@a.com', {}).then(entryInfo => {
            entryInfo.should.have.property('id');
            entryInfo.should.have.property('rev');
            return couch.getEntryById('myid', 'a@a.com').then(entry => {
                entry.should.have.property('$content');
            });
        });
    });

    it('create two entries with same id but different users', function () {
        return couch.createEntry('myid', 'a@a.com').then(entryInfo => {
            return couch.createEntry('myid', 'b@b.com').then(entryInfo2 => {
                entryInfo.id.should.not.equal(entryInfo2.id);
            });
        })
    });

    it('create an entry for which the owner and id already exists', function () {
        return couch.createEntry('myid', 'a@a.com').then(entryInfo => {
            return couch.createEntry('myid', 'a@a.com').then(entryInfo2 => {
                entryInfo.id.should.equal(entryInfo2.id);
            })
        })
    });

    it('anonymous cannot insert a new entry', function () {
        return couch.insertEntry(constants.newEntry, 'anonymous').should.be.rejectedWith(/must be an email/);
    });

    it('entry should have content', function () {
        return couch.insertEntry({
            $id: 'D'
        }, 'z@z.com').should.be.rejectedWith(/has no content/);
    });

    it('update entry should reject if entry does not exist', function () {
        return couch.insertEntry({
            _id: 'new',
            $content: {}
        }, 'z@z.com', {isUpdate: true}).should.be.rejectedWith(/does not exist/);
    });

    it('update entry without _id should reject', function () {
        return couch.insertEntry({
            $content: {}
        }, 'z@z.com', {isUpdate: true}).should.be.rejectedWith(/should have an _id/);
    });

    it('create new entry that has an _id is not possible', function () {
        return couch.insertEntry({
            $content: {},
            _id: 'new'
        }, 'z@z.com', {isNew: true}).should.be.rejectedWith(/should not have _id/);
    });

    it('anybody not anonymous can insert a new entry (without _id)', function () {
        return couch.insertEntry(constants.newEntry, 'z@z.com').then(res => {
            res.action.should.equal('created');
            res.info.id.should.be.an.instanceOf(String);
            res.info.rev.should.be.an.instanceOf(String);
            return couch.getEntryById('C', 'z@z.com').should.be.fulfilled();
        });
    });

    it('anybody not anonymous can insert a new entry (with _id)', function () {
        return couch.insertEntry(constants.newEntryWithId, 'z@z.com').then(() => {
            return couch.getEntryById('D', 'z@z.com').should.eventually.be.an.instanceOf(Object);
        });
    });

    it('insert new entry with groups', function () {
        return couch.insertEntry(constants.newEntry, 'z@z.com', {groups: ['groupX', 'groupY']})
            .then(() => couch.getEntryById(constants.newEntry.$id, 'z@z.com'))
            .then(entry => {
                entry.$owners.should.have.length(3);
        });
    });

    it('should throw a conflict error', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            return couch.insertEntry(doc, 'b@b.com').then(() => {
                return couch.insertEntry(doc, 'b@b.com').should.be.rejectedWith(/_rev differ/);
            });
        });
    });

    it('should modify an entry', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            doc.$content.abc = 'abc';
            return couch.insertEntry(doc, 'a@a.com').then(() => {
                return couch.getEntryById('A', 'a@a.com').then(entry => {
                    entry.$content.abc.should.equal('abc');
                });
            });
        });
    });

    it('should delete an entry by uuid', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            return couch.deleteEntryByUuid(doc._id, 'a@a.com')
                .then(() => {
                    return couch.getEntryById('A', 'a@a.com').should.be.rejectedWith(/not found/);
                });
        });
    });

    it('should delete an entry by id', function () {
        return couch.deleteEntryById('A', 'a@a.com')
            .then(() => {
                return couch.getEntryById('A', 'a@a.com').should.be.rejectedWith(/not found/);
            });
    });

    it('should add group to entry', function () {
        return couch.addGroupToEntry('A', 'b@b.com', 'groupD')
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(doc => {
                doc.$owners.indexOf('groupD').should.be.above(0);
            });
    });

    it('Add existing group to entry', function() {
        return couch.addGroupToEntry('A', 'b@b.com', 'groupD')
            .then(() => couch.addGroupToEntry('A', 'b@b.com', 'groupD'))
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(entry => {
                let count = 0;
                for (let i=0; i<entry.$owners.length; i++) {
                    if (entry.$owners[i] === 'groupD') count++;
                }
                count.should.equal(1);
            });
    });

    it('Add existing group to entry (by uuid)', function() {
        return couch.getEntryById('A', 'b@b.com')
            .then(entry => {
                let uuid = entry._id;
                return couch.addGroupToEntryByUuid(uuid, 'b@b.com', 'anonymousRead')
                    .then(() => couch.addGroupToEntryByUuid(uuid, 'b@b.com', 'anonymousRead'))
                    .then(() => couch.getEntryById('A', 'b@b.com'))
                    .then(entry => {
                        let count = 0;
                        for (let i=0; i<entry.$owners.length; i++) {
                            if (entry.$owners[i] === 'anonymousRead') count++;
                        }
                        count.should.equal(1);
                    });
            });
    });

    it('should fail to add group to entry', function () {
        return couch.addGroupToEntry('A', 'a@a.com', 'groupC').should.be.rejectedWith(/unauthorized/);
    });

    it('should remove group from entry', function () {
        return couch.removeGroupFromEntry('A', 'b@b.com', 'groupB')
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(doc => {
                doc.$owners.indexOf('groupB').should.be.equal(-1);
            });
    });

    it('should fail to remove group from entry', function () {
        return couch.removeGroupFromEntry('A', 'a@a.com', 'groupB').should.be.rejectedWith(/unauthorized/);
    });

    it('should fail to remove primary owner', function () {
        return couch.removeGroupFromEntry('A', 'b@b.com', 'b@b.com').should.be.rejectedWith(/cannot remove primary owner/);
    });
});
<commit_msg>eslint-fix<commit_after>'use strict';

const data = require('./data/data');
const constants = require('./data/constants');

describe('entry reads', function () {
    before(data);
    it('should grant read access to read-group member', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should grant read access to owner', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should grant read access to entry with anonymous read', function () {
        return couch.getEntryById('anonymousEntry', 'anonymous').then(doc => {
            doc.should.be.an.instanceOf(Object);
        });
    });

    it('should get entry by uuid', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            return couch.getEntryByUuid(doc._id, 'b@b.com').then(doc => {
                doc.should.be.an.instanceOf(Object);
            });
        }) ;
    });

    it('should not find document', function () {
        return couch.getEntryByUuid('inexistant', 'b@b.com').should.be.rejectedWith(/not found/);
    });

    it('should get all readable entries for a user', function () {
        return couch.getEntriesByUserAndRights('b@b.com', 'read').then(entries => {
            entries.should.have.length(5);
        });
    });
});

describe('entry creation and editions', function () {
    beforeEach(data);

    it('create a new entry', function() {
        return couch.createEntry('myid', 'a@a.com', {}).then(entryInfo => {
            entryInfo.should.have.property('id');
            entryInfo.should.have.property('rev');
            return couch.getEntryById('myid', 'a@a.com').then(entry => {
                entry.should.have.property('$content');
            });
        });
    });

    it('create two entries with same id but different users', function () {
        return couch.createEntry('myid', 'a@a.com').then(entryInfo => {
            return couch.createEntry('myid', 'b@b.com').then(entryInfo2 => {
                entryInfo.id.should.not.equal(entryInfo2.id);
            });
        });
    });

    it('create an entry for which the owner and id already exists', function () {
        return couch.createEntry('myid', 'a@a.com').then(entryInfo => {
            return couch.createEntry('myid', 'a@a.com').then(entryInfo2 => {
                entryInfo.id.should.equal(entryInfo2.id);
            });
        });
    });

    it('anonymous cannot insert a new entry', function () {
        return couch.insertEntry(constants.newEntry, 'anonymous').should.be.rejectedWith(/must be an email/);
    });

    it('entry should have content', function () {
        return couch.insertEntry({
            $id: 'D'
        }, 'z@z.com').should.be.rejectedWith(/has no content/);
    });

    it('update entry should reject if entry does not exist', function () {
        return couch.insertEntry({
            _id: 'new',
            $content: {}
        }, 'z@z.com', {isUpdate: true}).should.be.rejectedWith(/does not exist/);
    });

    it('update entry without _id should reject', function () {
        return couch.insertEntry({
            $content: {}
        }, 'z@z.com', {isUpdate: true}).should.be.rejectedWith(/should have an _id/);
    });

    it('create new entry that has an _id is not possible', function () {
        return couch.insertEntry({
            $content: {},
            _id: 'new'
        }, 'z@z.com', {isNew: true}).should.be.rejectedWith(/should not have _id/);
    });

    it('anybody not anonymous can insert a new entry (without _id)', function () {
        return couch.insertEntry(constants.newEntry, 'z@z.com').then(res => {
            res.action.should.equal('created');
            res.info.id.should.be.an.instanceOf(String);
            res.info.rev.should.be.an.instanceOf(String);
            return couch.getEntryById('C', 'z@z.com').should.be.fulfilled();
        });
    });

    it('anybody not anonymous can insert a new entry (with _id)', function () {
        return couch.insertEntry(constants.newEntryWithId, 'z@z.com').then(() => {
            return couch.getEntryById('D', 'z@z.com').should.eventually.be.an.instanceOf(Object);
        });
    });

    it('insert new entry with groups', function () {
        return couch.insertEntry(constants.newEntry, 'z@z.com', {groups: ['groupX', 'groupY']})
            .then(() => couch.getEntryById(constants.newEntry.$id, 'z@z.com'))
            .then(entry => {
                entry.$owners.should.have.length(3);
        });
    });

    it('should throw a conflict error', function () {
        return couch.getEntryById('A', 'b@b.com').then(doc => {
            return couch.insertEntry(doc, 'b@b.com').then(() => {
                return couch.insertEntry(doc, 'b@b.com').should.be.rejectedWith(/_rev differ/);
            });
        });
    });

    it('should modify an entry', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            doc.$content.abc = 'abc';
            return couch.insertEntry(doc, 'a@a.com').then(() => {
                return couch.getEntryById('A', 'a@a.com').then(entry => {
                    entry.$content.abc.should.equal('abc');
                });
            });
        });
    });

    it('should delete an entry by uuid', function () {
        return couch.getEntryById('A', 'a@a.com').then(doc => {
            return couch.deleteEntryByUuid(doc._id, 'a@a.com')
                .then(() => {
                    return couch.getEntryById('A', 'a@a.com').should.be.rejectedWith(/not found/);
                });
        });
    });

    it('should delete an entry by id', function () {
        return couch.deleteEntryById('A', 'a@a.com')
            .then(() => {
                return couch.getEntryById('A', 'a@a.com').should.be.rejectedWith(/not found/);
            });
    });

    it('should add group to entry', function () {
        return couch.addGroupToEntry('A', 'b@b.com', 'groupD')
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(doc => {
                doc.$owners.indexOf('groupD').should.be.above(0);
            });
    });

    it('Add existing group to entry', function() {
        return couch.addGroupToEntry('A', 'b@b.com', 'groupD')
            .then(() => couch.addGroupToEntry('A', 'b@b.com', 'groupD'))
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(entry => {
                let count = 0;
                for (let i=0; i<entry.$owners.length; i++) {
                    if (entry.$owners[i] === 'groupD') count++;
                }
                count.should.equal(1);
            });
    });

    it('Add existing group to entry (by uuid)', function() {
        return couch.getEntryById('A', 'b@b.com')
            .then(entry => {
                let uuid = entry._id;
                return couch.addGroupToEntryByUuid(uuid, 'b@b.com', 'anonymousRead')
                    .then(() => couch.addGroupToEntryByUuid(uuid, 'b@b.com', 'anonymousRead'))
                    .then(() => couch.getEntryById('A', 'b@b.com'))
                    .then(entry => {
                        let count = 0;
                        for (let i=0; i<entry.$owners.length; i++) {
                            if (entry.$owners[i] === 'anonymousRead') count++;
                        }
                        count.should.equal(1);
                    });
            });
    });

    it('should fail to add group to entry', function () {
        return couch.addGroupToEntry('A', 'a@a.com', 'groupC').should.be.rejectedWith(/unauthorized/);
    });

    it('should remove group from entry', function () {
        return couch.removeGroupFromEntry('A', 'b@b.com', 'groupB')
            .then(() => couch.getEntryById('A', 'b@b.com'))
            .then(doc => {
                doc.$owners.indexOf('groupB').should.be.equal(-1);
            });
    });

    it('should fail to remove group from entry', function () {
        return couch.removeGroupFromEntry('A', 'a@a.com', 'groupB').should.be.rejectedWith(/unauthorized/);
    });

    it('should fail to remove primary owner', function () {
        return couch.removeGroupFromEntry('A', 'b@b.com', 'b@b.com').should.be.rejectedWith(/cannot remove primary owner/);
    });
});
<|endoftext|>


<commit_before>module.exports = Swarm

var arrayRemove = require('unordered-array-remove')
var debug = require('debug')('bittorrent-tracker:swarm')
var LRU = require('lru')
var randomIterate = require('random-iterate')

// Regard this as the default implementation of an interface that you
// need to support when overriding Server.createSwarm() and Server.getSwarm()
function Swarm (infoHash, server) {
  var self = this
  self.infoHash = infoHash
  self.complete = 0
  self.incomplete = 0

  self.peers = new LRU({
    max: server.peersCacheLength || 1000,
    maxAge: server.peersCacheTtl || 20 * 60 * 1000 // 20 minutes
  })

  // When a peer is evicted from the LRU store, send a synthetic 'stopped' event
  // so the stats get updated correctly.
  self.peers.on('evict', function (data) {
    var peer = data.value
    var params = {
      type: peer.type,
      event: 'stopped',
      numwant: 0,
      peer_id: peer.peerId
    }
    self._onAnnounceStopped(params, peer, peer.peerId)

    // When a websocket peer is evicted, and it's not in any other swarms, close
    // the websocket to conserve server resources.
    if (peer.socket && peer.socket.infoHashes.length === 0) {
      try {
        peer.socket.close()
        peer.socket = null
      } catch (err) {}
    }
  })
}

Swarm.prototype.announce = function (params, cb) {
  var self = this
  var id = params.type === 'ws' ? params.peer_id : params.addr
  // Mark the source peer as recently used in cache
  var peer = self.peers.get(id)

  if (params.event === 'started') {
    self._onAnnounceStarted(params, peer, id)
  } else if (params.event === 'stopped') {
    self._onAnnounceStopped(params, peer, id)
  } else if (params.event === 'completed') {
    self._onAnnounceCompleted(params, peer, id)
  } else if (params.event === 'update') {
    self._onAnnounceUpdate(params, peer, id)
  } else {
    cb(new Error('invalid event'))
    return
  }
  cb(null, {
    complete: self.complete,
    incomplete: self.incomplete,
    peers: self._getPeers(params.numwant, params.peer_id, !!params.socket)
  })
}

Swarm.prototype.scrape = function (params, cb) {
  cb(null, {
    complete: this.complete,
    incomplete: this.incomplete
  })
}

Swarm.prototype._onAnnounceStarted = function (params, peer, id) {
  if (peer) {
    debug('unexpected `started` event from peer that is already in swarm')
    return this._onAnnounceUpdate(params, peer, id) // treat as an update
  }

  if (params.left === 0) this.complete += 1
  else this.incomplete += 1
  peer = this.peers.set(id, {
    type: params.type,
    complete: params.left === 0,
    peerId: params.peer_id, // as hex
    ip: params.ip,
    port: params.port,
    socket: params.socket // only websocket
  })
}

Swarm.prototype._onAnnounceStopped = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `stopped` event from peer that is not in swarm')
    return // do nothing
  }

  if (peer.complete) this.complete -= 1
  else this.incomplete -= 1

  // If it's a websocket, remove this swarm's infohash from the list of active
  // swarms that this peer is participating in.
  if (peer.socket && !peer.socket.destroyed) {
    var index = peer.socket.infoHashes.indexOf(this.infoHash)
    arrayRemove(peer.socket.infoHashes, index)
  }

  this.peers.remove(id)
}

Swarm.prototype._onAnnounceCompleted = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `completed` event from peer that is not in swarm')
    return this._onAnnounceStarted(params, peer, id) // treat as a start
  }
  if (peer.complete) {
    debug('unexpected `completed` event from peer that is already completed')
    return this._onAnnounceUpdate(params, peer, id) // treat as an update
  }

  this.complete += 1
  this.incomplete -= 1
  peer.complete = true
  this.peers.set(id, peer)
}

Swarm.prototype._onAnnounceUpdate = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `update` event from peer that is not in swarm')
    return this._onAnnounceStarted(params, peer, id) // treat as a start
  }

  if (!peer.complete && params.left === 0) {
    this.complete += 1
    this.incomplete -= 1
    peer.complete = true
  }
  this.peers.set(id, peer)
}

Swarm.prototype._getPeers = function (numwant, ownPeerId, isWebRTC) {
  var peers = []
  var ite = randomIterate(this.peers.keys)
  var peerId
  while ((peerId = ite()) && peers.length < numwant) {
    // Don't mark the peer as most recently used on announce
    var peer = this.peers.peek(peerId)
    if (!peer) continue
    if (isWebRTC && peer.peerId === ownPeerId) continue // don't send peer to itself
    if ((isWebRTC && peer.type !== 'ws') || (!isWebRTC && peer.type === 'ws')) continue // send proper peer type
    peers.push(peer)
  }
  return peers
}
<commit_msg>do not close socket even when it's not in other swarms<commit_after>module.exports = Swarm

var arrayRemove = require('unordered-array-remove')
var debug = require('debug')('bittorrent-tracker:swarm')
var LRU = require('lru')
var randomIterate = require('random-iterate')

// Regard this as the default implementation of an interface that you
// need to support when overriding Server.createSwarm() and Server.getSwarm()
function Swarm (infoHash, server) {
  var self = this
  self.infoHash = infoHash
  self.complete = 0
  self.incomplete = 0

  self.peers = new LRU({
    max: server.peersCacheLength || 1000,
    maxAge: server.peersCacheTtl || 20 * 60 * 1000 // 20 minutes
  })

  // When a peer is evicted from the LRU store, send a synthetic 'stopped' event
  // so the stats get updated correctly.
  self.peers.on('evict', function (data) {
    var peer = data.value
    var params = {
      type: peer.type,
      event: 'stopped',
      numwant: 0,
      peer_id: peer.peerId
    }
    self._onAnnounceStopped(params, peer, peer.peerId)
    peer.socket = null
  })
}

Swarm.prototype.announce = function (params, cb) {
  var self = this
  var id = params.type === 'ws' ? params.peer_id : params.addr
  // Mark the source peer as recently used in cache
  var peer = self.peers.get(id)

  if (params.event === 'started') {
    self._onAnnounceStarted(params, peer, id)
  } else if (params.event === 'stopped') {
    self._onAnnounceStopped(params, peer, id)
  } else if (params.event === 'completed') {
    self._onAnnounceCompleted(params, peer, id)
  } else if (params.event === 'update') {
    self._onAnnounceUpdate(params, peer, id)
  } else {
    cb(new Error('invalid event'))
    return
  }
  cb(null, {
    complete: self.complete,
    incomplete: self.incomplete,
    peers: self._getPeers(params.numwant, params.peer_id, !!params.socket)
  })
}

Swarm.prototype.scrape = function (params, cb) {
  cb(null, {
    complete: this.complete,
    incomplete: this.incomplete
  })
}

Swarm.prototype._onAnnounceStarted = function (params, peer, id) {
  if (peer) {
    debug('unexpected `started` event from peer that is already in swarm')
    return this._onAnnounceUpdate(params, peer, id) // treat as an update
  }

  if (params.left === 0) this.complete += 1
  else this.incomplete += 1
  peer = this.peers.set(id, {
    type: params.type,
    complete: params.left === 0,
    peerId: params.peer_id, // as hex
    ip: params.ip,
    port: params.port,
    socket: params.socket // only websocket
  })
}

Swarm.prototype._onAnnounceStopped = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `stopped` event from peer that is not in swarm')
    return // do nothing
  }

  if (peer.complete) this.complete -= 1
  else this.incomplete -= 1

  // If it's a websocket, remove this swarm's infohash from the list of active
  // swarms that this peer is participating in.
  if (peer.socket && !peer.socket.destroyed) {
    var index = peer.socket.infoHashes.indexOf(this.infoHash)
    arrayRemove(peer.socket.infoHashes, index)
  }

  this.peers.remove(id)
}

Swarm.prototype._onAnnounceCompleted = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `completed` event from peer that is not in swarm')
    return this._onAnnounceStarted(params, peer, id) // treat as a start
  }
  if (peer.complete) {
    debug('unexpected `completed` event from peer that is already completed')
    return this._onAnnounceUpdate(params, peer, id) // treat as an update
  }

  this.complete += 1
  this.incomplete -= 1
  peer.complete = true
  this.peers.set(id, peer)
}

Swarm.prototype._onAnnounceUpdate = function (params, peer, id) {
  if (!peer) {
    debug('unexpected `update` event from peer that is not in swarm')
    return this._onAnnounceStarted(params, peer, id) // treat as a start
  }

  if (!peer.complete && params.left === 0) {
    this.complete += 1
    this.incomplete -= 1
    peer.complete = true
  }
  this.peers.set(id, peer)
}

Swarm.prototype._getPeers = function (numwant, ownPeerId, isWebRTC) {
  var peers = []
  var ite = randomIterate(this.peers.keys)
  var peerId
  while ((peerId = ite()) && peers.length < numwant) {
    // Don't mark the peer as most recently used on announce
    var peer = this.peers.peek(peerId)
    if (!peer) continue
    if (isWebRTC && peer.peerId === ownPeerId) continue // don't send peer to itself
    if ((isWebRTC && peer.type !== 'ws') || (!isWebRTC && peer.type === 'ws')) continue // send proper peer type
    peers.push(peer)
  }
  return peers
}
<|endoftext|>


<commit_before>var zlib = require('zlib');

var STATUS_CODES = require('http').STATUS_CODES || {};
var TYPES = ['whistle', 'Fiddler'];

function getMethod(method) {
  if (typeof method !== 'string') {
    return 'GET';
  }
  return method.toUpperCase() || 'GET';
}

function getHeadersRaw(headers) {
  if (!headers) {
    return [];
  }
  delete headers.Host;
  return Object.keys(headers).map(function(name) {
    return name + ': ' + headers[name];
  });
}

function getReqRaw(req) {
  var headers = getHeadersRaw(req.headers);
  var url = String(req.url || '').replace(/^ws/, 'http');
  headers.unshift([getMethod(req.method), url, 'HTTP/1.1'].join(' '));
  return headers.join('\r\n') + '\r\n\r\n' + (req.body || '');
}

exports.getReqRaw = getReqRaw;

function getResRaw(res) {
  if (res.body && res.headers) {
    delete res.headers['content-encoding'];
    delete res.headers['transfer-encoding'];
  }
  var headers = getHeadersRaw(res.headers);
  headers.unshift(['HTTP/1.1', res.statusCode, res.statusMessage || STATUS_CODES[res.statusCode] || 'unknown'].join(' '));
  return headers.join('\r\n') + '\r\n\r\n' + (res.body || '');
}

exports.getResRaw = getResRaw;

var BODY_SEP = new Buffer('\r\n\r\n');

function getBodyOffset(raw) {
  var index = indexOfBuffer(raw, BODY_SEP);
  if (index !== -1) {
    return [index, index + 1];
  }
}
function indexOfBuffer(buf, subBuf, start) {
  start = start || 0;
  if (buf.indexOf) {
    return buf.indexOf(subBuf, start);
  }

  var subLen = subBuf.length;
  if (subLen) {
    for (var i = start, len = buf.length - subLen; i <= len; i++) {
      var j = 0;
      for (; j < subLen; j++) {
        if (subBuf[j] !== buf[i + j]) {
          break;
        }
      }
      if (j == subLen) {
        return i;
      }
    }
  }

  return -1;
}

function parseRawData(raw, cb) {
  var offset = getBodyOffset(raw);
  var body = '';
  if (offset) {
    body = raw.slice(offset[1]);
    raw = raw.slice(0, offset[0]);
  }
  raw = raw.toString();
  raw = raw.trim().split(/\r\n?|\n/g);
  var firstLine = raw.shift().split(/\s+/g);
  var headers = {};
  raw.forEach(function(line) {
    var index = line.indexOf(':');
    if (index === -1) {
      return;
    }
    var name = line.substring(0, index).trim();
    if (!name) {
      return;
    }
    var value = headers[name];
    var val = line.substring(index + 1).trim();
    if (value != null) {
      if (Array.isArray(value)) {
        value.push(val);
      } else {
        value = [value, val];
      }
    } else {
      value = val;
    }
    headers[name.toLowerCase()] = value;
  });

  //TODO: gzip, chunked
//  var contentEncoding = headers && headers['content-encoding'];
//  if (body && typeof contentEncoding === 'string') {
//    switch (contentEncoding.toLowerCase()) {
//    case 'gzip':
//      try {
//        body = zlib.gunzipSync(new Buffer(body));
//      } catch(e) {
//        body = e.stack;
//      }
//      break;
//    case 'deflate':
//      try {
//        body = zlib.deflateSync(new Buffer(body));
//      } catch(e) {}
//      break;
//    }
//  }
//
  process.nextTick(function() {
    cb({
      firstLine: firstLine,
      headers: headers,
      body: body ? body.toString() : ''
    });
  });
}

function getReq(raw, cb) {
  parseRawData(raw, function(raw) {
    cb(raw ? {
      method: raw.firstLine[0],
      httpVersion: '1.1',
      url: raw.firstLine[1],
      headers: raw.headers,
      body: raw.body
    } : null);
  });
}

exports.getReq = getReq;

function getRes(raw, cb) {
  parseRawData(raw, function(raw) {
    cb(raw ? {
      statusCode: raw.firstLine[1],
      httpVersion: '1.1',
      statusMessage: raw.firstLine[2],
      headers: raw.headers,
      body: raw.body
    } : {});
  });
}

exports.getRes = getRes;

function parseJSON(str) {
  try {
    return JSON.parse(str);
  } catch(e) {}
}

exports.parseJSON = parseJSON;

function padding(num) {
  return num < 10 ? '0' + num : num;
}

function getFilename(type) {
  if (!~TYPES.indexOf(type)) {
    type = 'whistle';
  }
  var date = new Date();
  var filename = [date.getFullYear(), padding(date.getMonth() + 1), padding(date.getDate())].join('-')
    + '_' + [padding(date.getHours()), padding(date.getMinutes()), padding(date.getSeconds())].join('-');
  return filename + (type === 'whistle' ? '.txt' : '.saz');
}

exports.getFilename = getFilename;

var ONE_MINUTE = 60 * 1000;
function toISOString(time) {
  var date = new Date();
  var offet = -date.getTimezoneOffset();
  time += offet * ONE_MINUTE;
  offet /= 60;
  time = time >= 0 ? new Date(time) : new Date();
  return time.toISOString().slice(0, -1) + '0000'
    + (offet >= 0 ? '+' : '-') + padding(Math.abs(offet)) + ':00';
}

exports.toISOString = toISOString;
<commit_msg>feat: Export the saz file<commit_after>var zlib = require('zlib');
var iconv = require('iconv-lite');

var STATUS_CODES = require('http').STATUS_CODES || {};
var TYPES = ['whistle', 'Fiddler'];

function getMethod(method) {
  if (typeof method !== 'string') {
    return 'GET';
  }
  return method.toUpperCase() || 'GET';
}

function getHeadersRaw(headers) {
  if (!headers) {
    return [];
  }
  delete headers.Host;
  return Object.keys(headers).map(function(name) {
    return name + ': ' + headers[name];
  });
}

function getReqRaw(req) {
  var headers = getHeadersRaw(req.headers);
  var url = String(req.url || '').replace(/^ws/, 'http');
  headers.unshift([getMethod(req.method), url, 'HTTP/1.1'].join(' '));
  return headers.join('\r\n') + '\r\n\r\n' + (req.body || '');
}

exports.getReqRaw = getReqRaw;

function getResRaw(res) {
  if (res.body && res.headers) {
    delete res.headers['content-encoding'];
    delete res.headers['transfer-encoding'];
  }
  var headers = getHeadersRaw(res.headers);
  headers.unshift(['HTTP/1.1', res.statusCode, res.statusMessage || STATUS_CODES[res.statusCode] || 'unknown'].join(' '));
  return headers.join('\r\n') + '\r\n\r\n' + (res.body || '');
}

exports.getResRaw = getResRaw;

var BODY_SEP = new Buffer('\r\n\r\n');

function getBodyOffset(raw) {
  var index = indexOfBuffer(raw, BODY_SEP);
  if (index !== -1) {
    return [index, index + 1];
  }
}
function indexOfBuffer(buf, subBuf, start) {
  start = start || 0;
  if (buf.indexOf) {
    return buf.indexOf(subBuf, start);
  }

  var subLen = subBuf.length;
  if (subLen) {
    for (var i = start, len = buf.length - subLen; i <= len; i++) {
      var j = 0;
      for (; j < subLen; j++) {
        if (subBuf[j] !== buf[i + j]) {
          break;
        }
      }
      if (j == subLen) {
        return i;
      }
    }
  }

  return -1;
}

function parseRawData(raw, cb) {
  var offset = getBodyOffset(raw);
  var body = '';
  if (offset) {
    body = raw.slice(offset[1]);
    raw = raw.slice(0, offset[0]);
  }
  raw = raw.toString();
  raw = raw.trim().split(/\r\n?|\n/g);
  var firstLine = raw.shift().split(/\s+/g);
  var headers = {};
  raw.forEach(function(line) {
    var index = line.indexOf(':');
    if (index === -1) {
      return;
    }
    var name = line.substring(0, index).trim();
    if (!name) {
      return;
    }
    var value = headers[name];
    var val = line.substring(index + 1).trim();
    if (value != null) {
      if (Array.isArray(value)) {
        value.push(val);
      } else {
        value = [value, val];
      }
    } else {
      value = val;
    }
    headers[name.toLowerCase()] = value;
  });

  //TODO: gzip, chunked
//  var contentEncoding = headers && headers['content-encoding'];
//  if (body && typeof contentEncoding === 'string') {
//    switch (contentEncoding.toLowerCase()) {
//    case 'gzip':
//      try {
//        body = zlib.gunzipSync(body);
//      } catch(e) {
//        body = e.stack;
//      }
//      break;
//    case 'deflate':
//      try {
//        body = zlib.deflateSync(body);
//      } catch(e) {}
//      break;
//    }
//  }
  if (body) {
    var charset = headers && headers['content-type'];
    if (typeof charset === 'string') {
      charset = charset.split(';')[1] || '';
    } else {
      charset = '';
    }
    charset = charset.trim();
    if (charset) {
      try {
        body = iconv.decode(body, charset);
      } catch(e) {}
      body = body.toString();
    } else {
      var str = body.toString();
      if (str.indexOf('�') != -1) {
        body = iconv.decode(body, 'gbk');
      } else {
        body = str;
      }
    }
  }

  process.nextTick(function() {
    cb({
      firstLine: firstLine,
      headers: headers,
      body: body
    });
  });
}

function getReq(raw, cb) {
  parseRawData(raw, function(raw) {
    cb(raw ? {
      method: raw.firstLine[0],
      httpVersion: '1.1',
      url: raw.firstLine[1],
      headers: raw.headers,
      body: raw.body
    } : null);
  });
}

exports.getReq = getReq;

function getRes(raw, cb) {
  parseRawData(raw, function(raw) {
    cb(raw ? {
      statusCode: raw.firstLine[1],
      httpVersion: '1.1',
      statusMessage: raw.firstLine[2],
      headers: raw.headers,
      body: raw.body
    } : {});
  });
}

exports.getRes = getRes;

function parseJSON(str) {
  try {
    return JSON.parse(str);
  } catch(e) {}
}

exports.parseJSON = parseJSON;

function padding(num) {
  return num < 10 ? '0' + num : num;
}

function getFilename(type) {
  if (!~TYPES.indexOf(type)) {
    type = 'whistle';
  }
  var date = new Date();
  var filename = [date.getFullYear(), padding(date.getMonth() + 1), padding(date.getDate())].join('-')
    + '_' + [padding(date.getHours()), padding(date.getMinutes()), padding(date.getSeconds())].join('-');
  return filename + (type === 'whistle' ? '.txt' : '.saz');
}

exports.getFilename = getFilename;

var ONE_MINUTE = 60 * 1000;
function toISOString(time) {
  var date = new Date();
  var offet = -date.getTimezoneOffset();
  time += offet * ONE_MINUTE;
  offet /= 60;
  time = time >= 0 ? new Date(time) : new Date();
  return time.toISOString().slice(0, -1) + '0000'
    + (offet >= 0 ? '+' : '-') + padding(Math.abs(offet)) + ':00';
}

exports.toISOString = toISOString;
<|endoftext|>


<commit_before>"use strict";
/*global describe, it, assert, beforeEach*/

describe("fs_ms", function () {

    if ("wscript" !== gpf.host()) {
        return; // Skip
    }

    var
        gpfI = gpf.interfaces,
        iWScriptFs;

    beforeEach(function () {
        iWScriptFs = new gpf.fs.WScriptFileStorage();
    });

    describe("gpf.fs.WScriptFileStorage", function () {

        it("implements IFileStorage", function () {
            assert(gpfI.isImplementedBy(iWScriptFs, gpfI.IFileStorage));
        });

    });

});<commit_msg>Trying to save a binary file<commit_after>"use strict";
/*global describe, it, assert, beforeEach*/

describe("fs_ms", function () {

    if ("wscript" !== gpf.host()) {
        return; // Skip
    }

    var
        gpfI = gpf.interfaces,
        iWScriptFs;

    beforeEach(function () {
        iWScriptFs = new gpf.fs.WScriptFileStorage();
    });

    describe("gpf.fs.WScriptFileStorage", function () {

        it("implements IFileStorage", function () {
            assert(gpfI.isImplementedBy(iWScriptFs, gpfI.IFileStorage));
        });

        it("saves binary files", function (done) {
            iWScriptFs.writeAsBinaryStream("tmp/fs.tmp", function (event) {
                assert(gpf.events.EVENT_READY === event.type);
                var wStream = event.get("stream");
                wStream.write([1, 2, 3], function (event) {
                    assert(gpf.events.EVENT_READY === event.type);
                    iWScriptFs.close(wStream);
                    done();
                });
            });
        });

    });

});<|endoftext|>


<commit_before>var util = require('util');

var CRM = exports.CRM = function (Client) {
  this.client = Client;

  return this;
};

// ---- BANK ACCOUNT BEGIN ---

/**
 * Get back account
 * @param  {String}   accountId Account ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.getBankAccount = function(accountId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts', 'GET', params, null, callback);
};

/**
 * Alter a bank account
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveBankAccount = function(bankAccountId, userData, division, callback) {

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts(guid\'' + bankAccountId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create a bank account
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.createBankAccount = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts', 'POST', null, userData, callback);
};

// ---- BANK ACCOUNT END ---

// ---- USER ACCOUNT BEGIN ---

/**
 * Get a user account
 * @param {String}   accountId Account ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getAccount = function(accountId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts', 'GET', params, null, callback);
};

/**
 * Alter a user account
 * @param  {String}   accountId Account ID
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveAccount = function(accountId, userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts(guid\'' + accountId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create an account
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.createAccount = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts', 'POST', null, userData, callback);
};

// ---- USER ACCOUNT END ---

// ---- DIRECTDEBITMANDATORY ATTACHMENTS BEGIN ---

/**
 * Get a user account
 * @param {String}   accountId Account ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.listDirectDebitMandate = function(accountId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Get a user account
 * @param {String}   mandateId Mandate ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getDirectDebitMandateFromUser = function(userId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ userId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Get a user account
 * @param {String}   mandateId Mandate ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getDirectDebitMandate = function(mandateId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ mandateId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Alter a user account
 * @param  {String}   mandateId Mandate ID
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveDirectDebitMandate = function(mandateId, userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates(guid\'' + mandateId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create an account
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.createDirectDebitMandate = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'POST', null, userData, callback);
};

/**
 * Create an account
 * @param  {String}   mandateId Mandate ID
 */
CRM.prototype.deleteDirectDebitMandate = function(mandateId, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates(guid\'' + mandateId + '\')', 'DELETE', null, userData, callback);
};

// ---- DIRECTDEBITMANDATORY ATTACHMENTS END ---

// ---- DOCUMENT ATTACHMENTS BEGIN ---

/**
 * Get document attachments
 * @param  {String}   documentId Document ID
 * @param  {Integer}   division   Division ID
 * @param  {Function} callback   Callback
 */
CRM.prototype.getDocumentAttachments = function(documentId, division, callback) {
  var params = {
    $filter: 'Document eq guid\''+ documentId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/documents/DocumentAttachments', 'GET', params, null, callback);
};

/**
 * Get document attachment
 * @param  {String}   documentId Document ID
 * @param  {Integer}   division   Division ID
 * @param  {Function} callback   Callback
 */
CRM.prototype.getDocumentAttachment = function(documentId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ documentId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/documents/DocumentAttachments', 'GET', params, null, callback);
};

// ---- DOCUMENT ATTACHMENTS END ---
<commit_msg>Added $top: 1.<commit_after>var util = require('util');

var CRM = exports.CRM = function (Client) {
  this.client = Client;

  return this;
};

// ---- BANK ACCOUNT BEGIN ---

/**
 * Get back account
 * @param  {String}   accountId Account ID
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.getBankAccount = function(accountId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts', 'GET', params, null, callback);
};

/**
 * Alter a bank account
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveBankAccount = function(bankAccountId, userData, division, callback) {

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts(guid\'' + bankAccountId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create a bank account
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.createBankAccount = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/BankAccounts', 'POST', null, userData, callback);
};

// ---- BANK ACCOUNT END ---

// ---- USER ACCOUNT BEGIN ---

/**
 * Get a user account
 * @param {String}   accountId Account ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getAccount = function(accountId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts', 'GET', params, null, callback);
};

/**
 * Alter a user account
 * @param  {String}   accountId Account ID
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveAccount = function(accountId, userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts(guid\'' + accountId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create an account
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.createAccount = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/crm/Accounts', 'POST', null, userData, callback);
};

// ---- USER ACCOUNT END ---

// ---- DIRECTDEBITMANDATORY ATTACHMENTS BEGIN ---

/**
 * Get a user account
 * @param {String}   accountId Account ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.listDirectDebitMandate = function(accountId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ accountId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Get a user account
 * @param {String}   mandateId Mandate ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getDirectDebitMandateFromUser = function(userId, division, callback) {
  var params = {
    $filter: 'Account eq guid\''+ userId +'\'',
    $top: 1
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Get a user account
 * @param {String}   mandateId Mandate ID
 * @param {Integer}  division  Division ID
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.getDirectDebitMandate = function(mandateId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ mandateId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'GET', params, null, callback);
};

/**
 * Alter a user account
 * @param  {String}   mandateId Mandate ID
 * @param  {String}   userData  JSON Object with content saved
 * @param  {Integer}  division  Division ID
 * @param  {Function} callback  Callback
 */
CRM.prototype.saveDirectDebitMandate = function(mandateId, userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates(guid\'' + mandateId + '\')', 'PUT', null, userData, callback);
};

/**
 * Create an account
 * @param {Function} callback gets called after request is complete
 */
CRM.prototype.createDirectDebitMandate = function(userData, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates', 'POST', null, userData, callback);
};

/**
 * Create an account
 * @param  {String}   mandateId Mandate ID
 */
CRM.prototype.deleteDirectDebitMandate = function(mandateId, division, callback) {
  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/cashflow/DirectDebitMandates(guid\'' + mandateId + '\')', 'DELETE', null, userData, callback);
};

// ---- DIRECTDEBITMANDATORY ATTACHMENTS END ---

// ---- DOCUMENT ATTACHMENTS BEGIN ---

/**
 * Get document attachments
 * @param  {String}   documentId Document ID
 * @param  {Integer}   division   Division ID
 * @param  {Function} callback   Callback
 */
CRM.prototype.getDocumentAttachments = function(documentId, division, callback) {
  var params = {
    $filter: 'Document eq guid\''+ documentId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/documents/DocumentAttachments', 'GET', params, null, callback);
};

/**
 * Get document attachment
 * @param  {String}   documentId Document ID
 * @param  {Integer}   division   Division ID
 * @param  {Function} callback   Callback
 */
CRM.prototype.getDocumentAttachment = function(documentId, division, callback) {
  var params = {
    $filter: 'ID eq guid\''+ documentId +'\''
  };

  if(typeof division === 'function') {
    callback = division;
    division = this.client.division;
  }

  this.client.sendRequest('/v1/' + division + '/documents/DocumentAttachments', 'GET', params, null, callback);
};

// ---- DOCUMENT ATTACHMENTS END ---
<|endoftext|>