<commit_before>'use strict';

require('./lib/test-env.js');

const awsMocks = require('./lib/aws-mocks.js');
const expect = require('chai').expect;
const request = require('superagent');
//const debug = require('debug')('wheatlessinv2:pic-route-test');

const User = require('../model/user.js');
const Biz  = require('../model/biz.js');
const Pic  = require('../model/pic.js');

require('../server.js');

const mockUser = require('./lib/mock-user.js');

const url = `http://localhost:${process.env.PORT}`;

var picId0, picId1;

describe('Pic Routes', function() {
  before( done => {
    mockUser().then( user => {
      this.user = user;
      done();
    })
    .catch(done);
  });
  before( done => {
    new Biz({
      userId: this.user._id,
      name: 'Example Biz',
      EIN: '12-3456789',
      menuPics: []
    }).save()
    .then( biz => {
      this.biz = biz;
      done();
    })
    .catch(done);
  });
  // before( done => {
  //   new Menu({
  //     bizId: this.biz._id
  //   }).save()
  //   .then( menu => {
  //     this.menu = menu;
  //     done();
  //   })
  //   .catch(done);
  // }); //before
  after( () => {
    return Promise.all([
      User.remove({}),
      Biz.remove({}),
      //Menu.remove({}),
      Pic.remove({}),
      // Promise.resolve(del(`${dataDir}/*`))
    ]);
  });

  describe('POST /api/biz/:bizId/pic', () => {
    describe('with a bizId that does not exist', () => {
      it('should return a 404', done => {
        request.post(`${url}/api/biz/5876cb5ea93f1ce1001bb490/pic`)
        // request.post(`${url}/api/menu/not_a_valid_id/pic`)
        .set({ Authorization: `Bearer ${this.user.token}` })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          expect(res.status).to.equal(404);
          done();
        });
      });
    }); //menuId does not exist

    describe('with a bizId that is bogus', () => {
      it('should return a 404', done => {
        request.post(`${url}/api/biz/bogus/pic`)
        // request.post(`${url}/api/menu/not_a_valid_id/pic`)
        .set({ Authorization: `Bearer ${this.user.token}` })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          expect(res.status).to.equal(404);
          done();
        });
      });
    }); //bogus menuId

    describe('with a valid bizId and pic', () => {
      it('should return a pic array', done => {
        request.post(`${url}/api/biz/${this.biz._id}/pic`)
        .set({
          Authorization: `Bearer ${this.user.token}`
        })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          console.log('res.body:', res.body);
          expect(res.status).to.equal(200);
          picId0 = res.body._id;
          //expect(res.body.bizId).to.equal(this.biz._id.toString());
          expect(res.body[0].imageURI).to.equal(awsMocks.uploadMock.Location);
          //expect(res.body.objectKey).to.equal(awsMocks.uploadMock.Key);
          Biz.findById(this.biz._id).populate('menuPics').then( foundBiz => {
            console.log('foundBiz:', foundBiz);
            expect(foundBiz.menuPics[0].imageURI.toString()).to.equal(res.body[0].imageURI);
          })
          .then(done)
          .catch(err => console.log(err));
        });
      });
    }); // valid menuId and pic

    describe('with a valid bizId and a second pic', () => {
      it('should return a list of pic objects', done => {
        awsMocks.randomize();
        request.post(`${url}/api/biz/${this.biz._id}/pic`)
        .set({
          Authorization: `Bearer ${this.user.token}`
        })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          console.log('res.body (2nd):', res.body);
          expect(res.status).to.equal(200);
          picId1 = res.body._id;
          //expect(res.body.bizId).to.equal(this.biz._id.toString());
          expect(res.body[1].imageURI).to.equal(awsMocks.uploadMock.Location);
          //expect(res.body.objectKey).to.equal(awsMocks.uploadMock.Key);

          Biz.findById(this.biz._id).populate('menuPics', 'imageURI').then( foundBiz => {
            expect(foundBiz.menuPics[0]._id.toString()).to.equal(picId0);
            expect(foundBiz.menuPics[1]._id.toString()).to.equal(picId1);
          })
          .then(done)
          .catch(err => {
            console.log(err);
            done();
          });
        });
      });
    }); // valid menuId and second pic

  }); // POST /api/menu/:menuId/pic

  describe('DELETE: /api/pic/:picId', () => {
    describe('with invalid picId and valid token', () => {
      it('should return res status 404', done => {
        request.delete(`${url}/api/pic/12345678901234`)
       .set({
         Authorization: `Bearer ${this.user.token}`
       })
       .end( (err, res) => {
         expect(res.status).to.equal(404);
         done();
       });
      });
    });

    describe('with valid picId and valid token', () => {
      it('should return res status 200', done => {
        request.delete(`${url}/api/pic/${picId0}`)
       .set({
         Authorization: `Bearer ${this.user.token}`
       })
       .end( (err, res) => {
         if(err) return done(err);
         expect(res.status).to.equal(200);
         done();
       });
      });
    });
  });
});
<commit_msg>Update pic-route-test.js<commit_after>'use strict';

require('./lib/test-env.js');

const awsMocks = require('./lib/aws-mocks.js');
const expect = require('chai').expect;
const request = require('superagent');
//const debug = require('debug')('wheatlessinv2:pic-route-test');

const User = require('../model/user.js');
const Biz  = require('../model/biz.js');
const Pic  = require('../model/pic.js');

require('../server.js');

const mockUser = require('./lib/mock-user.js');

const url = `http://localhost:${process.env.PORT}`;

var picId0, picId1;

describe('Pic Routes', function() {
  before( done => {
    mockUser().then( user => {
      this.user = user;
      done();
    })
    .catch(done);
  });
  before( done => {
    new Biz({
      userId: this.user._id,
      name: 'Example Biz',
      EIN: '12-3456789',
      menuPics: []
    }).save()
    .then( biz => {
      this.biz = biz;
      done();
    })
    .catch(done);
  });
  // before( done => {
  //   new Menu({
  //     bizId: this.biz._id
  //   }).save()
  //   .then( menu => {
  //     this.menu = menu;
  //     done();
  //   })
  //   .catch(done);
  // }); //before
  after( () => {
    return Promise.all([
      User.remove({}),
      Biz.remove({}),
      //Menu.remove({}),
      Pic.remove({}),
      // Promise.resolve(del(`${dataDir}/*`))
    ]);
  });

  describe('POST /api/biz/:bizId/pic', () => {
    describe('with a bizId that does not exist', () => {
      it('should return a 404', done => {
        request.post(`${url}/api/biz/5876cb5ea93f1ce1001bb490/pic`)
        // request.post(`${url}/api/menu/not_a_valid_id/pic`)
        .set({ Authorization: `Bearer ${this.user.token}` })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          expect(res.status).to.equal(404);
          done();
        });
      });
    }); //menuId does not exist

    describe('with a bizId that is bogus', () => {
      it('should return a 404', done => {
        request.post(`${url}/api/biz/bogus/pic`)
        // request.post(`${url}/api/menu/not_a_valid_id/pic`)
        .set({ Authorization: `Bearer ${this.user.token}` })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          expect(res.status).to.equal(404);
          done();
        });
      });
    }); //bogus menuId

    describe('with a valid bizId and pic', () => {
      it('should return a pic array', done => {
        request.post(`${url}/api/biz/${this.biz._id}/pic`)
        .set({
          Authorization: `Bearer ${this.user.token}`
        })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          console.log('res.body:', res.body);
          expect(res.status).to.equal(200);
          picId0 = res.body._id;
          //expect(res.body.bizId).to.equal(this.biz._id.toString());
          expect(res.body[0].imageURI).to.equal(awsMocks.uploadMock.Location);
          //expect(res.body.objectKey).to.equal(awsMocks.uploadMock.Key);
          Biz.findById(this.biz._id).populate('menuPics').then( foundBiz => {
            console.log('foundBiz:', foundBiz);
            expect(foundBiz.menuPics[0].imageURI.toString()).to.equal(res.body[0].imageURI);
          })
          .then(done)
          .catch(err => console.log(err));
        });
      });
    }); // valid menuId and pic

    describe('with a valid bizId and a second pic', () => {
      it('should return a list of pic objects', done => {
        awsMocks.randomize();
        request.post(`${url}/api/biz/${this.biz._id}/pic`)
        .set({
          Authorization: `Bearer ${this.user.token}`
        })
        .attach('image', `${__dirname}/data/pic.jpg`)
        .end( (err, res) => {
          console.log('res.body (2nd):', res.body);
          expect(res.status).to.equal(200);
          picId1 = res.body._id;
          //expect(res.body.bizId).to.equal(this.biz._id.toString());
          expect(res.body[1].imageURI).to.equal(awsMocks.uploadMock.Location);
          //expect(res.body.objectKey).to.equal(awsMocks.uploadMock.Key);

          Biz.findById(this.biz._id).populate('menuPics', 'imageURI').then( foundBiz => {
            expect(foundBiz.menuPics[0]._id.toString()).to.equal(picId0);
            expect(foundBiz.menuPics[1]._id.toString()).to.equal(picId1);
          })
          .then(done)
          .catch(err => {
            console.log(err);
            done();
          });
        });
      });
    }); // valid menuId and second pic

  }); // POST /api/menu/:menuId/pic

  describe.skip('DELETE: /api/pic/:picId', () => {
    describe('with invalid picId and valid token', () => {
      it('should return res status 404', done => {
        request.delete(`${url}/api/pic/12345678901234`)
       .set({
         Authorization: `Bearer ${this.user.token}`
       })
       .end( (err, res) => {
         expect(res.status).to.equal(404);
         done();
       });
      });
    });

    describe('with valid picId and valid token', () => {
      it('should return res status 200', done => {
        request.delete(`${url}/api/pic/${picId0}`)
       .set({
         Authorization: `Bearer ${this.user.token}`
       })
       .end( (err, res) => {
         if(err) return done(err);
         expect(res.status).to.equal(200);
         done();
       });
      });
    });
  });
});
<|endoftext|>


<commit_before>/* eslint-env mocha */
'use strict';

require('should');
const sinon = require('sinon');
const AWS = require('aws-sdk');
const generateConsulStub = require('./utils/consul-stub');

require('should-sinon');

const PluginManager = require('../lib/plugin-manager');
const StringTemplate = require('../lib/string-template');

const DEFAULT_INTERVAL = 60000;

const fakeIndexResponse = {
  ETag: 'ThisIsACoolEtag',
  Body: new Buffer(JSON.stringify(require('./data/s3/index')))
};

/* eslint-disable func-names, max-nested-callbacks */
describe('Plugin manager', function () {
  const unknownEndpointErr = new Error('UnknownEndpoint');
  const _S3 = AWS.S3;
  let manager,
      storage;

  beforeEach(function () {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
    const consul = generateConsulStub();

    storage = new (require('../lib/storage'))();
    manager = new PluginManager(storage, {
      interval: DEFAULT_INTERVAL,
      bucket: 'foo',
      path: 'bar',
      metadataHost: '127.0.0.1:8080',
      consul
    });
  });

  afterEach(function () {
    manager.shutdown();

    // Unregister listeners so tests error out cleanly.
    manager.removeAllListeners('error');
    manager.removeAllListeners('sources-registered');

    manager = null;
    storage = null;
    AWS.S3 = _S3;
  });

  it('fetches the index from S3 and gets a list of sources', function (done) {
    manager.once('sources-generated', (sources) => {
      const sourceObjs = sources.map((s) => {
        return {name: s.name, type: s.type};
      });

      sourceObjs.should.eql([{name: 'global', type: 's3'}, {name: 'account', type: 's3'}, {name: 'ami', type: 's3'}]);
      done();
    });

    manager.initialize();
  });

  it('correctly merges data from the metadata plugin with stringtemplate strings from the index', function (done) {
    manager.once('sources-generated', (sources) => {
      const amiPath = manager.index.properties[2].parameters.path;
      const mergedAmiPath = sources[2].parameters.path;
      const t = StringTemplate.coerce(amiPath, manager.metadata.properties);

      t.should.equal(mergedAmiPath);
      done();
    });

    manager.initialize();
  });

  it('handles being presented with data that will be parsed into a badly interpolated StringTemplate', function (done) {
    const badIndex = require('./data/s3/index');

    badIndex.sources[2].parameters.path = '{{ instance:foo-bar }}.json';
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: 'ThisIsACoolEtag',
      Body: new Buffer(JSON.stringify(badIndex))
    });

    manager.once('error', () => {
      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
    });

    manager.once('sources-generated', (sources) => {
      const sourceObjs = sources.map((s) => {
        return {name: s.name, type: s.type};
      });

      sourceObjs.should.eql([{name: 'global', type: 's3'}, {name: 'account', type: 's3'}, {name: 'ami', type: 's3'}]);
      done();
    });

    manager.index.interval = 1;
    manager.initialize();
  });

  it('registers plugins with the storage engine', function (done) {
    manager.once('sources-registered', () => {
      const sourceNames = storage.sources.map((el) => el.name); // eslint-disable-line max-nested-callbacks

      sourceNames.should.eql(['s3-foo-global.json', 's3-foo-account/12345.json', 's3-foo-ami-4aface7a.json']);
      done();
    });

    manager.initialize();
  });

  it('sets event handlers for plugin events', function (done) {
    manager.once('source-instantiated', (instance) => {
      const updateSpy = sinon.spy(instance, '_update');

      instance.once('update', () => {
        updateSpy.should.be.called();
        done();
      });
    });

    manager.initialize();
  });

  it('handles source types that have not been implemented', function (done) {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: 'ThisIsACoolEtag',
      Body: new Buffer(JSON.stringify({
        version: 1.0,
        sources: [
          {name: 'global', type: 's3', parameters: {path: 'global.json'}},
          {name: 'global', type: 'someBrandNewSourceType', parameters: {path: 'global.json'}}
        ]
      }))
    });

    manager.once('error', (err) => {
      const status = manager.status();

      err.message.should.equal('Source type someBrandNewSourceType not implemented');
      status.ok.should.be.false();
      done();
    });

    manager.initialize();
  });

  it('retries Metadata source until it succeeds if the Metadata source fails', function (done) {
    function onConnectionRefused(err) {
      if (err.code === 'ECONNREFUSED') {
        manager.removeListener('error', onConnectionRefused);

        const metadataStatus = manager.metadata.status();
        const managerStatus = manager.status();

        managerStatus.running.should.be.true();
        managerStatus.ok.should.be.false();
        metadataStatus.ok.should.be.false();
        metadataStatus.running.should.be.true();

        manager.metadata.service.host = '127.0.0.1:8080';
      }
    }

    manager.on('error', onConnectionRefused);

    manager.once('sources-generated', (sources) => {
      const status = manager.status();

      status.running.should.be.true();
      status.ok.should.be.true();
      sources.length.should.equal(3); // eslint-disable-line rapid7/static-magic-numbers
      done();
    });

    manager.metadata.service.host = '0.0.0.0';
    manager.metadata.interval = 1;
    manager.initialize();
  });

  it('retries S3 source until it succeeds if the S3 source fails', function (done) {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, unknownEndpointErr, null);

    function onUnknownEndpoint(err) {
      if (err.message === 'UnknownEndpoint') {
        manager.removeListener('error', onUnknownEndpoint);

        const indexStatus = manager.index.status();
        const managerStatus = manager.status();

        managerStatus.running.should.be.true();
        managerStatus.ok.should.be.false();
        indexStatus.ok.should.be.false();
        indexStatus.running.should.be.true();

        AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
      }
    }

    manager.on('error', onUnknownEndpoint);

    manager.once('sources-generated', (sources) => {
      const status = manager.status();

      status.running.should.be.true();
      status.ok.should.be.true();
      sources.length.should.equal(3); // eslint-disable-line rapid7/static-magic-numbers
      done();
    });

    manager.index.interval = 1;
    manager.initialize();
  });

  // SECOND PULL REQUEST
  /* it('rebuilds sources when the index is updated', function (done) {
    // TODO: Rewrite this test
    const updatedSource = {
      ETag: 'ThisIsADifferentETag',
      Body: new Buffer(JSON.stringify({
        version: 1.0,
        sources: [{name: 'global', type: 's3', parameters: {path: 'global.json'}}]
      }))
    };
    let sources = [];

    manager.on('sources-registered', (storageSources) => {
      if (sources.length === 0) {
        sources = storageSources;
        AWS.S3.prototype.getObject = this.stub().callsArgWith(1, null, updatedSource);
      } else {
        done();
      }
      manager.update();
    });

    manager.index.on('update', () => {
      console.log(`${Date.now()}: index updated`);
    });

    manager.initialize();
  }); */

  it('updates the storage engine when the index removes a source plugin', function (done) {
    let s3Sources = [{
      name: 'global', type: 's3', parameters: {path: 'global.json'}
    }, {
      name: 'local', type: 's3', parameters: {path: 'local.json'}
    }];

    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: `v${s3Sources.length}`,
      Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
    });

    function removeS3Source(name) {
      s3Sources = s3Sources.filter((source) => {
        return source.name !== name;
      });

      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
        ETag: `v${s3Sources.length}`,
        Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
      });
    }

    function onSourcesRegistered(storageSources) {
      if (storageSources.length === 2) {
        storageSources.map((source) => {
          return source.name;
        }).sort().should.eql(['s3-foo-global.json', 's3-foo-local.json']);
        removeS3Source('local');
      }

      if (storageSources.length === 1) {
        manager.removeListener('sources-registered', onSourcesRegistered);
        storageSources.map((source) => {
          return source.name;
        }).sort().should.eql(['s3-foo-global.json']);
        done();
      }
    }

    manager.on('sources-registered', onSourcesRegistered);
    manager.index.interval = 1;
    manager.initialize();
  });

  it('updates the storage engine when the index adds a source plugin', function (done) {
    const s3Sources = [];

    function addS3Source(name) {
      s3Sources.push({
        name, type: 's3', parameters: {path: `${name}.json`}
      });

      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
        ETag: `v${s3Sources.length}`,
        Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
      });
    }

    function onSourcesRegistered(storageSources) {
      if (storageSources.length === 1) {
        storageSources.map((source) => {
          return source.name;
        }).should.containEql('s3-foo-global.json');
        addS3Source('local');
      }

      if (storageSources.length === 2) {
        manager.removeListener('sources-registered', onSourcesRegistered);
        storageSources.map((source) => {
          return source.name;
        }).should.containEql('s3-foo-local.json');
        done();
      }
    }

    addS3Source('global');
    manager.on('sources-registered', onSourcesRegistered);
    manager.index.interval = 1;
    manager.initialize();
  });

  it('exposes an error from source plugins when one occurs but continues running', function (done) {
    function onUnknownEndpoint(err) {
      if (err.message === 'UnknownEndpoint') {
        manager.removeListener('error', onUnknownEndpoint);

        manager.status().running.should.be.true();
        done();
      }
    }

    manager.on('error', onUnknownEndpoint);

    manager.once('source-instantiated', () => {
      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, unknownEndpointErr, null);
    });

    manager.initialize();
  });
});

/* eslint-enable func-names */
<commit_msg>Works out final PluginManager test for source registration.<commit_after>/* eslint-env mocha */
'use strict';

require('should');
const sinon = require('sinon');
const AWS = require('aws-sdk');
const generateConsulStub = require('./utils/consul-stub');

require('should-sinon');

const PluginManager = require('../lib/plugin-manager');
const StringTemplate = require('../lib/string-template');

const DEFAULT_INTERVAL = 60000;

const fakeIndexResponse = {
  ETag: 'ThisIsACoolEtag',
  Body: new Buffer(JSON.stringify(require('./data/s3/index')))
};

/* eslint-disable func-names, max-nested-callbacks */
describe('Plugin manager', function () {
  const unknownEndpointErr = new Error('UnknownEndpoint');
  const _S3 = AWS.S3;
  let manager,
      storage;

  beforeEach(function () {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
    const consul = generateConsulStub();

    storage = new (require('../lib/storage'))();
    manager = new PluginManager(storage, {
      interval: DEFAULT_INTERVAL,
      bucket: 'foo',
      path: 'bar',
      metadataHost: '127.0.0.1:8080',
      consul
    });
  });

  afterEach(function () {
    manager.shutdown();

    // Unregister listeners so tests error out cleanly.
    manager.removeAllListeners('error');
    manager.removeAllListeners('sources-registered');

    manager = null;
    storage = null;
    AWS.S3 = _S3;
  });

  it('fetches the index from S3 and gets a list of sources', function (done) {
    manager.once('sources-generated', (sources) => {
      const sourceObjs = sources.map((s) => {
        return {name: s.name, type: s.type};
      });

      sourceObjs.should.eql([{name: 'global', type: 's3'}, {name: 'account', type: 's3'}, {name: 'ami', type: 's3'}]);
      done();
    });

    manager.initialize();
  });

  it('correctly merges data from the metadata plugin with stringtemplate strings from the index', function (done) {
    manager.once('sources-generated', (sources) => {
      const amiPath = manager.index.properties[2].parameters.path;
      const mergedAmiPath = sources[2].parameters.path;
      const t = StringTemplate.coerce(amiPath, manager.metadata.properties);

      t.should.equal(mergedAmiPath);
      done();
    });

    manager.initialize();
  });

  it('handles being presented with data that will be parsed into a badly interpolated StringTemplate', function (done) {
    const badIndex = require('./data/s3/index');

    badIndex.sources[2].parameters.path = '{{ instance:foo-bar }}.json';
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: 'ThisIsACoolEtag',
      Body: new Buffer(JSON.stringify(badIndex))
    });

    manager.once('error', () => {
      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
    });

    manager.once('sources-generated', (sources) => {
      const sourceObjs = sources.map((s) => {
        return {name: s.name, type: s.type};
      });

      sourceObjs.should.eql([{name: 'global', type: 's3'}, {name: 'account', type: 's3'}, {name: 'ami', type: 's3'}]);
      done();
    });

    manager.index.interval = 1;
    manager.initialize();
  });

  it('registers plugins with the storage engine', function (done) {
    manager.once('sources-registered', () => {
      const sourceNames = storage.sources.map((el) => el.name); // eslint-disable-line max-nested-callbacks

      sourceNames.should.eql(['s3-foo-global.json', 's3-foo-account/12345.json', 's3-foo-ami-4aface7a.json']);
      done();
    });

    manager.initialize();
  });

  it('sets event handlers for plugin events', function (done) {
    manager.once('source-instantiated', (instance) => {
      const updateSpy = sinon.spy(instance, '_update');

      instance.once('update', () => {
        updateSpy.should.be.called();
        done();
      });
    });

    manager.initialize();
  });

  it('handles source types that have not been implemented', function (done) {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: 'ThisIsACoolEtag',
      Body: new Buffer(JSON.stringify({
        version: 1.0,
        sources: [
          {name: 'global', type: 's3', parameters: {path: 'global.json'}},
          {name: 'global', type: 'someBrandNewSourceType', parameters: {path: 'global.json'}}
        ]
      }))
    });

    manager.once('error', (err) => {
      const status = manager.status();

      err.message.should.equal('Source type someBrandNewSourceType not implemented');
      status.ok.should.be.false();
      done();
    });

    manager.initialize();
  });

  it('retries Metadata source until it succeeds if the Metadata source fails', function (done) {
    function onConnectionRefused(err) {
      if (err.code === 'ECONNREFUSED') {
        manager.removeListener('error', onConnectionRefused);

        const metadataStatus = manager.metadata.status();
        const managerStatus = manager.status();

        managerStatus.running.should.be.true();
        managerStatus.ok.should.be.false();
        metadataStatus.ok.should.be.false();
        metadataStatus.running.should.be.true();

        manager.metadata.service.host = '127.0.0.1:8080';
      }
    }

    manager.on('error', onConnectionRefused);

    manager.once('sources-generated', (sources) => {
      const status = manager.status();

      status.running.should.be.true();
      status.ok.should.be.true();
      sources.length.should.equal(3); // eslint-disable-line rapid7/static-magic-numbers
      done();
    });

    manager.metadata.service.host = '0.0.0.0';
    manager.metadata.interval = 1;
    manager.initialize();
  });

  it('retries S3 source until it succeeds if the S3 source fails', function (done) {
    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, unknownEndpointErr, null);

    function onUnknownEndpoint(err) {
      if (err.message === 'UnknownEndpoint') {
        manager.removeListener('error', onUnknownEndpoint);

        const indexStatus = manager.index.status();
        const managerStatus = manager.status();

        managerStatus.running.should.be.true();
        managerStatus.ok.should.be.false();
        indexStatus.ok.should.be.false();
        indexStatus.running.should.be.true();

        AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, fakeIndexResponse);
      }
    }

    manager.on('error', onUnknownEndpoint);

    manager.once('sources-generated', (sources) => {
      const status = manager.status();

      status.running.should.be.true();
      status.ok.should.be.true();
      sources.length.should.equal(3); // eslint-disable-line rapid7/static-magic-numbers
      done();
    });

    manager.index.interval = 1;
    manager.initialize();
  });

  it('rebuilds sources when the index is updated', function (done) {
    const s3Sources = [];

    function addS3Source(name) {
      s3Sources.push({
        name, type: 's3', parameters: {path: `${name}.json`}
      });

      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
        ETag: `v${s3Sources.length}`,
        Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
      });
    }

    manager.once('sources-registered', (storageSources) => {
      storageSources[0].on('shutdown', () => {
        done();
      });
      addS3Source('local');
    });

    addS3Source('global');
    manager.index.interval = 1;
    manager.initialize();
  });

  it('updates the storage engine when the index removes a source plugin', function (done) {
    let s3Sources = [{
      name: 'global', type: 's3', parameters: {path: 'global.json'}
    }, {
      name: 'local', type: 's3', parameters: {path: 'local.json'}
    }];

    AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
      ETag: `v${s3Sources.length}`,
      Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
    });

    function removeS3Source(name) {
      s3Sources = s3Sources.filter((source) => {
        return source.name !== name;
      });

      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
        ETag: `v${s3Sources.length}`,
        Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
      });
    }

    function onSourcesRegistered(storageSources) {
      if (storageSources.length === 2) {
        storageSources.map((source) => {
          return source.name;
        }).sort().should.eql(['s3-foo-global.json', 's3-foo-local.json']);
        removeS3Source('local');
      }

      if (storageSources.length === 1) {
        manager.removeListener('sources-registered', onSourcesRegistered);
        storageSources.map((source) => {
          return source.name;
        }).sort().should.eql(['s3-foo-global.json']);
        done();
      }
    }

    manager.on('sources-registered', onSourcesRegistered);
    manager.index.interval = 1;
    manager.initialize();
  });

  it('updates the storage engine when the index adds a source plugin', function (done) {
    const s3Sources = [];

    function addS3Source(name) {
      s3Sources.push({
        name, type: 's3', parameters: {path: `${name}.json`}
      });

      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, null, {
        ETag: `v${s3Sources.length}`,
        Body: new Buffer(JSON.stringify({version: 1.0, sources: s3Sources}))
      });
    }

    function onSourcesRegistered(storageSources) {
      if (storageSources.length === 1) {
        storageSources.map((source) => {
          return source.name;
        }).should.containEql('s3-foo-global.json');
        addS3Source('local');
      }

      if (storageSources.length === 2) {
        manager.removeListener('sources-registered', onSourcesRegistered);
        storageSources.map((source) => {
          return source.name;
        }).should.containEql('s3-foo-local.json');
        done();
      }
    }

    addS3Source('global');
    manager.on('sources-registered', onSourcesRegistered);
    manager.index.interval = 1;
    manager.initialize();
  });

  it('exposes an error from source plugins when one occurs but continues running', function (done) {
    function onUnknownEndpoint(err) {
      if (err.message === 'UnknownEndpoint') {
        manager.removeListener('error', onUnknownEndpoint);

        manager.status().running.should.be.true();
        done();
      }
    }

    manager.on('error', onUnknownEndpoint);

    manager.once('source-instantiated', () => {
      AWS.S3.prototype.getObject = sinon.stub().callsArgWith(1, unknownEndpointErr, null);
    });

    manager.initialize();
  });
});

/* eslint-enable func-names */
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

var path = require('path');
var resolvePlugins = require('../lib/resolvePlugins');

var hmrTransform = 'react-transform-hmr/lib/index.js';
var transformPath = require.resolve(hmrTransform);

module.exports = function(options, filename) {
  var transform = filename
      ? './' + path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths
      : hmrTransform;
  return {
    plugins: resolvePlugins([
      [
        'react-transform',
        {
          transforms: [{
            transform: transform,
            imports: ['React'],
            locals: ['module'],
          }]
        },
      ]
    ])
  };
};
<commit_msg>Use `react-native` instead of `React` on hmr config<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

var path = require('path');
var resolvePlugins = require('../lib/resolvePlugins');

var hmrTransform = 'react-transform-hmr/lib/index.js';
var transformPath = require.resolve(hmrTransform);

module.exports = function(options, filename) {
  var transform = filename
      ? './' + path.relative(path.dirname(filename), transformPath) // packager can't handle absolute paths
      : hmrTransform;
  return {
    plugins: resolvePlugins([
      [
        'react-transform',
        {
          transforms: [{
            transform: transform,
            imports: ['react-native'],
            locals: ['module'],
          }]
        },
      ]
    ])
  };
};
<|endoftext|>


<commit_before>angular.module( 'moviematch.showmatch', [] )

  .controller( 'ShowmatchController', function( $scope ) {

    $scope.session = {};
    $scope.user = {};
    $scope.imgPath = 'http://image.tmdb.org/t/p/w500';

    $scope.moviePackage = [
      {
        "poster_path": "/jjBgi2r5cRt36xF6iNUEhzscEcb.jpg",
        "adult": false,
        "overview": "Twenty-two years after the events of Jurassic Park, Isla Nublar now features a fully functioning dinosaur theme park, Jurassic World, as originally envisioned by John Hammond.",
        "release_date": "2015-06-09",
        "genre_ids": [
          28,
          12,
          878,
          53
        ],
        "id": 135397,
        "original_title": "Jurassic World",
        "original_language": "en",
        "title": "Jurassic World",
        "backdrop_path": "/dkMD5qlogeRMiEixC4YNPUvax2T.jpg",
        "popularity": 28.042069,
        "vote_count": 3884,
        "video": false,
        "vote_average": 6.71
      },
      {
        "poster_path": "/kqjL17yufvn9OVLyXYpvtyrFfak.jpg",
        "adult": false,
        "overview": "An apocalyptic story set in the furthest reaches of our planet, in a stark desert landscape where humanity is broken, and most everyone is crazed fighting for the necessities of life. Within this world exist two rebels on the run who just might be able to restore order. There's Max, a man of action and a man of few words, who seeks peace of mind following the loss of his wife and child in the aftermath of the chaos. And Furiosa, a woman of action and a woman who believes her path to survival may be achieved if she can make it across the desert back to her childhood homeland.",
        "release_date": "2015-05-13",
        "genre_ids": [
          878,
          53,
          28,
          12
        ],
        "id": 76341,
        "original_title": "Mad Max: Fury Road",
        "original_language": "en",
        "title": "Mad Max: Fury Road",
        "backdrop_path": "/tbhdm8UJAb4ViCTsulYFL3lxMCd.jpg",
        "popularity": 24.874131,
        "vote_count": 3744,
        "video": false,
        "vote_average": 7.47
      },
      {
        "poster_path": "/hE24GYddaxB9MVZl1CaiI86M3kp.jpg",
        "adult": false,
        "overview": "A cryptic message from Bond’s past sends him on a trail to uncover a sinister organization. While M battles political forces to keep the secret service alive, Bond peels back the layers of deceit to reveal the terrible truth behind SPECTRE.",
        "release_date": "2015-10-26",
        "genre_ids": [
          28,
          12,
          80
        ],
        "id": 206647,
        "original_title": "Spectre",
        "original_language": "en",
        "title": "Spectre",
        "backdrop_path": "/wVTYlkKPKrljJfugXN7UlLNjtuJ.jpg",
        "popularity": 22.938967,
        "vote_count": 2044,
        "video": false,
        "vote_average": 6.29
      }
    ];

    $scope.currMovie = $scope.moviePackage[0];
  });
<commit_msg>Display current user<commit_after>angular.module( 'moviematch.showmatch', [] )

  .controller( 'ShowmatchController', function( $scope, Session, Auth ) {

    Session.getSession()
    .then( function( session ) {
      $scope.session = session;
    });
    $scope.user = {};
    $scope.user.name = Auth.getUserName();
    $scope.imgPath = 'http://image.tmdb.org/t/p/w500';

    $scope.currMovie = {};
  });
<|endoftext|>


<commit_before>var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

var env = process.env.NODE_ENV === 'testing' ?
    require('../config/test.env') :
    config.build.env

var webpackConfig = merge(baseWebpackConfig, {
    module: {
        rules: utils.styleLoaders({
            sourceMap: config.build.productionSourceMap,
            extract: true
        })
    },
    devtool: config.build.productionSourceMap ? '#source-map' : false,
    output: {
        path: config.build.assetsRoot,
        filename: utils.assetsPath('js/[name].[chunkhash].js'),
        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
    },
    plugins: [
        // http://vuejs.github.io/vue-loader/en/workflow/production.html
        new webpack.DefinePlugin({
            'process.env': env
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            sourceMap: true
        }),
        // extract css into its own file
        new ExtractTextPlugin({
            filename: utils.assetsPath('css/[name].[contenthash].css')
        }),
        // Compress extracted CSS. We are using this plugin so that possible
        // duplicated CSS from different components can be deduped.
        new OptimizeCSSPlugin({
            cssProcessorOptions: {
                safe: true
            }
        }),
        // generate dist index.html with correct asset hash for caching.
        // you can customize output by editing /index.html
        // see https://github.com/ampedandwired/html-webpack-plugin
        new HtmlWebpackPlugin({
            filename: process.env.NODE_ENV === 'testing' ?
                'index.html' : config.build.index,
            template: 'index.html',
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
                // more options:
                // https://github.com/kangax/html-minifier#options-quick-reference
            },
            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
            chunksSortMode: 'dependency'
        }),
        // split vendor js into its own file
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function (module, count) {
                // any required modules inside node_modules are extracted to vendor
                return (
                    module.resource &&
                    /\.js$/.test(module.resource) &&
                    module.resource.indexOf(
                        path.join(__dirname, '../node_modules')
                    ) === 0
                )
            }
        }),
        // extract webpack runtime and module manifest to its own file in order to
        // prevent vendor hash from being updated whenever app bundle is updated
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest',
            chunks: ['vendor']
        }),
        // copy custom static assets
        new CopyWebpackPlugin([{
            from: path.resolve(__dirname, '../static'),
            to: config.build.assetsSubDirectory,
            ignore: ['.*']
        }]),
        // sw precache for static assest
        new SWPrecacheWebpackPlugin({
            cacheId: 'news-weaver',
            filename: 'service-worker.js',
            staticFileGlobs: ['dist/**/*.{js,html,css,png,json}'],
            minify: true,
            stripPrefix: 'dist/',
            runtimeCaching: [{
                    urlPattern: /^https:\/\/fonts\.googleapis\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/cdnjs\.cloudflare\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/cdn\.polyfill\.io\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/fonts\.googleapis\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/news-weaver\.firebaseapp\.com\/?/,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/news-weaver\.herokuapp\.com\/?/,
                    handler: 'cacheFirst'
                }
            ]
        })
    ]
})

if (config.build.productionGzip) {
    var CompressionWebpackPlugin = require('compression-webpack-plugin')

    webpackConfig.plugins.push(
        new CompressionWebpackPlugin({
            asset: '[path].gz[query]',
            algorithm: 'gzip',
            test: new RegExp(
                '\\.(' +
                config.build.productionGzipExtensions.join('|') +
                ')$'
            ),
            threshold: 10240,
            minRatio: 0.8
        })
    )
}

if (config.build.bundleAnalyzerReport) {
    var BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
        .BundleAnalyzerPlugin
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
<commit_msg>Updated Service Worker<commit_after>var path = require('path')
var utils = require('./utils')
var webpack = require('webpack')
var config = require('../config')
var merge = require('webpack-merge')
var baseWebpackConfig = require('./webpack.base.conf')
var CopyWebpackPlugin = require('copy-webpack-plugin')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')

var env = process.env.NODE_ENV === 'testing' ?
    require('../config/test.env') :
    config.build.env

var webpackConfig = merge(baseWebpackConfig, {
    module: {
        rules: utils.styleLoaders({
            sourceMap: config.build.productionSourceMap,
            extract: true
        })
    },
    devtool: config.build.productionSourceMap ? '#source-map' : false,
    output: {
        path: config.build.assetsRoot,
        filename: utils.assetsPath('js/[name].[chunkhash].js'),
        chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
    },
    plugins: [
        // http://vuejs.github.io/vue-loader/en/workflow/production.html
        new webpack.DefinePlugin({
            'process.env': env
        }),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            sourceMap: true
        }),
        // extract css into its own file
        new ExtractTextPlugin({
            filename: utils.assetsPath('css/[name].[contenthash].css')
        }),
        // Compress extracted CSS. We are using this plugin so that possible
        // duplicated CSS from different components can be deduped.
        new OptimizeCSSPlugin({
            cssProcessorOptions: {
                safe: true
            }
        }),
        // generate dist index.html with correct asset hash for caching.
        // you can customize output by editing /index.html
        // see https://github.com/ampedandwired/html-webpack-plugin
        new HtmlWebpackPlugin({
            filename: process.env.NODE_ENV === 'testing' ?
                'index.html' : config.build.index,
            template: 'index.html',
            inject: true,
            minify: {
                removeComments: true,
                collapseWhitespace: true,
                removeAttributeQuotes: true
                // more options:
                // https://github.com/kangax/html-minifier#options-quick-reference
            },
            // necessary to consistently work with multiple chunks via CommonsChunkPlugin
            chunksSortMode: 'dependency'
        }),
        // split vendor js into its own file
        new webpack.optimize.CommonsChunkPlugin({
            name: 'vendor',
            minChunks: function (module, count) {
                // any required modules inside node_modules are extracted to vendor
                return (
                    module.resource &&
                    /\.js$/.test(module.resource) &&
                    module.resource.indexOf(
                        path.join(__dirname, '../node_modules')
                    ) === 0
                )
            }
        }),
        // extract webpack runtime and module manifest to its own file in order to
        // prevent vendor hash from being updated whenever app bundle is updated
        new webpack.optimize.CommonsChunkPlugin({
            name: 'manifest',
            chunks: ['vendor']
        }),
        // copy custom static assets
        new CopyWebpackPlugin([{
            from: path.resolve(__dirname, '../static'),
            to: config.build.assetsSubDirectory,
            ignore: ['.*']
        }]),
        // sw precache for static assest
        new SWPrecacheWebpackPlugin({
            cacheId: 'news-weaver',
            filename: 'service-worker.js',
            staticFileGlobs: ['dist/**/*.{js,html,css,png,json,jpg}', 'dist/*.js'],
            minify: true,
            stripPrefix: 'dist/',
            runtimeCaching: [{
                    urlPattern: /^https:\/\/fonts\.googleapis\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/cdnjs\.cloudflare\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/cdn\.polyfill\.io\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/fonts\.googleapis\.com\//,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/news-weaver\.firebaseapp\.com\/?/,
                    handler: 'cacheFirst'
                },
                {
                    urlPattern: /^https:\/\/news-weaver\.herokuapp\.com\/?/,
                    handler: 'cacheFirst'
                }
            ]
        })
    ]
})

if (config.build.productionGzip) {
    var CompressionWebpackPlugin = require('compression-webpack-plugin')

    webpackConfig.plugins.push(
        new CompressionWebpackPlugin({
            asset: '[path].gz[query]',
            algorithm: 'gzip',
            test: new RegExp(
                '\\.(' +
                config.build.productionGzipExtensions.join('|') +
                ')$'
            ),
            threshold: 10240,
            minRatio: 0.8
        })
    )
}

if (config.build.bundleAnalyzerReport) {
    var BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
        .BundleAnalyzerPlugin
    webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}

module.exports = webpackConfig
<|endoftext|>


<commit_before>import { store } from '../../store.js'; // connect to redux
import { html } from 'lit-html';
import { customElement } from 'lit-element';
import { BaseLitComponent } from '../../components/base-component';
import styles from './pl-logo.scss?external';

@customElement('pl-logo')
class Logo extends BaseLitComponent {
  connectedCallback() {
    super.connectedCallback && super.connectedCallback();
    styles.use();
    const state = store.getState();
    this.theme = this.theme || state.app.themeMode || 'dark';
  }

  disconnectedCallback() {
    super.disconnectedCallback && super.disconnectedCallback();
    styles.unuse();
  }

  static get properties() {
    return {
      ratio: String,
      theme: String,
      url: String,
      text: String,
      altText: String,
      srcLight: {
        type: String,
        attribute: 'src-light',
      },
      srcDark: {
        type: String,
        attribute: 'src-dark',
      },
    };
  }

  render() {
    const imageSrc = this.theme === 'dark' ? this.srcDark : this.srcLight;

    return html`

        ${this.text && this.text !== ''
          ? html`
              ${this.text}
            `
          : ''}

    `;
  }
}

export { Logo };
<commit_msg>fix: configure the Logo's `altText` config option when used as an HTML attribute<commit_after>import { store } from '../../store.js'; // connect to redux
import { html } from 'lit-html';
import { customElement } from 'lit-element';
import { BaseLitComponent } from '../../components/base-component';
import styles from './pl-logo.scss?external';

@customElement('pl-logo')
class Logo extends BaseLitComponent {
  connectedCallback() {
    super.connectedCallback && super.connectedCallback();
    styles.use();
    const state = store.getState();
    this.theme = this.theme || state.app.themeMode || 'dark';
  }

  disconnectedCallback() {
    super.disconnectedCallback && super.disconnectedCallback();
    styles.unuse();
  }

  static get properties() {
    return {
      ratio: String,
      theme: String,
      url: String,
      text: String,
      altText: {
        type: String,
        attribute: 'alt-text',
      },
      srcLight: {
        type: String,
        attribute: 'src-light',
      },
      srcDark: {
        type: String,
        attribute: 'src-dark',
      },
    };
  }

  render() {
    const imageSrc = this.theme === 'dark' ? this.srcDark : this.srcLight;

    return html`

        ${this.text && this.text !== ''
          ? html`
              ${this.text}
            `
          : ''}

    `;
  }
}

export { Logo };
<|endoftext|>


<commit_before>import Marionette from 'backbone.marionette';
import $ from 'jquery';
import 'bootstrap-slider';
import 'bootstrap-slider/dist/css/bootstrap-slider.css';

import template from './LayerListItemView.hbs';
import './LayerListItemView.css';

// eslint-disable-next-line max-len
const LayerListItemView = Marionette.ItemView.extend(/** @lends core/views/layers.LayerListItemView# */{
  tagName: 'li',
  className: 'layer-list-item',
  template,
  events: {
    'change .layer-visible': 'onLayerVisibleChange',
    'click .layer-options': 'onLayerOptionsClick',

    // for when no options are set
    'click .layer-adjust-opacity': 'onLayerAdjustOpacityClick',
    'inserted.bs.popover': 'onPopoverInserted',
    'hidden.bs.popover': 'onPopoverHidden',
    'click .layer-download-full-resolution': 'onLayerDownloadFullResolutionClick',

    // when using options
    'click .layer-show-options': 'onShowOptionsClick',
    'click .display-name':'onPopoverClick',
  },

  modelEvents: {
    change: 'onModelChange',
  },

  /**
    @constructs
    @param {Object} options
    @param {core/models.LayersCollection} options.collection The layers to display
    @param {boolean} options.singleChoice Whether the visibility of the layers
                                          is mutually exclusive.
    @param {boolean} options.fullDisplay Whether the layers shall be displayed
                                         with options, colors, etc.
   */
  initialize(options) {
    this.singleChoice = options.singleChoice;
    this.fullDisplay = options.fullDisplay;
  },

  templateHelpers() {
    const GetCapabilities = this.model.get('display') && this.model.get('display').urls ? `${this.model.get('display').urls[0]}?service=${this.model.get('display').protocol}&request=GetCapabilities` : '';
    const description = this.model.get('display') && this.model.get('display').description;
    this.template = `<p><p><strong>GetCapabilities:</strong></p><a href=${GetCapabilities}>${GetCapabilities}</a></p>${description}`;

    return {
      singleChoice: this.singleChoice,
      fullDisplay: this.fullDisplay,
      options: this.model.get('display.options'),
      template: this.template,
    };
  },

  onAttach() {
    this.$popoverButton = this.$('.layer-adjust-opacity');
    this.$popoverButton.popover({
      container: 'body',
      content: 'x',
      trigger: 'manual',
    });

    $('.display-name').popover({
      placement: 'top',
      trigger: "manual"
      })
  },
  onLayerAdjustOpacityClick() {
    if (!this.isPopoverShown) {
      this.$popoverButton.popover('show');
    }
  },

  onLayerDownloadFullResolutionClick() {
    this.model.trigger('download-full-resolution', this.model);
  },

  onPopoverInserted() {
    this.isPopoverShown = true;
    const popoverId = this.$('.layer-adjust-opacity').attr('aria-describedby');
    if (popoverId){
      const $popover = $(`#${popoverId}`);
      const $popoverContent = $popover.find('.popover-content');
      $popover.addClass('layer-adjust-opacity-popover');
      $popoverContent
        .empty().text('')
        .css('width', '200px');

      let opacity = this.model.get('display.opacity');
      opacity = typeof opacity === 'undefined' ? 1 : opacity;

      this.$slider = $('<input/>')
        .appendTo($popoverContent)
        .slider({
          min: 0,
          max: 100,
          value: opacity * 100,
          formatter(value) {
            return `${value}%`;
          }
        });
      this.$slider.on('slide', (event) => {
        this.model.set('display.opacity', event.value / 100);
      });
      this.$slider.on('change', () => {
        this.model.set('display.opacity', parseInt(this.$slider.val(), 10) / 100);
      });
      this.$slider.on('slideStop', () => $popover.focus());

      $popover.attr('tabindex', '0');
      $popover.focus();

      $popover[0].onblur = (event) => {
        // fix for IE, as the blur event is also raised when a child gets focused:
        // check if the currently targeted element is a descendant. Only hide the
        // popover when the new target is outside of the popover.
        const $target = $(event.explicitOriginalTarget || document.activeElement);
        if ($target.closest($popover).length === 0) {
          this.$popoverButton.popover('hide');
          $popover[0].onblur = null;
        } else {
          $popover.focus();
        }
      };
    }
  },

  onPopoverHidden() {
    this.isPopoverShown = false;
    if (typeof this.$slider !== 'undefined') {
      this.$slider.off('slide');
      this.$slider.off('change');
      this.$slider.slider('destroy');
    }
  },

  onLayerVisibleChange() {
    this.model.set('display.visible', this.$('.layer-visible').is(':checked'));
  },

  onShowOptionsClick() {
    this.model.trigger('show-options', this.model);
  },

  onModelChange(model) {
    // TODO: other fields required too?
    this.$('.layer-visible').prop('checked', model.get('display.visible'));
  },

  hidePopover() {
    this.$popoverButton.popover('hide');
  },
  onPopoverClick (e){
    $("[data-toggle='popover']").popover('toggle');
    $("[data-toggle='popover']").not(e.target).popover("hide");

  }

});

export default LayerListItemView;
<commit_msg>adding close button to popover<commit_after>import Marionette from 'backbone.marionette';
import $ from 'jquery';
import 'bootstrap-slider';
import 'bootstrap-slider/dist/css/bootstrap-slider.css';

import template from './LayerListItemView.hbs';
import './LayerListItemView.css';

// eslint-disable-next-line max-len
const LayerListItemView = Marionette.ItemView.extend(/** @lends core/views/layers.LayerListItemView# */{
  tagName: 'li',
  className: 'layer-list-item',
  template,
  events: {
    'change .layer-visible': 'onLayerVisibleChange',
    'click .layer-options': 'onLayerOptionsClick',

    // for when no options are set
    'click .layer-adjust-opacity': 'onLayerAdjustOpacityClick',
    'inserted.bs.popover': 'onPopoverInserted',
    'hidden.bs.popover': 'onPopoverHidden',
    'click .layer-download-full-resolution': 'onLayerDownloadFullResolutionClick',

    // when using options
    'click .layer-show-options': 'onShowOptionsClick',
    'click .display-name':'onPopoverClick',
    'click .close': 'close',
  },

  modelEvents: {
    change: 'onModelChange',
  },

  /**
    @constructs
    @param {Object} options
    @param {core/models.LayersCollection} options.collection The layers to display
    @param {boolean} options.singleChoice Whether the visibility of the layers
                                          is mutually exclusive.
    @param {boolean} options.fullDisplay Whether the layers shall be displayed
                                         with options, colors, etc.
   */
  initialize(options) {
    this.singleChoice = options.singleChoice;
    this.fullDisplay = options.fullDisplay;
  },

  templateHelpers() {
    const GetCapabilities = this.model.get('display') && this.model.get('display').urls ? `${this.model.get('display').urls[0]}?service=${this.model.get('display').protocol}&request=GetCapabilities` : '';
    const description = this.model.get('display') && this.model.get('display').description;
    this.template = `<p><p><strong>GetCapabilities:</strong></p><a href=${GetCapabilities}>${GetCapabilities}</a></p>${description}`;

    return {
      singleChoice: this.singleChoice,
      fullDisplay: this.fullDisplay,
      options: this.model.get('display.options'),
      template: this.template,
    };
  },

  onAttach() {
    this.$popoverButton = this.$('.layer-adjust-opacity');
    this.$popoverButton.popover({
      container: 'body',
      content: 'x',
      trigger: 'manual',
    });

    $('.display-name').popover({
      placement: 'top',
      trigger: 'manual'
      })
  },
  onLayerAdjustOpacityClick() {
    if (!this.isPopoverShown) {
      this.$popoverButton.popover('show');
    }
  },

  onLayerDownloadFullResolutionClick() {
    this.model.trigger('download-full-resolution', this.model);
  },

  onPopoverInserted() {
    this.isPopoverShown = true;
    const popoverId = this.$('.layer-adjust-opacity').attr('aria-describedby');
    if (popoverId){
      const $popover = $(`#${popoverId}`);
      const $popoverContent = $popover.find('.popover-content');
      $popover.addClass('layer-adjust-opacity-popover');
      $popoverContent
        .empty().text('')
        .css('width', '200px');

      let opacity = this.model.get('display.opacity');
      opacity = typeof opacity === 'undefined' ? 1 : opacity;

      this.$slider = $('<input/>')
        .appendTo($popoverContent)
        .slider({
          min: 0,
          max: 100,
          value: opacity * 100,
          formatter(value) {
            return `${value}%`;
          }
        });
      this.$slider.on('slide', (event) => {
        this.model.set('display.opacity', event.value / 100);
      });
      this.$slider.on('change', () => {
        this.model.set('display.opacity', parseInt(this.$slider.val(), 10) / 100);
      });
      this.$slider.on('slideStop', () => $popover.focus());

      $popover.attr('tabindex', '0');
      $popover.focus();

      $popover[0].onblur = (event) => {
        // fix for IE, as the blur event is also raised when a child gets focused:
        // check if the currently targeted element is a descendant. Only hide the
        // popover when the new target is outside of the popover.
        const $target = $(event.explicitOriginalTarget || document.activeElement);
        if ($target.closest($popover).length === 0) {
          this.$popoverButton.popover('hide');
          $popover[0].onblur = null;
        } else {
          $popover.focus();
        }
      };
    }
  },

  onPopoverHidden() {
    this.isPopoverShown = false;
    if (typeof this.$slider !== 'undefined') {
      this.$slider.off('slide');
      this.$slider.off('change');
      this.$slider.slider('destroy');
    }
  },

  onLayerVisibleChange() {
    this.model.set('display.visible', this.$('.layer-visible').is(':checked'));
  },

  onShowOptionsClick() {
    this.model.trigger('show-options', this.model);
  },

  onModelChange(model) {
    // TODO: other fields required too?
    this.$('.layer-visible').prop('checked', model.get('display.visible'));
  },

  hidePopover() {
    this.$popoverButton.popover('hide');
  },
  onPopoverClick (e){

    $('.popover-title').find('button').remove();
    $("[data-toggle='popover']").popover('toggle');
    $("[data-toggle='popover']").not(e.target).popover("hide");
    $('.popover-title').append('<button id="popovercloseid" type="button" class="close">×</button>');

  },
  close() {
    $("[data-toggle='popover']").popover("hide");
  },

});

export default LayerListItemView;
<|endoftext|>


<commit_before>const path = require('path');

const LIB_BASE_CONFIG = {
  entry: "./src/index.ts",
  mode: "production",
  module: {
    rules: [{
      test: /\.ts?$/,
      use: 'ts-loader',
      exclude: /node_modules/
    }]
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
};
const DIST_DIR = path.resolve(__dirname, 'dist');

module.exports = [{
    name: 'lib-commonjs',
    ...LIB_BASE_CONFIG,
    output: {
      filename: `grpc-web-client.js`,
      path: DIST_DIR,
      libraryTarget: 'commonjs',
    }
  },
  {
    name: 'lib-umd',
    ...LIB_BASE_CONFIG,
    output: {
      filename: `grpc-web-client.umd.js`,
      path: DIST_DIR,
      libraryTarget: 'umd',
    }
  },
];
<commit_msg>Worker error "window not defined" fix (#411)<commit_after>const path = require('path');

const LIB_BASE_CONFIG = {
  entry: "./src/index.ts",
  mode: "production",
  module: {
    rules: [{
      test: /\.ts?$/,
      use: 'ts-loader',
      exclude: /node_modules/
    }]
  },
  resolve: {
    extensions: ['.ts', '.js']
  },
};
const DIST_DIR = path.resolve(__dirname, 'dist');

module.exports = [{
    name: 'lib-commonjs',
    ...LIB_BASE_CONFIG,
    output: {
      filename: `grpc-web-client.js`,
      path: DIST_DIR,
      libraryTarget: 'commonjs',
      globalObject: 'this',
    }
  },
  {
    name: 'lib-umd',
    ...LIB_BASE_CONFIG,
    output: {
      filename: `grpc-web-client.umd.js`,
      path: DIST_DIR,
      libraryTarget: 'umd',
      globalObject: 'this',
    }
  },
];
<|endoftext|>


<commit_before>'use strict';
/*global rtc: true */
angular.module('mean.rooms').factory('UserHandler',['Rooms','UIHandler','Notification',function(Rooms,UIHandler,Notification){
	return function (){

		var room = new Rooms({});
		var uiHandler = UIHandler;

		this.init = function ($scope){

			/* Set owner status*/
			uiHandler.userStatus = [];
			uiHandler.users = [];
			uiHandler.name = $scope.global.name;
			uiHandler.avatar = $scope.global.avatar;
			uiHandler.gravatar = $scope.global.gravatar;
			uiHandler.editName = false;
			uiHandler.editNameClass = '';
			uiHandler.status = uiHandler.isowner?'OPENED':'DISCONNECTED';
			uiHandler.access = angular.copy($scope.global.access);

			$scope.changeName = function() {
		        if (!uiHandler.name) { uiHandler.name = $scope.global.name; return; }
		        if (uiHandler.isowner){
					room.editOwnerName($scope.global.roomId, uiHandler.name, uiHandler.gravatar, function(rdo){
			            $scope.global.name = uiHandler.name;
			            $scope.enableEditName();
			            uiHandler.avatar = rdo.owner.avatar;
			            $scope.global.avatar = uiHandler.avatar;

			            rtc.peerListUpdated(uiHandler.roomId);
			            rtc.updateOwnerData (uiHandler.roomId,uiHandler.name,uiHandler.avatar,uiHandler.status,uiHandler.access);
		        	});
		        }else{
		        	room.editGuestName($scope.global.roomId, uiHandler.name, uiHandler.gravatar, function(rdo){
            			$scope.global.name = uiHandler.name;
            			$scope.enableEditName();
			            var cid = room.getConnectionId();
			            for (var i=0; i<rdo.guests.length; i+=1) {
			                if (rdo.guests[i].connectionId === cid) {
			                	uiHandler.avatar = rdo.guests[i].avatar;
			                }
			            }
			            rtc.peerListUpdated($scope.global.roomId);
        			});
		        }
		    };

		    $scope.enableEditName = function() {
  				if (!uiHandler.isowner && uiHandler.passNeeded) { return; }

		        if (!uiHandler.name) { uiHandler.name = $scope.global.name; return; }
		        uiHandler.editName = !uiHandler.editName;
		        if (uiHandler.editName) {
		        	uiHandler.editNameClass = 'editable';
		            setTimeout(function(){document.getElementById('chgname').focus();},100);
		        } else {
		        	uiHandler.editNameClass = '';
		            setTimeout(function(){document.getElementById('chgname').blur();},100);
		        }
		        return false;
		    };

		    $scope.connectedUsers = function() {
		        var cnt = 0;
		        if (uiHandler.users) {
		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].status === 'CONNECTED'){
		                    cnt+=1;
		                }
		            }
		        }
		        return cnt;
	    	};

	    	var getNewUsersFromResult = function(result) {
	            for (var i=0; i<result.length; i+=1) {
	                var exists = false;
	                for (var j=0; j<uiHandler.users.length; j+=1) {
	                    if (uiHandler.users[j].connectionId === result[i].connectionId) {
	                        exists = true;
	                        uiHandler.users[j].name = result[i].name;
	                        uiHandler.users[j].avatar = result[i].avatar;
	                        if (uiHandler.users[j].status !== result[i].status) {
	                        	uiHandler.newusers.unshift(result[i]);
	                        }
	                        uiHandler.users[j].status = result[i].status;
	                        $scope.changeWindowName(result[i].connectionId,result[i].name);
	                    }
	                }
	                if (!exists) {
	                	uiHandler.users.push(result[i]);
	                	uiHandler.newusers.unshift(result[i]);
	                    $scope.changeWindowName(result[i].connectionId,result[i].name);
	                }
	            }
	    	};

	    	var removeOldUsers = function(result) {
	            for (var j2=0; j2<uiHandler.users.length; j2+=1) {
	            	var exists2 = false;
	            	for (var i2=0; i2<result.length; i2+=1) {
	            		if (uiHandler.users[j2].connectionId === result[i2].connectionId) {
	            			exists2 = true;
	            		}
	            	}
	            	if (!exists2) {
	            		uiHandler.users.slice(j2,1);
	            	}
	            }
	    	};

	    	var raiseHtml5Notification = function() {
	        	var bd = '';
	        	for (var u=0; u<uiHandler.newusers.length; u+=1) {
	        		bd = uiHandler.newusers[u].name + ' ' + (uiHandler.newusers[u].status === 'CONNECTED'?'(+)':'(-)');
	        	}
	        	if (bd !== '') {
	       		    var notification = new Notification($scope.resourceBundle.usertypeviewer, {
       		            body: bd,
       		            icon: uiHandler.newusers.length>1?'img/icons/favicon.ico':uiHandler.newusers[0].avatar,
       		            delay: 3000
	       		    });
	       	        notification.$on('click', function () {
	       	        	if (!uiHandler.focused) { window.focus(); }
	       	        	if (uiHandler.connectedClass!=='') { $scope.toggleConnected(); }
	       	        });
	        	}
	    	};

	    	var raiseAudioNotification = function() {
   				// Doit traditional
        		if (!uiHandler.focused && uiHandler.audible) {
	        		var readText = $scope.resourceBundle.onlinenews;
	        		if (uiHandler.newusers.length===1) {
	        			readText = (uiHandler.newusers[0].status === 'CONNECTED')?$scope.resourceBundle._('joinroom',uiHandler.newusers[0].name):$scope.resourceBundle._('uleaveroom',uiHandler.newusers[0].name);
	        		}
	        		var audio = document.getElementById('audiotts')?document.getElementById('audiotts'):document.createElement('audio');
	        		audio.setAttribute('id', 'audiotts');
	        		audio.setAttribute('src', '/chat/talk?text=' + encodeURIComponent(readText));
	        		audio.load();
	        		audio.play();
        		} else {
   					uiHandler.connNew = 'connected_now';
   					setTimeout(function(){ uiHandler.connNew = ''; uiHandler.safeApply($scope,function(){}); },3000);
   				}
	    	};

	    	$scope.updateUsers = function(result) {
	    		uiHandler.newusers = [];
		        if (uiHandler.users) {
		        	getNewUsersFromResult(result);
		        	removeOldUsers(result);
		        } else {
		            // If no users no windows
		        	uiHandler.newusers = result;
		        	uiHandler.users = result;
		        }
		        if (uiHandler.connectedClass!=='' || !uiHandler.focused) {
		        	if (uiHandler.notificationReady) {
		        		raiseHtml5Notification();
		        	} else {
		        		raiseAudioNotification();
		        	}
		        }
		        //uiHandler.users = result;
		    };

		    $scope.isOwner = function (id) {
    			return (id === uiHandler.ownerConnectionId) || ($scope.global.own === id);
    		};

    		var findUser = function(connectionId) {
		        if (uiHandler.users) {
		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].connectionId === connectionId){
		                    return uiHandler.users[i];
		                }
		            }
		        }
		        return null;
    		};

    		$scope.getUser = function (connectionId) {
		        if (connectionId === $scope.global.bot) { return {name:'loowid',avatar:'img/icons/favicon.ico'}; }
		        if (rtc._me === connectionId || (connectionId === $scope.global.own && uiHandler.isowner)) { return $scope.ui; }
		        if (!uiHandler.isowner && $scope.isOwner(connectionId)) { return {avatar:uiHandler.ownerAvatar,name:uiHandler.ownerName}; }
	        	return findUser(connectionId);
	  	 	};

	  		$scope.toggleConnected = function() {
	  			uiHandler.connectedClass=(uiHandler.connectedClass==='collapsed')?'':'collapsed';
	  			uiHandler.dashConn=(uiHandler.connectedClass==='collapsed')?'connected_collapsed':'';
	  		};

	    	$scope.getUserName = function (connectionId){
	    		if (uiHandler.isowner && rtc._me === connectionId){
	    			return uiHandler.name;
	    		}else if (!uiHandler.isowner && $scope.isOwner(connectionId)){
		            return uiHandler.ownerName;
		        }else{
		            var name = 'unkown user';

		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].connectionId === connectionId){
		                    name = uiHandler.users[i].name;
		                    continue;
		                }
		            }
		            return name;
		        }
	    	};

	    	rtc.on ('owner_data_updated',function(data){
	    		uiHandler.ownerName = data.ownerName;
	    		uiHandler.ownerAvatar = data.ownerAvatar;
                $scope.changeOwnerConnectionId(data.ownerCid);
                $scope.changeWindowName(uiHandler.ownerConnectionId,uiHandler.ownerName);
                uiHandler.safeApply($scope,function(){});
            });

	    	var peerListUpdated = 'peer_list_updated';
	    	if (rtc._events[peerListUpdated]) {
				setTimeout(function(){ rtc.fire('peer_list_updated'); },100);
			}

	        rtc.uniqueon('peer_list_updated',function (){
				//We should wait for a few to ensure the record is stored in the db
				room.users (uiHandler.roomId,$scope.updateUsers);
			});

    	};
	};
}]);<commit_msg>Change slice to splice. Fixes #114<commit_after>'use strict';
/*global rtc: true */
angular.module('mean.rooms').factory('UserHandler',['Rooms','UIHandler','Notification',function(Rooms,UIHandler,Notification){
	return function (){

		var room = new Rooms({});
		var uiHandler = UIHandler;

		this.init = function ($scope){

			/* Set owner status*/
			uiHandler.userStatus = [];
			uiHandler.users = [];
			uiHandler.name = $scope.global.name;
			uiHandler.avatar = $scope.global.avatar;
			uiHandler.gravatar = $scope.global.gravatar;
			uiHandler.editName = false;
			uiHandler.editNameClass = '';
			uiHandler.status = uiHandler.isowner?'OPENED':'DISCONNECTED';
			uiHandler.access = angular.copy($scope.global.access);

			$scope.changeName = function() {
		        if (!uiHandler.name) { uiHandler.name = $scope.global.name; return; }
		        if (uiHandler.isowner){
					room.editOwnerName($scope.global.roomId, uiHandler.name, uiHandler.gravatar, function(rdo){
			            $scope.global.name = uiHandler.name;
			            $scope.enableEditName();
			            uiHandler.avatar = rdo.owner.avatar;
			            $scope.global.avatar = uiHandler.avatar;

			            rtc.peerListUpdated(uiHandler.roomId);
			            rtc.updateOwnerData (uiHandler.roomId,uiHandler.name,uiHandler.avatar,uiHandler.status,uiHandler.access);
		        	});
		        }else{
		        	room.editGuestName($scope.global.roomId, uiHandler.name, uiHandler.gravatar, function(rdo){
            			$scope.global.name = uiHandler.name;
            			$scope.enableEditName();
			            var cid = room.getConnectionId();
			            for (var i=0; i<rdo.guests.length; i+=1) {
			                if (rdo.guests[i].connectionId === cid) {
			                	uiHandler.avatar = rdo.guests[i].avatar;
			                }
			            }
			            rtc.peerListUpdated($scope.global.roomId);
        			});
		        }
		    };

		    $scope.enableEditName = function() {
  				if (!uiHandler.isowner && uiHandler.passNeeded) { return; }

		        if (!uiHandler.name) { uiHandler.name = $scope.global.name; return; }
		        uiHandler.editName = !uiHandler.editName;
		        if (uiHandler.editName) {
		        	uiHandler.editNameClass = 'editable';
		            setTimeout(function(){document.getElementById('chgname').focus();},100);
		        } else {
		        	uiHandler.editNameClass = '';
		            setTimeout(function(){document.getElementById('chgname').blur();},100);
		        }
		        return false;
		    };

		    $scope.connectedUsers = function() {
		        var cnt = 0;
		        if (uiHandler.users) {
		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].status === 'CONNECTED'){
		                    cnt+=1;
		                }
		            }
		        }
		        return cnt;
	    	};

	    	var getNewUsersFromResult = function(result) {
	            for (var i=0; i<result.length; i+=1) {
	                var exists = false;
	                for (var j=0; j<uiHandler.users.length; j+=1) {
	                    if (uiHandler.users[j].connectionId === result[i].connectionId) {
	                        exists = true;
	                        uiHandler.users[j].name = result[i].name;
	                        uiHandler.users[j].avatar = result[i].avatar;
	                        if (uiHandler.users[j].status !== result[i].status) {
	                        	uiHandler.newusers.unshift(result[i]);
	                        }
	                        uiHandler.users[j].status = result[i].status;
	                        $scope.changeWindowName(result[i].connectionId,result[i].name);
	                    }
	                }
	                if (!exists) {
	                	uiHandler.users.push(result[i]);
	                	uiHandler.newusers.unshift(result[i]);
	                    $scope.changeWindowName(result[i].connectionId,result[i].name);
	                }
	            }
	    	};

	    	var removeOldUsers = function(result) {
	            for (var j2=0; j2<uiHandler.users.length; j2+=1) {
	            	var exists2 = false;
	            	for (var i2=0; i2<result.length; i2+=1) {
	            		if (uiHandler.users[j2].connectionId === result[i2].connectionId) {
	            			exists2 = true;
	            		}
	            	}
	            	if (!exists2) {
	            		uiHandler.users.splice(j2,1);
	            	}
	            }
	    	};

	    	var raiseHtml5Notification = function() {
	        	var bd = '';
	        	for (var u=0; u<uiHandler.newusers.length; u+=1) {
	        		bd = uiHandler.newusers[u].name + ' ' + (uiHandler.newusers[u].status === 'CONNECTED'?'(+)':'(-)');
	        	}
	        	if (bd !== '') {
	       		    var notification = new Notification($scope.resourceBundle.usertypeviewer, {
       		            body: bd,
       		            icon: uiHandler.newusers.length>1?'img/icons/favicon.ico':uiHandler.newusers[0].avatar,
       		            delay: 3000
	       		    });
	       	        notification.$on('click', function () {
	       	        	if (!uiHandler.focused) { window.focus(); }
	       	        	if (uiHandler.connectedClass!=='') { $scope.toggleConnected(); }
	       	        });
	        	}
	    	};

	    	var raiseAudioNotification = function() {
   				// Doit traditional
        		if (!uiHandler.focused && uiHandler.audible) {
	        		var readText = $scope.resourceBundle.onlinenews;
	        		if (uiHandler.newusers.length===1) {
	        			readText = (uiHandler.newusers[0].status === 'CONNECTED')?$scope.resourceBundle._('joinroom',uiHandler.newusers[0].name):$scope.resourceBundle._('uleaveroom',uiHandler.newusers[0].name);
	        		}
	        		var audio = document.getElementById('audiotts')?document.getElementById('audiotts'):document.createElement('audio');
	        		audio.setAttribute('id', 'audiotts');
	        		audio.setAttribute('src', '/chat/talk?text=' + encodeURIComponent(readText));
	        		audio.load();
	        		audio.play();
        		} else {
   					uiHandler.connNew = 'connected_now';
   					setTimeout(function(){ uiHandler.connNew = ''; uiHandler.safeApply($scope,function(){}); },3000);
   				}
	    	};

	    	$scope.updateUsers = function(result) {
	    		uiHandler.newusers = [];
		        if (uiHandler.users) {
		        	getNewUsersFromResult(result);
		        	removeOldUsers(result);
		        } else {
		            // If no users no windows
		        	uiHandler.newusers = result;
		        	uiHandler.users = result;
		        }
		        if (uiHandler.connectedClass!=='' || !uiHandler.focused) {
		        	if (uiHandler.notificationReady) {
		        		raiseHtml5Notification();
		        	} else {
		        		raiseAudioNotification();
		        	}
		        }
		        //uiHandler.users = result;
		    };

		    $scope.isOwner = function (id) {
    			return (id === uiHandler.ownerConnectionId) || ($scope.global.own === id);
    		};

    		var findUser = function(connectionId) {
		        if (uiHandler.users) {
		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].connectionId === connectionId){
		                    return uiHandler.users[i];
		                }
		            }
		        }
		        return null;
    		};

    		$scope.getUser = function (connectionId) {
		        if (connectionId === $scope.global.bot) { return {name:'loowid',avatar:'img/icons/favicon.ico'}; }
		        if (rtc._me === connectionId || (connectionId === $scope.global.own && uiHandler.isowner)) { return $scope.ui; }
		        if (!uiHandler.isowner && $scope.isOwner(connectionId)) { return {avatar:uiHandler.ownerAvatar,name:uiHandler.ownerName}; }
	        	return findUser(connectionId);
	  	 	};

	  		$scope.toggleConnected = function() {
	  			uiHandler.connectedClass=(uiHandler.connectedClass==='collapsed')?'':'collapsed';
	  			uiHandler.dashConn=(uiHandler.connectedClass==='collapsed')?'connected_collapsed':'';
	  		};

	    	$scope.getUserName = function (connectionId){
	    		if (uiHandler.isowner && rtc._me === connectionId){
	    			return uiHandler.name;
	    		}else if (!uiHandler.isowner && $scope.isOwner(connectionId)){
		            return uiHandler.ownerName;
		        }else{
		            var name = 'unkown user';

		            for (var i = 0; i < uiHandler.users.length; i+=1){
		                if (uiHandler.users[i].connectionId === connectionId){
		                    name = uiHandler.users[i].name;
		                    continue;
		                }
		            }
		            return name;
		        }
	    	};

	    	rtc.on ('owner_data_updated',function(data){
	    		uiHandler.ownerName = data.ownerName;
	    		uiHandler.ownerAvatar = data.ownerAvatar;
                $scope.changeOwnerConnectionId(data.ownerCid);
                $scope.changeWindowName(uiHandler.ownerConnectionId,uiHandler.ownerName);
                uiHandler.safeApply($scope,function(){});
            });

	    	var peerListUpdated = 'peer_list_updated';
	    	if (rtc._events[peerListUpdated]) {
				setTimeout(function(){ rtc.fire('peer_list_updated'); },100);
			}

	        rtc.uniqueon('peer_list_updated',function (){
				//We should wait for a few to ensure the record is stored in the db
				room.users (uiHandler.roomId,$scope.updateUsers);
			});

    	};
	};
}]);<|endoftext|>


<commit_before>import React, { Component } from "react";

const BASE_URL = "http://83.254.25.245:3001/";
const myFetch = (path, args) => {
  return fetch(BASE_URL + path, args);
};

class Admin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isAdmin: false,
      authCode: "",
      nickToRemove: ""
    };
    this.handleAuthCodeChange = this.handleAuthCodeChange.bind(this);
    this.handleNickToRemoveChange = this.handleNickToRemoveChange.bind(this);
    this.removeUser = this.removeUser.bind(this);
    this.attemptAuth = this.attemptAuth.bind(this);
    this.getIsAdmin = this.getIsAdmin.bind(this);
  }

  newDiscussion() {
    myFetch("/admin/discussion", { method: "POST" }).then(resp => {
      if (resp.status === 200) {
        console.log("discussion added");
      }
    });
  }

  endDiscussion() {
    myFetch("/admin/discussion", { method: "DELETE" }).then(resp => {
      if (resp.status === 200) {
        console.log("discussion ended");
      }
    });
  }

  removeUser() {
    myFetch("/admin/user", {
      method: "DELETE",
      body: JSON.stringify({ nick: this.state.nickToRemove })
    }).then(resp => {
      if (resp.status === 200) {
        console.log(this.state.nickToRemove + "Removed from discussion");
      }
    });
  }

  attemptAuth() {
    myFetch("/admin", {
      method: "POST",
      body: JSON.stringify({ code: this.state.authCode })
    }).then(resp => {
      if (resp.status === 200) {
        console.log(this.state.authCode + " was a success.");
        this.setState({ isAdmin: true });
      } else {
        console.log("Wrong code, try again");
      }
    });
  }

  handleNickToRemoveChange(event) {
    this.setState({ nickToRemove: event.target.value });
  }

  handleAuthCodeChange(event) {
    this.setState({ authCode: event.target.value });
  }

  getIsAdmin() {
    myFetch("/me").then(resp => {
      if (resp.status === 200) {
        resp.json().then(data => {
          console.log("data", data);
          this.setState({ isAdmin: data.isAdmin });
        });
      }
    });
  }

  render() {
    if (!this.props.isAdmin) {
      return (

          <input
            type="submit"
            value="Start new discussion"
            onClick={this.newDiscussion}
          />
          <input
            type="submit"
            value="End current discussion"
            onClick={this.endDiscussion}
          />
          <textarea
            value={this.state.nickToRemove}
            onChange={this.handleNickToRemoveChange}
          />
          <input type="submit" value="Remove user" onClick={this.removeUser} />

      );
    } else {
      return (

          <textarea
            value={this.state.authCode}
            onChange={this.handleAuthCodeChange}
          />
          <input
            type="submit"
            value="Attempt authorization"
            onClick={this.attemptAuth}
          />

      );
    }
  }
}

export default Admin;
<commit_msg>Correct isAdmin check<commit_after>import React, { Component } from "react";

const BASE_URL = "http://83.254.25.245:3001/";
const myFetch = (path, args) => {
  return fetch(BASE_URL + path, args);
};

class Admin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isAdmin: false,
      authCode: "",
      nickToRemove: ""
    };
    this.handleAuthCodeChange = this.handleAuthCodeChange.bind(this);
    this.handleNickToRemoveChange = this.handleNickToRemoveChange.bind(this);
    this.removeUser = this.removeUser.bind(this);
    this.attemptAuth = this.attemptAuth.bind(this);
    this.getIsAdmin = this.getIsAdmin.bind(this);
  }

  newDiscussion() {
    myFetch("/admin/discussion", { method: "POST" }).then(resp => {
      if (resp.status === 200) {
        console.log("discussion added");
      }
    });
  }

  endDiscussion() {
    myFetch("/admin/discussion", { method: "DELETE" }).then(resp => {
      if (resp.status === 200) {
        console.log("discussion ended");
      }
    });
  }

  removeUser() {
    myFetch("/admin/user", {
      method: "DELETE",
      body: JSON.stringify({ nick: this.state.nickToRemove })
    }).then(resp => {
      if (resp.status === 200) {
        console.log(this.state.nickToRemove + "Removed from discussion");
      }
    });
  }

  attemptAuth() {
    myFetch("/admin", {
      method: "POST",
      body: JSON.stringify({ code: this.state.authCode })
    }).then(resp => {
      if (resp.status === 200) {
        console.log(this.state.authCode + " was a success.");
        this.setState({ isAdmin: true });
      } else {
        console.log("Wrong code, try again");
      }
    });
  }

  handleNickToRemoveChange(event) {
    this.setState({ nickToRemove: event.target.value });
  }

  handleAuthCodeChange(event) {
    this.setState({ authCode: event.target.value });
  }

  getIsAdmin() {
    myFetch("/me").then(resp => {
      if (resp.status === 200) {
        resp.json().then(data => {
          console.log("data", data);
          this.setState({ isAdmin: data.isAdmin });
        });
      }
    });
  }

  render() {
    if (this.state.isAdmin) {
      return (

          <input
            type="submit"
            value="Start new discussion"
            onClick={this.newDiscussion}
          />
          <input
            type="submit"
            value="End current discussion"
            onClick={this.endDiscussion}
          />
          <textarea
            value={this.state.nickToRemove}
            onChange={this.handleNickToRemoveChange}
          />
          <input type="submit" value="Remove user" onClick={this.removeUser} />

      );
    } else {
      return (

          <textarea
            value={this.state.authCode}
            onChange={this.handleAuthCodeChange}
          />
          <input
            type="submit"
            value="Attempt authorization"
            onClick={this.attemptAuth}
          />

      );
    }
  }
}

export default Admin;
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import {createStore} from 'redux'
import App from './app/App';
import RootReducer from './app/reducers';
import registerServiceWorker from './registerServiceWorker';

let store = createStore(RootReducer);

const unsubscribe = store.subscribe(() =>
    console.log('New State: ', store.getState())
);

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root'));
registerServiceWorker();
<commit_msg>Extract store<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import App from './app/App';
import registerServiceWorker from './registerServiceWorker';
import store from "./app/store";

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
    document.getElementById('root'));
registerServiceWorker();
<|endoftext|>