<commit_before>var all, util, sort, random, itertools, functools;

util = require( "util" );
sort = require( "aureooms-js-sort" );
random = require( "aureooms-js-random" );
itertools = require( "aureooms-js-itertools" );
functools = require( "aureooms-js-functools" );

all = function ( tmpl_name, tmpl, diffname, diff, n ) {

	var name = util.format( "binary search tree (%s, %s, %d)", tmpl_name, diffname, n );

	console.log( name );

	test( name, function () {

		var SplayTree = tmpl(diff);
		var sample = random.__sample__(random.randint);
		var shuffle = random.__shuffle__(sample);

		var bt = new SplayTree();
		var a = [];

		var i = n, x;

		while ( i-- ) {
			x = Math.random();
			bt.insert(x);
			a.push(x);
		}

		a.sort( diff );

		var b = [], c = [], d, e, half = Math.floor(n/2);

		// CHECK CONTENT
		bt.in_order_traversal(function(v){ b.push(v); });
		deepEqual(b, a, "check content");

		// PREPARE FOR CHECKING PURPOSES
		i = n;
		while(i--) a[i] = [true, a[i]];

		// CHECK FIND SORTED
		i = n;
		while(i--){
			b[i] = bt.find(a[i][1]);
		}
		deepEqual(b, a, "check find sorted");

		// CHECK FIND SHUFFLED
		shuffle(a, 0, n);
		i = n;
		while (i--) b[i] = bt.find(a[i][1]);
		deepEqual(b, a, "check find shuffled");

		var remove = function(l, r, p, q, txt){
			// REMOVE
			i = r;
			while(i --> l){
				bt.remove(a[i][1]);
				a[i][0] = false;
			}

			// CHECK CONTENT AFTER REMOVE
			d = [];
			e = [];
			for(i = p; i < q; ++i) e.push(a[i][1]);
			e.sort(diff);
			bt.in_order_traversal(function(v){ d.push(v); });
			deepEqual(d, e, "check content " + txt);

			// CHECK FIND AFTER REMOVE
			i = n;
			while(i--){
				b[i] = bt.find(a[i][1])[0];
				c[i] = a[i][0];
			}

			deepEqual(b, c, "check find " + txt);

			// TRY REMOVING TWICE
			i = r;
			while(i --> l) bt.remove(a[i][1]);
		};

		remove(half, n, 0, half, "after remove half");

		// ADD NEW ELEMENTS
		i = n;
		while(i --> half){
			x = Math.random();
			bt.insert(x);
			a[i] = [true, x];
		}

		// CHECK CONTENT NEW ELEMENTS
		d = [];
		e = [];
		for(i = 0; i < n; ++i) e.push(a[i][1]);
		e.sort(diff);
		bt.in_order_traversal(function(v){ d.push(v); });
		deepEqual(d, e, "check content new elements");

		// CHECK FIND NEW ELEMENTS
		i = n;
		while (i--) b[i] = bt.find(a[i][1]);
		deepEqual(b, a, "check find new elements");

		remove(0, half, half, n,  "after remove first half");
		remove(half, n, 0, 0,  "after remove second half");

	});

};

itertools.product( [

[
	["splay_tree_t", algo.splay_tree_t],
	["splay_tree_2_t", algo.splay_tree_2_t],
	["splay_tree_3_t", algo.splay_tree_3_t],
	["splay_tree_4_t", algo.splay_tree_4_t],
	["splay_tree_5_t", algo.splay_tree_5_t],
],

[
	["increasing", sort.increasing],
	["decreasing", sort.decreasing]
],

[1, 16, 17, 31, 32, 33, 127, 128, 129]

], 1, [] ).forEach( functools.partial( functools.star, null, [all] ) );
<commit_msg>style<commit_after>var all, util, sort, random, itertools, functools, shuffle;

util = require( "util" );
sort = require( "aureooms-js-sort" );
random = require( "aureooms-js-random" );
itertools = require( "aureooms-js-itertools" );
functools = require( "aureooms-js-functools" );

shuffle = random.__shuffle__( random.__sample__( random.randint ) );

all = function ( BSTname, BST, diffname, diff, n ) {

	var title;

	title = util.format( "binary search tree (%s, %s, %d)", BSTname, diffname, n );

	console.log( title );

	test( title, function () {

		var SplayTree, bst, a, b, c, d, e, half, i, x, remove;

		SplayTree = BST( diff );
		bst = new SplayTree();

		a = [];
		i = n;

		while ( i-- ) {
			x = Math.random();
			bst.insert( x );
			a.push( x );
		}

		a.sort( diff );

		b = [];
		c = [];
		half = Math.floor( n / 2 );

		// CHECK CONTENT
		bst.in_order_traversal( function ( v ) { b.push( v ); } );
		deepEqual(b, a, "check content");

		// PREPARE FOR CHECKING PURPOSES
		i = n;
		while ( i-- ) {
			a[i] = [true, a[i]];
		}

		// CHECK FIND SORTED
		i = n;
		while ( i-- ) {
			b[i] = bst.find( a[i][1] );
		}
		deepEqual( b, a, "check find sorted" );

		// CHECK FIND SHUFFLED
		shuffle( a, 0, n );
		i = n;
		while ( i-- ) {
			b[i] = bst.find( a[i][1] );
		}
		deepEqual( b, a, "check find shuffled" );

		remove = function(l, r, p, q, txt){

			// REMOVE

			i = r;
			while ( i --> l ) {
				bst.remove( a[i][1] );
				a[i][0] = false;
			}

			// CHECK CONTENT AFTER REMOVE

			d = [];
			e = [];
			for ( i = p ; i < q ; ++i ) {
				e.push( a[i][1] );
			}

			e.sort( diff );
			bst.in_order_traversal( function ( v ) { d.push(v); } );
			deepEqual( d, e, "check content " + txt );

			// CHECK FIND AFTER REMOVE

			i = n;
			while ( i-- ) {
				b[i] = bst.find(a[i][1])[0];
				c[i] = a[i][0];
			}

			deepEqual( b, c, "check find " + txt );

			// TRY REMOVING TWICE

			i = r;
			while ( i --> l ) {
				bst.remove(a[i][1]);
			}

		};

		remove( half, n, 0, half, "after remove half" );

		// ADD NEW ELEMENTS
		i = n;
		while ( i --> half ) {
			x = Math.random();
			bst.insert( x );
			a[i] = [true, x];
		}

		// CHECK CONTENT NEW ELEMENTS

		d = [];
		e = [];
		for ( i = 0 ; i < n ; ++i ) {
			e.push( a[i][1] );
		}

		e.sort( diff );
		bst.in_order_traversal( function ( v ) { d.push(v); } );
		deepEqual( d, e, "check content new elements" );

		// CHECK FIND NEW ELEMENTS

		i = n;

		while ( i-- ) {
			b[i] = bst.find( a[i][1] );
		}

		deepEqual( b, a, "check find new elements" );

		remove( 0, half, half, n,  "after remove first half" );
		remove( half, n, 0, 0,  "after remove second half" );

	});

};

itertools.product( [

[
	["splay_tree_t", algo.splay_tree_t],
	["splay_tree_2_t", algo.splay_tree_2_t],
	["splay_tree_3_t", algo.splay_tree_3_t],
	["splay_tree_4_t", algo.splay_tree_4_t],
	["splay_tree_5_t", algo.splay_tree_5_t],
],

[
	["increasing", sort.increasing],
	["decreasing", sort.decreasing]
],

[1, 16, 17, 31, 32, 33, 127, 128, 129]

], 1, [] ).forEach( functools.partial( functools.star, null, [all] ) );
<|endoftext|>


<commit_before>/*global defineSuite*/
defineSuite([
         'Core/deprecationWarning'
     ], function(
         deprecationWarning) {
    "use strict";
    /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor,console*/

    it('logs a warning', function() {
        var consoleLog = console.log;
        var spy = jasmine.createSpy('listener');
        console.log = spy;

        deprecationWarning('identifier', 'message');
        deprecationWarning('identifier', 'message');
        deprecationWarning('another identifier', 'another message');

        expect(spy.calls.length).toEqual(2);
        expect(spy.calls[0].args[0]).toBe('message');
        expect(spy.calls[1].args[0]).toBe('another message');

        console.log = consoleLog;
    });

    it('throws without identifier', function() {
        expect(function() {
            deprecationWarning();
        }).toThrowDeveloperError();
    });

    it('throws without message', function() {
        expect(function() {
            deprecationWarning('identifier');
        }).toThrowDeveloperError();
    });
});<commit_msg>Use spyOn<commit_after>/*global defineSuite*/
defineSuite([
         'Core/deprecationWarning'
     ], function(
         deprecationWarning) {
    "use strict";
    /*global jasmine,describe,xdescribe,it,xit,expect,beforeEach,afterEach,beforeAll,afterAll,spyOn,runs,waits,waitsFor,console*/

    it('logs a warning', function() {
        spyOn(console, 'log');

        deprecationWarning('identifier', 'message');
        deprecationWarning('identifier', 'message');
        deprecationWarning('another identifier', 'another message');

        expect(console.log.calls.length).toEqual(2);
        expect(console.log.calls[0].args[0]).toBe('message');
        expect(console.log.calls[1].args[0]).toBe('another message');
    });

    it('throws without identifier', function() {
        expect(function() {
            deprecationWarning();
        }).toThrowDeveloperError();
    });

    it('throws without message', function() {
        expect(function() {
            deprecationWarning('identifier');
        }).toThrowDeveloperError();
    });
});<|endoftext|>


<commit_before>/* global describe, it, expect */

var chai = require('chai');
var expect = require('chai').expect;
var sinon = require('sinon');
var flowstate = require('flowstate');
var factory = require('../../../../app/oob/http/handlers/verify');

describe('oob/http/handlers/verify', function() {

  it('should export factory function', function() {
    expect(factory).to.be.a('function');
  });

  it('should be annotated', function() {
    expect(factory['@implements']).to.be.undefined;
    expect(factory['@singleton']).to.be.undefined;
  });

  describe('handler', function() {
    var manager = new flowstate.Manager();
    manager.use('login', {
      resume:  [
        function(req, res, next) {
          res.end();
        }
      ]
    })

    function ceremony(name) {
      return manager.flow.apply(manager, arguments);
    }

    function parse(type) {
      return function(req, res, next) {
        req.__ = req.__ || {};
        req.__.supportedMediaType = type;
        next();
      };
    }

    function csrfProtection() {
      return function(req, res, next) {
        req.csrfToken = function() {
          return 'xxxxxxxx';
        };

        next();
      };
    }

    function authenticate(method) {
      return function(req, res, next) {
        req.authInfo = req.authInfo || { methods: [] };
        req.authInfo.methods.push(method);
        req.authInfo.pending = false;
        next();
      };
    }

    describe('authenticating', function() {
      var request, response;

      before(function(done) {
        var handler = factory(parse, csrfProtection, authenticate, ceremony);

        chai.express.handler(handler)
          .req(function(req) {
            request = req;
          })
          .res(function(res) {
            response = res;
          })
          .end(function() {
            done();
          })
          .dispatch();
      });

      it('should parse request body', function() {
        expect(request.__.supportedMediaType).to.equal('application/x-www-form-urlencoded');
      });

      it('should provide CSRF protection', function() {
        expect(request.csrfToken()).to.equal('xxxxxxxx');
      });

      it('should authenticate', function() {
        expect(request.authInfo).to.deep.equal({
          methods: [ 'state', 'oob' ],
          pending: false
        });
      });

      it('should set yieldState', function() {
        expect(request.yieldState).to.deep.equal({
          name: 'login/oob'
        });
        expect(request.yieldState.isComplete()).to.equal(true);
      });

      it('should set state', function() {
        expect(request.state).to.deep.equal({
          name: 'login'
        });
        expect(request.state.isComplete()).to.equal(false);
      });

      it('should resume', function() {
        expect(response.statusCode).to.equal(200);
      });
    });

  }); // handler

});
<commit_msg>Add tests.<commit_after>/* global describe, it, expect */

var chai = require('chai');
var expect = require('chai').expect;
var sinon = require('sinon');
var flowstate = require('flowstate');
var factory = require('../../../../app/oob/http/handlers/verify');

describe('oob/http/handlers/verify', function() {

  it('should export factory function', function() {
    expect(factory).to.be.a('function');
  });

  it('should be annotated', function() {
    expect(factory['@implements']).to.be.undefined;
    expect(factory['@singleton']).to.be.undefined;
  });

  describe('handler', function() {
    var manager = new flowstate.Manager();
    manager.use('login', {
      resume:  [
        function(req, res, next) {
          res.end();
        }
      ]
    })
    manager.use('login/oob', {
      prompt:  [
        function(req, res, next) {
          res.statusCode = 302;
          res.end();
        }
      ]
    })

    function ceremony(name) {
      return manager.flow.apply(manager, arguments);
    }

    function parse(type) {
      return function(req, res, next) {
        req.__ = req.__ || {};
        req.__.supportedMediaType = type;
        next();
      };
    }

    function csrfProtection() {
      return function(req, res, next) {
        req.csrfToken = function() {
          return 'xxxxxxxx';
        };

        next();
      };
    }

    function authenticate(method) {
      return function(req, res, next) {
        req.authInfo = req.authInfo || { methods: [] };
        req.authInfo.methods.push(method);
        req.authInfo.pending = false;
        next();
      };
    }

    describe.skip('authenticating', function() {
      var request, response;

      before(function(done) {
        var handler = factory(parse, csrfProtection, authenticate, ceremony);

        chai.express.handler(handler)
          .req(function(req) {
            request = req;
          })
          .res(function(res) {
            response = res;
          })
          .end(function() {
            done();
          })
          .dispatch();
      });

      it('should parse request body', function() {
        expect(request.__.supportedMediaType).to.equal('application/x-www-form-urlencoded');
      });

      it('should provide CSRF protection', function() {
        expect(request.csrfToken()).to.equal('xxxxxxxx');
      });

      it('should authenticate', function() {
        expect(request.authInfo).to.deep.equal({
          methods: [ 'state', 'oob' ],
          pending: false
        });
      });

      it('should set yieldState', function() {
        expect(request.yieldState).to.deep.equal({
          name: 'login/oob'
        });
        expect(request.yieldState.isComplete()).to.equal(true);
      });

      it('should set state', function() {
        expect(request.state).to.deep.equal({
          name: 'login'
        });
        expect(request.state.isComplete()).to.equal(false);
      });

      it('should resume', function() {
        expect(response.statusCode).to.equal(200);
      });
    }); // authenticating

    describe('re-prompting a pending challenge', function() {
      var request, response;

      function authenticate(method) {
        return function(req, res, next) {
          req.authInfo = req.authInfo || { methods: [] };
          req.authInfo.methods.push(method);
          next();
        };
      }

      before(function(done) {
        var handler = factory(parse, csrfProtection, authenticate, ceremony);

        chai.express.handler(handler)
          .req(function(req) {
            request = req;
          })
          .res(function(res) {
            response = res;
          })
          .end(function() {
            done();
          })
          .dispatch();
      });

      it('should parse request body', function() {
        expect(request.__.supportedMediaType).to.equal('application/x-www-form-urlencoded');
      });

      it('should provide CSRF protection', function() {
        expect(request.csrfToken()).to.equal('xxxxxxxx');
      });

      it('should authenticate', function() {
        expect(request.authInfo).to.deep.equal({
          methods: [ 'state', 'oob' ]
        });
      });

      it('should not set yieldState', function() {
        expect(request.yieldState).to.be.undefined;
      });

      it('should set state', function() {
        expect(request.state).to.deep.equal({
          name: 'login/oob'
        });
        expect(request.state.isComplete()).to.equal(false);
      });

      it('should prompt', function() {
        expect(response.statusCode).to.equal(302);
      });
    }); // re-prompting a pending challenge

  }); // handler

});
<|endoftext|>


<commit_before>const { generateCalendarObj } = require('../utilities/jwt');

export default function deleteEvent(options) {
  const { calendarId, eventId } = options;
  return new Promise(async (res, rej) => {
    const calendar = await generateCalendarObj();
    // const timeMin = timeStart || moment().subtract(1, 'hours').toISOString();
    calendar.events.delete(
      {
        calendarId,
        eventId,
      },
      async (err, { data: response }) => {
        if (err) {
          rej(err);
        } else {
          res(response);
        }
      },
    );
  });
}
<commit_msg>deleted logic modified<commit_after>const { generateCalendarObj } = require('../utilities/jwt');

export default function deleteEvent(options) {
  const { calendarId, eventId } = options;
  return new Promise(async (res, rej) => {
    const calendar = await generateCalendarObj();
    // const timeMin = timeStart || moment().subtract(1, 'hours').toISOString();
    calendar.events.delete(
      {
        calendarId,
        eventId,
      },
      async (err, response) => {
        if (err) {
          rej(err);
        } else {
          res(response);
        }
      },
    );
  });
}
<|endoftext|>


<commit_before>/*global describe, beforeEach, module, inject, it, angular, expect */
/*jslint nomen: true */
describe('Directive: vjs.directive.js', function () {
    'use strict';

    // load the directive's module
    beforeEach(module('vjsVideoApp'));

    var vidStr = "<video vjs-video></video>",
        multipleVidStr = "
<video vjs-video></video><video vjs-video></video>
",
        nonVidStr = "
",
        vidContainerStr = "
<video></video>
",
        vidElementContainerStr = "<vjs-video-container><video></video></vjs-video-container>",
        nonVidContainerStr = "

",
        multVidsContainerStr = "
<video></video><video></video>
",
        //vidContainerWithDimsStr = "
<video width='320' height='320'></video>
",
        scope,
        $compile;

    //load templates
    beforeEach(module('scripts/directives/vjs.container.html'));

    beforeEach(inject(function ($rootScope, _$compile_) {
        scope = $rootScope.$new();
        $compile = _$compile_;
    }));

    function compileAndLink(htmlStr, s) {
        var el = angular.element(htmlStr);

        el = $compile(el)(s);
        scope.$digest();

        return el;
    }

    describe('vjs-video', function () {
        it('should attach videojs to the video tag', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidStr, scope);
            expect(el.hasClass('vjs-tech')).to.be.true;
        });

        it('should attach videojs to multiple video tags', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(multipleVidStr, scope);
            expect(el[0].querySelectorAll('.vjs-tech').length).to.equal(2);
        });

        it('should throw an error if not attached to a video tag', function () {
            expect(function () {
                var el = compileAndLink(nonVidStr, scope);
            }).throws(Error);

            expect(function () {
                var el = compileAndLink(vidStr, scope);
            }).to.not.throw(Error);
        });

    });

    describe('vjs-video-container', function () {
        it('should throw an error if container does not have a video tag defined', function () {
            expect(function () {
                var el = compileAndLink(nonVidContainerStr, scope);
            }).throws(Error, 'video tag must be defined within container directive!');
        });

        it('should throw an error if container defines more than one video tag', function () {
            expect(function () {
                compileAndLink(multVidsContainerStr, scope);
            }).throws(Error, 'only one video can be defined within the container directive!');
        });

        it('should attach videojs to the video tag', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidContainerStr, scope);
            expect(el.find('video').hasClass('vjs-tech')).to.be.true;
        });

        it('should register as the vjs-video-container element', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidElementContainerStr, scope);
            expect(el.find('video').hasClass('vjs-tech')).to.be.true;
        });

//        it('should set width and height of included video to auto', function () {
//            var el = compileAndLink(vidContainerWithDimsStr, scope),
//                vid = el.find('video');
//
//            expect(vid.attr('width')).to.equal('auto');
//            expect(vid.attr('height')).to.equal('auto');
//
//        });
    });

    describe('missing library', function () {
        it('should throw an error if videojs is not loaded', function () {
            //TOOD: currently, this must be the last test
            //      because it destroys the reference to videojs
            //      find a way to fix that
            expect(function () {
                var vjs = window.videojs,
                    el;

                window.videojs = undefined;
                el = compileAndLink(vidStr, scope);
                window.videojs = vjs;
            }).throws(Error);
        });
    });
});
<commit_msg>Added tests for scenaries that should throw errors - #1<commit_after>/*global describe, beforeEach, module, inject, it, angular, expect */
/*jslint nomen: true */
describe('Directive: vjs.directive.js', function () {
    'use strict';

    // load the directive's module
    beforeEach(module('vjsVideoApp'));

    var vidStr = "<video vjs-video></video>",
        multipleVidStr = "
<video vjs-video></video><video vjs-video></video>
",
        nonVidStr = "
",
        vidContainerStr = "
<video></video>
",
        vidElementContainerStr = "<vjs-video-container><video></video></vjs-video-container>",
        nonVidContainerStr = "

",
        multVidsContainerStr = "
<video></video><video></video>
",
        //vidContainerWithDimsStr = "
<video width='320' height='320'></video>
",
        vidRatioCharStr = "
<video></video>
",
        vidRatioInvalidStr = "
<video></video>
",
        vidRatioInvalidWStr = "
<video></video>
",
        vidRatioInvalidHStr = "
<video></video>
",
        vidRatioHeightZeroStr = "
<video></video>
",
        vidRatioWidthZeroStr = "
<video></video>
",
        scope,
        $compile;

    //load templates
    beforeEach(module('scripts/directives/vjs.container.html'));

    beforeEach(inject(function ($rootScope, _$compile_) {
        scope = $rootScope.$new();
        $compile = _$compile_;
    }));

    function compileAndLink(htmlStr, s) {
        var el = angular.element(htmlStr);

        el = $compile(el)(s);
        scope.$digest();

        return el;
    }

    describe('vjs-video', function () {
        it('should attach videojs to the video tag', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidStr, scope);
            expect(el.hasClass('vjs-tech')).to.be.true;
        });

        it('should attach videojs to multiple video tags', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(multipleVidStr, scope);
            expect(el[0].querySelectorAll('.vjs-tech').length).to.equal(2);
        });

        it('should throw an error if not attached to a video tag', function () {
            expect(function () {
                var el = compileAndLink(nonVidStr, scope);
            }).throws(Error);

            expect(function () {
                var el = compileAndLink(vidStr, scope);
            }).to.not.throw(Error);
        });

    });

    describe('vjs-video-container', function () {
        it('should throw an error if container does not have a video tag defined', function () {
            expect(function () {
                var el = compileAndLink(nonVidContainerStr, scope);
            }).throws(Error, 'video tag must be defined within container directive!');
        });

        it('should throw an error if container defines more than one video tag', function () {
            expect(function () {
                compileAndLink(multVidsContainerStr, scope);
            }).throws(Error, 'only one video can be defined within the container directive!');
        });

        it('should attach videojs to the video tag', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidContainerStr, scope);
            expect(el.find('video').hasClass('vjs-tech')).to.be.true;
        });

        it('should register as the vjs-video-container element', function () {
            //videojs should add at vjs-tech class to the element
            var el = compileAndLink(vidElementContainerStr, scope);
            expect(el.find('video').hasClass('vjs-tech')).to.be.true;
        });

//        it('should set width and height of included video to auto', function () {
//            var el = compileAndLink(vidContainerWithDimsStr, scope),
//                vid = el.find('video');
//
//            expect(vid.attr('width')).to.equal('auto');
//            expect(vid.attr('height')).to.equal('auto');
//
//        });

        describe('vjs-ratio', function () {
            var ratioErrMsg = 'the ratio must either be "wide", "standard" or decimal values in the format of w/h',
                ratioZeroErrMsg = 'neither the width or height ratio can be zero!';

            it('should throw an error if an invalid string is provided', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioCharStr, scope);
                }).to.throw(Error, ratioErrMsg);
            });

            it('should throw an error if invalid ratio is supplied', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioInvalidStr, scope);
                }).to.throw(Error, ratioErrMsg);
            });

            it('should throw an error if width is a string', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioInvalidWStr, scope);
                }).to.throw(Error, ratioErrMsg);
            });

            it('should throw an error if height is a string', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioInvalidHStr, scope);
                }).to.throw(Error, ratioErrMsg);
            });

            it('should throw an error if width is zero', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioWidthZeroStr, scope);
                }).to.throw(Error, ratioZeroErrMsg);
            });

            it('should throw an error if height is zero', function () {
                expect(function () {
                    var el = compileAndLink(vidRatioHeightZeroStr, scope);
                }).to.throw(Error, ratioZeroErrMsg);
            });
        });
    });

    describe('missing library', function () {
        it('should throw an error if videojs is not loaded', function () {
            //TOOD: currently, this must be the last test
            //      because it destroys the reference to videojs
            //      find a way to fix that
            expect(function () {
                var vjs = window.videojs,
                    el;

                window.videojs = undefined;
                el = compileAndLink(vidStr, scope);
                window.videojs = vjs;
            }).throws(Error);
        });
    });
});
<|endoftext|>


<commit_before>/* global config, APP, chrome, $, alert */
/* jshint -W003 */
var RTCBrowserType = require("../RTC/RTCBrowserType");
var AdapterJS = require("../RTC/adapter.screenshare");
var DesktopSharingEventTypes
    = require("../../service/desktopsharing/DesktopSharingEventTypes");

/**
 * Indicates whether the Chrome desktop sharing extension is installed.
 * @type {boolean}
 */
var chromeExtInstalled = false;

/**
 * Indicates whether an update of the Chrome desktop sharing extension is
 * required.
 * @type {boolean}
 */
var chromeExtUpdateRequired = false;

/**
 * Whether the jidesha extension for firefox is installed for the domain on
 * which we are running. Null designates an unknown value.
 * @type {null}
 */
var firefoxExtInstalled = null;

/**
 * If set to true, detection of an installed firefox extension will be started
 * again the next time obtainScreenOnFirefox is called (e.g. next time the
 * user tries to enable screen sharing).
 */
var reDetectFirefoxExtension = false;

/**
 * Handles obtaining a stream from a screen capture on different browsers.
 */
function ScreenObtainer(){
}

/**
 * The EventEmitter to use to emit events.
 * @type {null}
 */
ScreenObtainer.prototype.eventEmitter = null;

/**
 * Initializes the function used to obtain a screen capture (this.obtainStream).
 *
 * If the browser is Chrome, it uses the value of
 * 'config.desktopSharingChromeMethod' (or 'config.desktopSharing') to * decide
 * whether to use the a Chrome extension (if the value is 'ext'), use the
 * "screen" media source (if the value is 'webrtc'), or disable screen capture
 * (if the value is other).
 * Note that for the "screen" media source to work the
 * 'chrome://flags/#enable-usermedia-screen-capture' flag must be set.
 */
ScreenObtainer.prototype.init = function(eventEmitter) {
    this.eventEmitter = eventEmitter;
    var obtainDesktopStream = null;

    if (RTCBrowserType.isFirefox())
        initFirefoxExtensionDetection();

    // TODO remove this, config.desktopSharing is deprecated.
    var chromeMethod =
        (config.desktopSharingChromeMethod || config.desktopSharing);

    if (RTCBrowserType.isTemasysPluginUsed()) {
        if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
            console.info("Screensharing not supported by this plugin version");
        } else if (!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) {
            console.info(
                "Screensharing not available with Temasys plugin on this site");
        } else {
            obtainDesktopStream = obtainWebRTCScreen;
            console.info("Using Temasys plugin for desktop sharing");
        }
    } else if (RTCBrowserType.isChrome()) {
        if (chromeMethod == "ext") {
            if (RTCBrowserType.getChromeVersion() >= 34) {
                obtainDesktopStream = obtainScreenFromExtension;
                console.info("Using Chrome extension for desktop sharing");
                initChromeExtension();
            } else {
                console.info("Chrome extension not supported until ver 34");
            }
        } else if (chromeMethod == "webrtc") {
            obtainDesktopStream = obtainWebRTCScreen;
            console.info("Using Chrome WebRTC for desktop sharing");
        }
    } else if (RTCBrowserType.isFirefox()) {
        if (config.desktopSharingFirefoxDisabled) {
            obtainDesktopStream = null;
        } else if (window.location.protocol === "http:"){
            console.log("Screen sharing is not supported over HTTP. Use of " +
                "HTTPS is required.");
            obtainDesktopStream = null;
        } else {
            obtainDesktopStream = this.obtainScreenOnFirefox;
        }

    }

    if (!obtainDesktopStream) {
        console.info("Desktop sharing disabled");
    }

    ScreenObtainer.prototype.obtainStream = obtainDesktopStream;
};

ScreenObtainer.prototype.obtainStream = null;

/**
 * Checks whether obtaining a screen capture is supported in the current
 * environment.
 * @returns {boolean}
 */
ScreenObtainer.prototype.isSupported = function() {
    return !!this.obtainStream;
};

/**
 * Obtains a desktop stream using getUserMedia.
 * For this to work on Chrome, the
 * 'chrome://flags/#enable-usermedia-screen-capture' flag must be enabled.
 *
 * On firefox, the document's domain must be white-listed in the
 * 'media.getusermedia.screensharing.allowed_domains' preference in
 * 'about:config'.
 */
function obtainWebRTCScreen(streamCallback, failCallback) {
    APP.RTC.getUserMediaWithConstraints(
        ['screen'],
        streamCallback,
        failCallback
    );
}

/**
 * Constructs inline install URL for Chrome desktop streaming extension.
 * The 'chromeExtensionId' must be defined in config.js.
 * @returns {string}
 */
function getWebStoreInstallUrl()
{
    //TODO remove chromeExtensionId (deprecated)
    return "https://chrome.google.com/webstore/detail/" +
        (config.desktopSharingChromeExtId || config.chromeExtensionId);
}

/**
 * Checks whether an update of the Chrome extension is required.
 * @param minVersion minimal required version
 * @param extVersion current extension version
 * @returns {boolean}
 */
function isUpdateRequired(minVersion, extVersion) {
    try {
        var s1 = minVersion.split('.');
        var s2 = extVersion.split('.');

        var len = Math.max(s1.length, s2.length);
        for (var i = 0; i < len; i++) {
            var n1 = 0,
                n2 = 0;

            if (i < s1.length)
                n1 = parseInt(s1[i]);
            if (i < s2.length)
                n2 = parseInt(s2[i]);

            if (isNaN(n1) || isNaN(n2)) {
                return true;
            } else if (n1 !== n2) {
                return n1 > n2;
            }
        }

        // will happen if both versions have identical numbers in
        // their components (even if one of them is longer, has more components)
        return false;
    }
    catch (e) {
        console.error("Failed to parse extension version", e);
        APP.UI.messageHandler.showError("dialog.error",
            "dialog.detectext");
        return true;
    }
}

function checkChromeExtInstalled(callback) {
    if (!chrome || !chrome.runtime) {
        // No API, so no extension for sure
        callback(false, false);
        return;
    }
    chrome.runtime.sendMessage(
        //TODO: remove chromeExtensionId (deprecated)
        (config.desktopSharingChromeExtId || config.chromeExtensionId),
        { getVersion: true },
        function (response) {
            if (!response || !response.version) {
                // Communication failure - assume that no endpoint exists
                console.warn(
                    "Extension not installed?: ", chrome.runtime.lastError);
                callback(false, false);
                return;
            }
            // Check installed extension version
            var extVersion = response.version;
            console.log('Extension version is: ' + extVersion);
            //TODO: remove minChromeExtVersion (deprecated)
            var updateRequired
                = isUpdateRequired(
                    (config.desktopSharingChromeMinExtVersion ||
                        config.minChromeExtVersion),
                    extVersion);
            callback(!updateRequired, updateRequired);
        }
    );
}

function doGetStreamFromExtension(streamCallback, failCallback) {
    // Sends 'getStream' msg to the extension.
    // Extension id must be defined in the config.
    chrome.runtime.sendMessage(
        config.chromeExtensionId,
        {
            getStream: true,
            //TODO: remove desktopSharingSources (deprecated).
            sources: (config.desktopSharingChromeSources ||
                config.desktopSharingSources)
        },
        function (response) {
            if (!response) {
                failCallback(chrome.runtime.lastError);
                return;
            }
            console.log("Response from extension: " + response);
            if (response.streamId) {
                APP.RTC.getUserMediaWithConstraints(
                    ['desktop'],
                    function (stream) {
                        streamCallback(stream);
                    },
                    failCallback,
                    null, null, null,
                    response.streamId);
            } else {
                failCallback("Extension failed to get the stream");
            }
        }
    );
}

/**
 * Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop'
 * stream for returned stream token.
 */
function obtainScreenFromExtension(streamCallback, failCallback) {
    if (chromeExtInstalled) {
        doGetStreamFromExtension(streamCallback, failCallback);
    } else {
        if (chromeExtUpdateRequired) {
            alert(
                'Jitsi Desktop Streamer requires update. ' +
                'Changes will take effect after next Chrome restart.');
        }

        chrome.webstore.install(
            getWebStoreInstallUrl(),
            function (arg) {
                console.log("Extension installed successfully", arg);
                chromeExtInstalled = true;
                // We need to give a moment for the endpoint to become available
                window.setTimeout(function () {
                    doGetStreamFromExtension(streamCallback, failCallback);
                }, 500);
            },
            function (arg) {
                console.log("Failed to install the extension", arg);
                failCallback(arg);
                APP.UI.messageHandler.showError("dialog.error",
                    "dialog.failtoinstall");
            }
        );
    }
}

/**
 * Initializes <link rel=chrome-webstore-item /> with extension id set in
 * config.js to support inline installs. Host site must be selected as main
 * website of published extension.
 */
function initInlineInstalls()
{
    $("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
}

function initChromeExtension() {
    // Initialize Chrome extension inline installs
    initInlineInstalls();
    // Check if extension is installed
    checkChromeExtInstalled(function (installed, updateRequired) {
        chromeExtInstalled = installed;
        chromeExtUpdateRequired = updateRequired;
        console.info(
            "Chrome extension installed: " + chromeExtInstalled +
            " updateRequired: " + chromeExtUpdateRequired);
    });
}

/**
 * Obtains a screen capture stream on Firefox.
 * @param callback
 * @param errorCallback
 */
ScreenObtainer.prototype.obtainScreenOnFirefox =
       function (callback, errorCallback) {
    var self = this;
    var extensionRequired = false;
    if (config.desktopSharingFirefoxMaxVersionExtRequired === -1 ||
        (config.desktopSharingFirefoxMaxVersionExtRequired >= 0 &&
            RTCBrowserType.getFirefoxVersion() <=
                config.desktopSharingFirefoxMaxVersionExtRequired)) {
        extensionRequired = true;
        console.log("Jidesha extension required on firefox version " +
            RTCBrowserType.getFirefoxVersion());
    }

    if (!extensionRequired || firefoxExtInstalled === true) {
        obtainWebRTCScreen(callback, errorCallback);
        return;
    }

    if (reDetectFirefoxExtension) {
        reDetectFirefoxExtension = false;
        initFirefoxExtensionDetection();
    }

    // Give it some (more) time to initialize, and assume lack of extension if
    // it hasn't.
    if (firefoxExtInstalled === null) {
        window.setTimeout(
            function() {
                if (firefoxExtInstalled === null)
                    firefoxExtInstalled = false;
                self.obtainScreenOnFirefox(callback, errorCallback);
            },
            300
        );
        console.log("Waiting for detection of jidesha on firefox to finish.");
        return;
    }

    // We need an extension and it isn't installed.

    // Make sure we check for the extension when the user clicks again.
    firefoxExtInstalled = null;
    reDetectFirefoxExtension = true;

    // Prompt the user to install the extension
    this.eventEmitter.emit(DesktopSharingEventTypes.FIREFOX_EXTENSION_NEEDED,
                           config.desktopSharingFirefoxExtensionURL);

    // Make sure desktopsharing knows that we failed, so that it doesn't get
    // stuck in 'switching' mode.
    errorCallback('Firefox extension required.');
};

/**
 * Starts the detection of an installed jidesha extension for firefox.
 */
function initFirefoxExtensionDetection() {
    if (config.desktopSharingFirefoxDisabled) {
        return;
    }
    if (firefoxExtInstalled === false || firefoxExtInstalled === true)
        return;
    if (!config.desktopSharingFirefoxExtId) {
        firefoxExtInstalled = false;
        return;
    }

    var img = document.createElement('img');
    img.onload = function(){
        console.log("Detected firefox screen sharing extension.");
        firefoxExtInstalled = true;
    };
    img.onerror = function(){
        console.log("Detected lack of firefox screen sharing extension.");
        firefoxExtInstalled = false;
    };

    // The jidesha extension exposes an empty image file under the url:
    // "chrome://EXT_ID/content/DOMAIN.png"
    // Where EXT_ID is the ID of the extension with "@" replaced by ".", and
    // DOMAIN is a domain whitelisted by the extension.
    var src = "chrome://" +
        (config.desktopSharingFirefoxExtId.replace('@', '.')) +
        "/content/" + document.location.hostname + ".png";
    img.setAttribute('src', src);
}

module.exports = ScreenObtainer;
<commit_msg>Uses the new name of the chrome extension id field.<commit_after>/* global config, APP, chrome, $, alert */
/* jshint -W003 */
var RTCBrowserType = require("../RTC/RTCBrowserType");
var AdapterJS = require("../RTC/adapter.screenshare");
var DesktopSharingEventTypes
    = require("../../service/desktopsharing/DesktopSharingEventTypes");

/**
 * Indicates whether the Chrome desktop sharing extension is installed.
 * @type {boolean}
 */
var chromeExtInstalled = false;

/**
 * Indicates whether an update of the Chrome desktop sharing extension is
 * required.
 * @type {boolean}
 */
var chromeExtUpdateRequired = false;

/**
 * Whether the jidesha extension for firefox is installed for the domain on
 * which we are running. Null designates an unknown value.
 * @type {null}
 */
var firefoxExtInstalled = null;

/**
 * If set to true, detection of an installed firefox extension will be started
 * again the next time obtainScreenOnFirefox is called (e.g. next time the
 * user tries to enable screen sharing).
 */
var reDetectFirefoxExtension = false;

/**
 * Handles obtaining a stream from a screen capture on different browsers.
 */
function ScreenObtainer(){
}

/**
 * The EventEmitter to use to emit events.
 * @type {null}
 */
ScreenObtainer.prototype.eventEmitter = null;

/**
 * Initializes the function used to obtain a screen capture (this.obtainStream).
 *
 * If the browser is Chrome, it uses the value of
 * 'config.desktopSharingChromeMethod' (or 'config.desktopSharing') to * decide
 * whether to use the a Chrome extension (if the value is 'ext'), use the
 * "screen" media source (if the value is 'webrtc'), or disable screen capture
 * (if the value is other).
 * Note that for the "screen" media source to work the
 * 'chrome://flags/#enable-usermedia-screen-capture' flag must be set.
 */
ScreenObtainer.prototype.init = function(eventEmitter) {
    this.eventEmitter = eventEmitter;
    var obtainDesktopStream = null;

    if (RTCBrowserType.isFirefox())
        initFirefoxExtensionDetection();

    // TODO remove this, config.desktopSharing is deprecated.
    var chromeMethod =
        (config.desktopSharingChromeMethod || config.desktopSharing);

    if (RTCBrowserType.isTemasysPluginUsed()) {
        if (!AdapterJS.WebRTCPlugin.plugin.HasScreensharingFeature) {
            console.info("Screensharing not supported by this plugin version");
        } else if (!AdapterJS.WebRTCPlugin.plugin.isScreensharingAvailable) {
            console.info(
                "Screensharing not available with Temasys plugin on this site");
        } else {
            obtainDesktopStream = obtainWebRTCScreen;
            console.info("Using Temasys plugin for desktop sharing");
        }
    } else if (RTCBrowserType.isChrome()) {
        if (chromeMethod == "ext") {
            if (RTCBrowserType.getChromeVersion() >= 34) {
                obtainDesktopStream = obtainScreenFromExtension;
                console.info("Using Chrome extension for desktop sharing");
                initChromeExtension();
            } else {
                console.info("Chrome extension not supported until ver 34");
            }
        } else if (chromeMethod == "webrtc") {
            obtainDesktopStream = obtainWebRTCScreen;
            console.info("Using Chrome WebRTC for desktop sharing");
        }
    } else if (RTCBrowserType.isFirefox()) {
        if (config.desktopSharingFirefoxDisabled) {
            obtainDesktopStream = null;
        } else if (window.location.protocol === "http:"){
            console.log("Screen sharing is not supported over HTTP. Use of " +
                "HTTPS is required.");
            obtainDesktopStream = null;
        } else {
            obtainDesktopStream = this.obtainScreenOnFirefox;
        }

    }

    if (!obtainDesktopStream) {
        console.info("Desktop sharing disabled");
    }

    ScreenObtainer.prototype.obtainStream = obtainDesktopStream;
};

ScreenObtainer.prototype.obtainStream = null;

/**
 * Checks whether obtaining a screen capture is supported in the current
 * environment.
 * @returns {boolean}
 */
ScreenObtainer.prototype.isSupported = function() {
    return !!this.obtainStream;
};

/**
 * Obtains a desktop stream using getUserMedia.
 * For this to work on Chrome, the
 * 'chrome://flags/#enable-usermedia-screen-capture' flag must be enabled.
 *
 * On firefox, the document's domain must be white-listed in the
 * 'media.getusermedia.screensharing.allowed_domains' preference in
 * 'about:config'.
 */
function obtainWebRTCScreen(streamCallback, failCallback) {
    APP.RTC.getUserMediaWithConstraints(
        ['screen'],
        streamCallback,
        failCallback
    );
}

/**
 * Constructs inline install URL for Chrome desktop streaming extension.
 * The 'chromeExtensionId' must be defined in config.js.
 * @returns {string}
 */
function getWebStoreInstallUrl()
{
    //TODO remove chromeExtensionId (deprecated)
    return "https://chrome.google.com/webstore/detail/" +
        (config.desktopSharingChromeExtId || config.chromeExtensionId);
}

/**
 * Checks whether an update of the Chrome extension is required.
 * @param minVersion minimal required version
 * @param extVersion current extension version
 * @returns {boolean}
 */
function isUpdateRequired(minVersion, extVersion) {
    try {
        var s1 = minVersion.split('.');
        var s2 = extVersion.split('.');

        var len = Math.max(s1.length, s2.length);
        for (var i = 0; i < len; i++) {
            var n1 = 0,
                n2 = 0;

            if (i < s1.length)
                n1 = parseInt(s1[i]);
            if (i < s2.length)
                n2 = parseInt(s2[i]);

            if (isNaN(n1) || isNaN(n2)) {
                return true;
            } else if (n1 !== n2) {
                return n1 > n2;
            }
        }

        // will happen if both versions have identical numbers in
        // their components (even if one of them is longer, has more components)
        return false;
    }
    catch (e) {
        console.error("Failed to parse extension version", e);
        APP.UI.messageHandler.showError("dialog.error",
            "dialog.detectext");
        return true;
    }
}

function checkChromeExtInstalled(callback) {
    if (!chrome || !chrome.runtime) {
        // No API, so no extension for sure
        callback(false, false);
        return;
    }
    chrome.runtime.sendMessage(
        //TODO: remove chromeExtensionId (deprecated)
        (config.desktopSharingChromeExtId || config.chromeExtensionId),
        { getVersion: true },
        function (response) {
            if (!response || !response.version) {
                // Communication failure - assume that no endpoint exists
                console.warn(
                    "Extension not installed?: ", chrome.runtime.lastError);
                callback(false, false);
                return;
            }
            // Check installed extension version
            var extVersion = response.version;
            console.log('Extension version is: ' + extVersion);
            //TODO: remove minChromeExtVersion (deprecated)
            var updateRequired
                = isUpdateRequired(
                    (config.desktopSharingChromeMinExtVersion ||
                        config.minChromeExtVersion),
                    extVersion);
            callback(!updateRequired, updateRequired);
        }
    );
}

function doGetStreamFromExtension(streamCallback, failCallback) {
    // Sends 'getStream' msg to the extension.
    // Extension id must be defined in the config.
    chrome.runtime.sendMessage(
        //TODO: remove chromeExtensionId (deprecated)
        (config.desktopSharingChromeExtId || config.chromeExtensionId),
        {
            getStream: true,
            //TODO: remove desktopSharingSources (deprecated).
            sources: (config.desktopSharingChromeSources ||
                config.desktopSharingSources)
        },
        function (response) {
            if (!response) {
                failCallback(chrome.runtime.lastError);
                return;
            }
            console.log("Response from extension: " + response);
            if (response.streamId) {
                APP.RTC.getUserMediaWithConstraints(
                    ['desktop'],
                    function (stream) {
                        streamCallback(stream);
                    },
                    failCallback,
                    null, null, null,
                    response.streamId);
            } else {
                failCallback("Extension failed to get the stream");
            }
        }
    );
}

/**
 * Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop'
 * stream for returned stream token.
 */
function obtainScreenFromExtension(streamCallback, failCallback) {
    if (chromeExtInstalled) {
        doGetStreamFromExtension(streamCallback, failCallback);
    } else {
        if (chromeExtUpdateRequired) {
            alert(
                'Jitsi Desktop Streamer requires update. ' +
                'Changes will take effect after next Chrome restart.');
        }

        chrome.webstore.install(
            getWebStoreInstallUrl(),
            function (arg) {
                console.log("Extension installed successfully", arg);
                chromeExtInstalled = true;
                // We need to give a moment for the endpoint to become available
                window.setTimeout(function () {
                    doGetStreamFromExtension(streamCallback, failCallback);
                }, 500);
            },
            function (arg) {
                console.log("Failed to install the extension", arg);
                failCallback(arg);
                APP.UI.messageHandler.showError("dialog.error",
                    "dialog.failtoinstall");
            }
        );
    }
}

/**
 * Initializes <link rel=chrome-webstore-item /> with extension id set in
 * config.js to support inline installs. Host site must be selected as main
 * website of published extension.
 */
function initInlineInstalls()
{
    $("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
}

function initChromeExtension() {
    // Initialize Chrome extension inline installs
    initInlineInstalls();
    // Check if extension is installed
    checkChromeExtInstalled(function (installed, updateRequired) {
        chromeExtInstalled = installed;
        chromeExtUpdateRequired = updateRequired;
        console.info(
            "Chrome extension installed: " + chromeExtInstalled +
            " updateRequired: " + chromeExtUpdateRequired);
    });
}

/**
 * Obtains a screen capture stream on Firefox.
 * @param callback
 * @param errorCallback
 */
ScreenObtainer.prototype.obtainScreenOnFirefox =
       function (callback, errorCallback) {
    var self = this;
    var extensionRequired = false;
    if (config.desktopSharingFirefoxMaxVersionExtRequired === -1 ||
        (config.desktopSharingFirefoxMaxVersionExtRequired >= 0 &&
            RTCBrowserType.getFirefoxVersion() <=
                config.desktopSharingFirefoxMaxVersionExtRequired)) {
        extensionRequired = true;
        console.log("Jidesha extension required on firefox version " +
            RTCBrowserType.getFirefoxVersion());
    }

    if (!extensionRequired || firefoxExtInstalled === true) {
        obtainWebRTCScreen(callback, errorCallback);
        return;
    }

    if (reDetectFirefoxExtension) {
        reDetectFirefoxExtension = false;
        initFirefoxExtensionDetection();
    }

    // Give it some (more) time to initialize, and assume lack of extension if
    // it hasn't.
    if (firefoxExtInstalled === null) {
        window.setTimeout(
            function() {
                if (firefoxExtInstalled === null)
                    firefoxExtInstalled = false;
                self.obtainScreenOnFirefox(callback, errorCallback);
            },
            300
        );
        console.log("Waiting for detection of jidesha on firefox to finish.");
        return;
    }

    // We need an extension and it isn't installed.

    // Make sure we check for the extension when the user clicks again.
    firefoxExtInstalled = null;
    reDetectFirefoxExtension = true;

    // Prompt the user to install the extension
    this.eventEmitter.emit(DesktopSharingEventTypes.FIREFOX_EXTENSION_NEEDED,
                           config.desktopSharingFirefoxExtensionURL);

    // Make sure desktopsharing knows that we failed, so that it doesn't get
    // stuck in 'switching' mode.
    errorCallback('Firefox extension required.');
};

/**
 * Starts the detection of an installed jidesha extension for firefox.
 */
function initFirefoxExtensionDetection() {
    if (config.desktopSharingFirefoxDisabled) {
        return;
    }
    if (firefoxExtInstalled === false || firefoxExtInstalled === true)
        return;
    if (!config.desktopSharingFirefoxExtId) {
        firefoxExtInstalled = false;
        return;
    }

    var img = document.createElement('img');
    img.onload = function(){
        console.log("Detected firefox screen sharing extension.");
        firefoxExtInstalled = true;
    };
    img.onerror = function(){
        console.log("Detected lack of firefox screen sharing extension.");
        firefoxExtInstalled = false;
    };

    // The jidesha extension exposes an empty image file under the url:
    // "chrome://EXT_ID/content/DOMAIN.png"
    // Where EXT_ID is the ID of the extension with "@" replaced by ".", and
    // DOMAIN is a domain whitelisted by the extension.
    var src = "chrome://" +
        (config.desktopSharingFirefoxExtId.replace('@', '.')) +
        "/content/" + document.location.hostname + ".png";
    img.setAttribute('src', src);
}

module.exports = ScreenObtainer;
<|endoftext|>


<commit_before>const {Subject} = require('rxjs')
const {finalize, first, map, filter} = require('rxjs/operators')
const {Worker, MessageChannel} = require('worker_threads')
const {deserializeError} = require('serialize-error')
const {v4: uuid} = require('uuid')
const path = require('path')
const _ = require('lodash')
const log = require('@sepal/log')

const WORKER_PATH = path.join(__dirname, 'worker.js')

const createMessageChannels = names =>
    _.transform(names, (data, name) => {
        const {port1: localPort, port2: remotePort} = new MessageChannel()
        data.localPorts[name] = localPort
        data.remotePorts[name] = remotePort
    }, {
        localPorts: {},
        remotePorts: {}
    })

const bootstrapWorker$ = (name, channelNames) => {
    const worker$ = new Subject()
    const worker = new Worker(WORKER_PATH)
    const {localPorts, remotePorts} = createMessageChannels(channelNames)
    worker.once('message', status => {
        if (status === 'READY') {
            worker$.next({worker, ports: localPorts})
        } else {
            worker$.error('Cannot initialize worker.')
        }
    })
    worker.postMessage({name, ports: remotePorts}, _.values(remotePorts))
    return worker$.pipe(
        first()
    )
}

const initWorker$ = (name, jobPath) => {
    const msg = (msg, jobId) => [
        `[${name}${jobId ? `.${jobId.substr(-4)}` : ''}]`,
        msg
    ].join(' ')

    const result$ = new Subject()

    const setupWorker = (worker, port) => {
        const handleWorkerMessage = message => {
            message.value && handleValue(message)
            message.error && handleError(message)
            message.complete && handleComplete(message)
            // message.dispose && handleDispose(message, worker)
        }

        const handleValue = ({jobId, value}) => {
            log.trace(msg(`value: ${value}`, jobId))
            result$.next({jobId, value})
        }

        const handleError = ({jobId, error: serializedError}) => {
            const error = deserializeError(serializedError)
            const errors = _.compact([
                error.message,
                error.type ? `(${error.type})` : null
            ]).join()
            log.error(msg(`error: ${errors}`, jobId))
            result$.next({jobId, error})
        }

        const handleComplete = ({jobId, complete}) => {
            log.debug(msg('completed', jobId))
            result$.next({jobId, complete})
        }

        const openPort = () => port.on('message', handleWorkerMessage)
        // const closePort = () => port.off('message', handleWorkerMessage)
        const send = msg => port.postMessage(msg)

        openPort()
        log.trace('Worker ready')

        return {
            submit$(args, args$) {
                const jobId = uuid()
                const jobResult$ = new Subject()

                result$.pipe(
                    filter(message => message.jobId === jobId)
                ).subscribe(
                    message => {
                        message.value && jobResult$.next({value: message.value})
                        message.error && jobResult$.error({error: message.error})
                        message.complete && jobResult$.complete()
                    },
                    error => log.error(error), // how to handle this?
                    complete => log.warn(complete) // how to handle this?
                )

                const start = jobId => {
                    const workerArgs = _.last(args)
                    _.isEmpty(workerArgs)
                        ? log.debug(msg('started with no args', jobId))
                        : log.debug(msg('started with args:', jobId), workerArgs)
                    send({jobId, start: {jobPath, args}})
                }

                const stop = jobId =>
                    send({jobId, stop: true})

                start(jobId)

                if (args$) {
                    args$.subscribe(
                        value => send({jobId, value})
                    )
                }

                return jobResult$.pipe(
                    finalize(() => stop(jobId))
                )
            },
            dispose() {
                worker.terminate()
                // send({dispose: true})
            }
        }
    }

    return bootstrapWorker$(name, ['job']).pipe(
        map(({worker, ports: {job: port}}) => setupWorker(worker, port))
    )
}

module.exports = {
    initWorker$
}
<commit_msg>Prefixed worker log messages.<commit_after>const {Subject} = require('rxjs')
const {finalize, first, map, filter} = require('rxjs/operators')
const {Worker, MessageChannel} = require('worker_threads')
const {deserializeError} = require('serialize-error')
const {v4: uuid} = require('uuid')
const path = require('path')
const _ = require('lodash')
const log = require('@sepal/log')

const WORKER_PATH = path.join(__dirname, 'worker.js')

const createMessageChannels = names =>
    _.transform(names, (data, name) => {
        const {port1: localPort, port2: remotePort} = new MessageChannel()
        data.localPorts[name] = localPort
        data.remotePorts[name] = remotePort
    }, {
        localPorts: {},
        remotePorts: {}
    })

const bootstrapWorker$ = (name, channelNames) => {
    const worker$ = new Subject()
    const worker = new Worker(WORKER_PATH)
    const {localPorts, remotePorts} = createMessageChannels(channelNames)
    worker.once('message', status => {
        if (status === 'READY') {
            worker$.next({worker, ports: localPorts})
        } else {
            worker$.error('Cannot initialize worker.')
        }
    })
    worker.postMessage({name, ports: remotePorts}, _.values(remotePorts))
    return worker$.pipe(
        first()
    )
}

const initWorker$ = (name, jobPath) => {
    const msg = (msg, jobId) => [
        `Worker [${name}${jobId ? `.${jobId.substr(-4)}` : ''}]`,
        msg
    ].join(' ')

    const result$ = new Subject()

    const setupWorker = (worker, port) => {
        const handleWorkerMessage = message => {
            message.value && handleValue(message)
            message.error && handleError(message)
            message.complete && handleComplete(message)
            // message.dispose && handleDispose(message, worker)
        }

        const handleValue = ({jobId, value}) => {
            log.trace(msg(`value: ${value}`, jobId))
            result$.next({jobId, value})
        }

        const handleError = ({jobId, error: serializedError}) => {
            const error = deserializeError(serializedError)
            const errors = _.compact([
                error.message,
                error.type ? `(${error.type})` : null
            ]).join()
            log.error(msg(`error: ${errors}`, jobId))
            result$.next({jobId, error})
        }

        const handleComplete = ({jobId, complete}) => {
            log.debug(msg('completed', jobId))
            result$.next({jobId, complete})
        }

        const openPort = () => port.on('message', handleWorkerMessage)
        // const closePort = () => port.off('message', handleWorkerMessage)
        const send = msg => port.postMessage(msg)

        openPort()
        log.trace('Worker ready')

        return {
            submit$(args, args$) {
                const jobId = uuid()
                const jobResult$ = new Subject()

                result$.pipe(
                    filter(message => message.jobId === jobId)
                ).subscribe(
                    message => {
                        message.value && jobResult$.next({value: message.value})
                        message.error && jobResult$.error({error: message.error})
                        message.complete && jobResult$.complete()
                    },
                    error => log.error(error), // how to handle this?
                    complete => log.warn(complete) // how to handle this?
                )

                const start = jobId => {
                    const workerArgs = _.last(args)
                    _.isEmpty(workerArgs)
                        ? log.debug(msg('started with no args', jobId))
                        : log.debug(msg('started with args:', jobId), workerArgs)
                    send({jobId, start: {jobPath, args}})
                }

                const stop = jobId =>
                    send({jobId, stop: true})

                start(jobId)

                if (args$) {
                    args$.subscribe(
                        value => send({jobId, value})
                    )
                }

                return jobResult$.pipe(
                    finalize(() => stop(jobId))
                )
            },
            dispose() {
                worker.terminate()
                // send({dispose: true})
            }
        }
    }

    return bootstrapWorker$(name, ['job']).pipe(
        map(({worker, ports: {job: port}}) => setupWorker(worker, port))
    )
}

module.exports = {
    initWorker$
}
<|endoftext|>


<commit_before>/**
*	@name							Elastic
*	@descripton						Elastic is jQuery plugin that grow and shrink your textareas automatically
*	@version						1.6.10
*	@requires						jQuery 1.2.6+
*
*	@author							Jan Jarfalk
*	@author-email					jan.jarfalk@unwrongest.com
*	@author-website					http://www.unwrongest.com
*
*	@licence						MIT License - http://www.opensource.org/licenses/mit-license.php
*
*   This file has been downloaded from http://unwrongest.com/projects/elastic/, please notify the author of
*   any changes.
*/

(function(jQuery){
	jQuery.fn.extend({
		elastic: function() {

			//	We will create a div clone of the textarea
			//	by copying these attributes from the textarea to the div.
			var mimics = [
				'paddingTop',
				'paddingRight',
				'paddingBottom',
				'paddingLeft',
				'fontSize',
				'lineHeight',
				'fontFamily',
				'width',
				'fontWeight',
				'border-top-width',
				'border-right-width',
				'border-bottom-width',
				'border-left-width',
				'borderTopStyle',
				'borderTopColor',
				'borderRightStyle',
				'borderRightColor',
				'borderBottomStyle',
				'borderBottomColor',
				'borderLeftStyle',
				'borderLeftColor'
				];

			return this.each( function() {

				// Elastic only works on textareas
				if ( this.type !== 'textarea' ) {
					return false;
				}

			var $textarea	= jQuery(this),
				$twin		= jQuery('
').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
				lineHeight	= parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
				minheight	= parseInt($textarea.css('height'),10) || lineHeight*3,
				maxheight	= parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
				goalheight	= 0;

				// Opera returns max-height of -1 if not set
				if (maxheight < 0) { maxheight = Number.MAX_VALUE; }

				// Append the twin to the DOM
				// We are going to meassure the height of this, not the textarea.
				$twin.appendTo($textarea.parent());

				// Copy the essential styles (mimics) from the textarea to the twin
				var i = mimics.length;
				while(i--){
					$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
				}

				// Updates the width of the twin. (solution for textareas with widths in percent)
				function setTwinWidth(){
					curatedWidth = Math.floor(parseInt($textarea.width(),10));
					if($twin.width() !== curatedWidth){
						$twin.css({'width': curatedWidth + 'px'});

						// Update height of textarea
						update(true);
					}
				}

				// Sets a given height and overflow state on the textarea
				function setHeightAndOverflow(height, overflow){

					var curratedHeight = Math.floor(parseInt(height,10));
					if($textarea.height() !== curratedHeight){
						$textarea.css({'height': curratedHeight + 'px','overflow':overflow});

						// Fire the custom event resize
						//$textarea.trigger('resize');

					}
				}

				// This function will update the height of the textarea if necessary
				function update(forced) {

					// Get curated content from the textarea.
					var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ {2}/g, ' ').replace(/<|>/g, '>').replace(/\n/g, '
');

					// Compare curated content with curated twin.
					var twinContent = $twin.html().replace(/
/ig,'
');

					if(forced || textareaContent+' ' !== twinContent){

						// Add an extra white space so new rows are added when you are at the end of a row.
						$twin.html(textareaContent+' ');

						// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
						if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){

							var goalheight = $twin.height()+lineHeight;
							if(goalheight >= maxheight) {
								setHeightAndOverflow(maxheight,'auto');
							} else if(goalheight <= minheight) {
								setHeightAndOverflow(minheight,'hidden');
							} else {
								setHeightAndOverflow(goalheight,'hidden');
							}

						}

					}

				}

				// Hide scrollbars
				$textarea.css({'overflow':'hidden'});

				// Update textarea size on keyup, change, cut and paste
				$textarea.bind('keyup change cut paste', function(){
					update();
				});

				// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
				$(window).bind('resize', setTwinWidth);
				$textarea.bind('resize', setTwinWidth);
				$textarea.bind('update', update);

				// Compact textarea on blur
				$textarea.bind('blur',function(){
					if($twin.height() < maxheight){
						if($twin.height() > minheight) {
							$textarea.height($twin.height());
						} else {
							$textarea.height(minheight);
						}
					}
				});

				// And this line is to catch the browser paste event
				$textarea.bind('input paste',function(e){ setTimeout( update, 250); });

				// Run update once when elastic is initialized
				update();

			});

        }
    });
})(jQuery);<commit_msg>updating jquery.elastic.js<commit_after>/**
*	@name							Elastic
*	@descripton						Elastic is jQuery plugin that grow and shrink your textareas automatically
*	@version						1.6.11
*	@requires						jQuery 1.2.6+
*
*	@author							Jan Jarfalk
*	@author-email					jan.jarfalk@unwrongest.com
*	@author-website					http://www.unwrongest.com
*
*	@licence						MIT License - http://www.opensource.org/licenses/mit-license.php
*/

(function($){
	jQuery.fn.extend({
		elastic: function() {

			//	We will create a div clone of the textarea
			//	by copying these attributes from the textarea to the div.
			var mimics = [
				'paddingTop',
				'paddingRight',
				'paddingBottom',
				'paddingLeft',
				'fontSize',
				'lineHeight',
				'fontFamily',
				'width',
				'fontWeight',
				'border-top-width',
				'border-right-width',
				'border-bottom-width',
				'border-left-width',
				'borderTopStyle',
				'borderTopColor',
				'borderRightStyle',
				'borderRightColor',
				'borderBottomStyle',
				'borderBottomColor',
				'borderLeftStyle',
				'borderLeftColor'
				];

			return this.each( function() {

				// Elastic only works on textareas
				if ( this.type !== 'textarea' ) {
					return false;
				}

			var $textarea	= jQuery(this),
				$twin		= jQuery('
').css({
					'position'		: 'absolute',
					'display'		: 'none',
					'word-wrap'		: 'break-word',
					'white-space'	: 'pre-wrap'
				}),
				lineHeight	= parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
				minheight	= parseInt($textarea.css('height'),10) || lineHeight*3,
				maxheight	= parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
				goalheight	= 0;

				// Opera returns max-height of -1 if not set
				if (maxheight < 0) { maxheight = Number.MAX_VALUE; }

				// Append the twin to the DOM
				// We are going to meassure the height of this, not the textarea.
				$twin.appendTo($textarea.parent());

				// Copy the essential styles (mimics) from the textarea to the twin
				var i = mimics.length;
				while(i--){
					$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
				}

				// Updates the width of the twin. (solution for textareas with widths in percent)
				function setTwinWidth(){
					var curatedWidth = Math.floor(parseInt($textarea.width(),10));
					if($twin.width() !== curatedWidth){
						$twin.css({'width': curatedWidth + 'px'});

						// Update height of textarea
						update(true);
					}
				}

				// Sets a given height and overflow state on the textarea
				function setHeightAndOverflow(height, overflow){
					var curratedHeight = Math.floor(parseInt(height,10));
					if($textarea.height() !== curratedHeight){
						$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
					}
				}

				// This function will update the height of the textarea if necessary
				function update(forced) {

					// Get curated content from the textarea.
					var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ {2}/g, ' ').replace(/<|>/g, '>').replace(/\n/g, '
');

					// Compare curated content with curated twin.
					var twinContent = $twin.html().replace(/
/ig,'
');

					if(forced || textareaContent+' ' !== twinContent){

						// Add an extra white space so new rows are added when you are at the end of a row.
						$twin.html(textareaContent+' ');

						// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
						if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){

							var goalheight = $twin.height()+lineHeight;
							if(goalheight >= maxheight) {
								setHeightAndOverflow(maxheight,'auto');
							} else if(goalheight <= minheight) {
								setHeightAndOverflow(minheight,'hidden');
							} else {
								setHeightAndOverflow(goalheight,'hidden');
							}

						}

					}

				}

				// Hide scrollbars
				$textarea.css({'overflow':'hidden'});

				// Update textarea size on keyup, change, cut and paste
				$textarea.bind('keyup change cut paste', function(){
					update();
				});

				// Update width of twin if browser or textarea is resized (solution for textareas with widths in percent)
				$(window).bind('resize', setTwinWidth);
				$textarea.bind('resize', setTwinWidth);
				$textarea.bind('update', update);

				// Compact textarea on blur
				$textarea.bind('blur',function(){
					if($twin.height() < maxheight){
						if($twin.height() > minheight) {
							$textarea.height($twin.height());
						} else {
							$textarea.height(minheight);
						}
					}
				});

				// And this line is to catch the browser paste event
				$textarea.bind('input paste',function(e){ setTimeout( update, 250); });

				// Run update once when elastic is initialized
				update();

			});

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


<commit_before>/* global describe, it */
import { expect } from 'chai';

import RegionService from '../../services/Region';

describe('react › services › Region', function () {
  it('is a function', function () {
    expect(RegionService).to.be.a('function');
  });
});
<commit_msg>tests: for RegionService.<commit_after>/* global describe, it */
import { expect } from 'chai';

import RegionService from '../../services/Region';

describe('react › services › Region', function () {
  it('is a function', function () {
    expect(RegionService).to.be.a('function');
  });

  it('emits props', function (done) {
    const region = new RegionService();
    region.emit({
      key: 'value',
    });

    region.getProps$()
      .subscribe(function (props) {
        expect(props).to.deep.equal({
          key: 'value',
        });

        done();
      });
  });

  it('can get only data as an observable', function (done) {
    const region = new RegionService();
    region.emit({
      name: 'sidebar',
      data: {
        some: 'info',
      },
    });

    region.getData$()
      .subscribe(function (props) {
        expect(props).to.deep.equal({
          some: 'info',
        });

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


<commit_before>'use strict';

/**
 * @ngInject
 */
var UserRegisterController = function ($scope, $http, $location, $routeParams, npolarApiConfig, NpolarApiMessage, User, base64) {
  const registrationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/register";
  const confirmationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/confirm";
  const captchaUri = "http://data.npolar.no:20938";

  $scope.captcha = {
	enable: true,
	uuid: null,
	src: "//:0",
	string: ""
  };

  $scope.resource = User;
  $scope.user = { link: `https://${window.location.host}/user/confirm` };

  $scope.compare = function(user) {
    if (user.password2 !== undefined) {
      if (user.password !== user.password2) {
        $scope.pwdStyle = { color: "rgb(215,10,83)", "border-color": "rgb(215,10,83)" };
      } else {
        $scope.pwdStyle = { color: "rgb(34,139,34)", "border-color": "rgb(34,139,34)" };
      }

      if (user.password2 === "") {
        $scope.pwdStyle={};
      }
    }
  };

  $scope.register = function(user) {
    if (user.password !== user.password2) {
      NpolarApiMessage.emit("npolar-api-error", "Password mismatch! Please enter the same password twice.");
    } else {
      $scope.user = user;
      $http({
        method: "POST",
        url: registrationUri,
        data: $scope.user,
        headers: {
          "Authorization": "Sicas " + base64.encode($scope.captcha.uuid + ":" + $scope.captcha.string)
        }
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "You should receive a confirmation mail in a short while");
        $location.path(".");
      }, function error(res) {
        NpolarApiMessage.emit("npolar-api-error", (typeof res.data == "object" && res.data && res.data.error ? res.data.error : "Registration failed"));
      });
    }
  };

  $scope.confirm = function(id) {
      $http({
        method: "GET",
        url: confirmationUri+$routeParams.id
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "Confirmation successful. You can now login with your new account");
        $location.path(".");
      }, function error() {
        NpolarApiMessage.emit("npolar-api-error", "Confirmation failed");
      });
  };

  if($scope.captcha) {
    ($scope.captcha.renew = function() {
      $http({
        method: "GET",
        url: captchaUri + "/captcha?width=100&height=50&time=" + Date.now()
      }).then(function(response) {
        $scope.captcha.src = captchaUri + response.data.path;
        $scope.captcha.uuid = response.data.uuid;
        $scope.captcha.string = "";
      });
    })();
  }

  $scope.valid = function() {
    return (!$scope.captcha || $scope.captcha.string) && $scope.user.email && $scope.user.name && $scope.user.password && ($scope.user.password === $scope.user.password2);
  };
};

module.exports = UserRegisterController;
<commit_msg>Updated captcha URI now hiding the internal host:port<commit_after>'use strict';

/**
 * @ngInject
 */
var UserRegisterController = function ($scope, $http, $location, $routeParams, npolarApiConfig, NpolarApiMessage, User, base64) {
  const registrationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/register";
  const confirmationUri = "https://"+npolarApiConfig.base.split("//")[1]+"/user/confirm";
  const captchaUri = "https://api.npolar.no/_captcha";

  $scope.captcha = {
	uuid: null,
	src: "//:0",
	string: ""
  };

  $scope.resource = User;
  $scope.user = { link: `https://${window.location.host}/user/confirm` };

  $scope.compare = function(user) {
    if (user.password2 !== undefined) {
      if (user.password !== user.password2) {
        $scope.pwdStyle = { color: "rgb(215,10,83)", "border-color": "rgb(215,10,83)" };
      } else {
        $scope.pwdStyle = { color: "rgb(34,139,34)", "border-color": "rgb(34,139,34)" };
      }

      if (user.password2 === "") {
        $scope.pwdStyle={};
      }
    }
  };

  $scope.register = function(user) {
    if (user.password !== user.password2) {
      NpolarApiMessage.emit("npolar-api-error", "Password mismatch! Please enter the same password twice.");
    } else {
      $scope.user = user;
      $http({
        method: "POST",
        url: registrationUri,
        data: $scope.user,
        headers: {
          "Authorization": "Sicas " + base64.encode($scope.captcha.uuid + ":" + $scope.captcha.string)
        }
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "You should receive a confirmation mail in a short while");
        $location.path(".");
      }, function error(res) {
        NpolarApiMessage.emit("npolar-api-error", (typeof res.data == "object" && res.data && res.data.error ? res.data.error : "Registration failed"));
      });
    }
  };

  $scope.confirm = function(id) {
      $http({
        method: "GET",
        url: confirmationUri+$routeParams.id
      }).then(function success() {
        NpolarApiMessage.emit("npolar-info", "Confirmation successful. You can now login with your new account");
        $location.path(".");
      }, function error() {
        NpolarApiMessage.emit("npolar-api-error", "Confirmation failed");
      });
  };

  if($scope.captcha) {
    ($scope.captcha.renew = function() {
      $http({
        method: "GET",
        url: captchaUri + "/?width=100&height=50&time=" + Date.now()
      }).then(function(response) {
        $scope.captcha.src = captchaUri + response.data.path;
        $scope.captcha.uuid = response.data.uuid;
        $scope.captcha.string = "";
      });
    })();
  }

  $scope.valid = function() {
    return (!$scope.captcha || $scope.captcha.string) && $scope.user.email && $scope.user.name && $scope.user.password && ($scope.user.password === $scope.user.password2);
  };
};

module.exports = UserRegisterController;
<|endoftext|>


<commit_before>require('module-alias/register')
const {parentPort} = require('worker_threads')
const {ReplaySubject, Subject, of, concat} = require('rxjs')
const {map, mergeMap, takeUntil, tap, filter, share} = require('rxjs/operators')
const {serializeError} = require('serialize-error')
const _ = require('lodash')
const log = require('@sepal/log')
const context = require('./context')

const exported = {}
const request$ = new ReplaySubject()
const response$ = new Subject()

parentPort.once('message', ({name, ports}) => {
    const args$ = new Subject()
    const stop$ = new Subject()
    const jobPort = ports.job
    const conversationPort = ports.conversation
    conversationPort.on('message', message => response$.next(message))
    exported.ports = ports

    const msg = (msg, jobId) => [
        `Worker [${name}${jobId ? `.${jobId.substr(-4)}` : ''}]`,
        msg
    ].join(' ')

    const start = ({jobId, start: {jobPath, args}}) => {
        log.trace(msg('start', jobId))
        context.request$ = request$
        context.response$ = response$.pipe(share())
        const tasks = require(jobPath)()

        const tasks$ = _.chain(tasks)
            .zip(args)
            .map(([{jobName, worker$}, args]) =>
                of({jobName, worker$, args})
            )
            .value()

        const jobArgs$ = args$.pipe(
            filter(arg => arg.jobId === jobId),
            map(({value}) => value)
        )

        run(jobId, tasks$, jobArgs$)
    }

    const run = (jobId, tasks$, args$) => {
        const next = value => {
            log.trace(msg(`value: ${JSON.stringify(value)}`, jobId))
            return jobPort.postMessage({jobId, ...value})
        }

        const error = error => {
            log.trace(msg(`error: ${error}`, jobId))
            return jobPort.postMessage({jobId, error: serializeError(error)})
        }

        const complete = () => {
            log.trace(msg('complete', jobId))
            return jobPort.postMessage({jobId, complete: true})
        }

        const job$ = concat(...tasks$).pipe(
            tap(({jobName, args}) =>
                log.trace(msg(`running <${jobName}> with args:`, jobId), args)
            ),
            mergeMap(({worker$, args}) => worker$(...args, args$), 1),
            takeUntil(stop$.pipe(filter(id => id === jobId)))
        )

        request$.pipe(
            map(request => ({request}))
        ).subscribe(next)

        job$.pipe(
            map(value => ({value}))
        ).subscribe({next, error, complete})
    }

    const stop = ({jobId}) => {
        log.trace(msg('stop', jobId))
        stop$.next(jobId)
    }

    const next = ({jobId, value}) => {
        args$.next({jobId, value})
    }

    const handleMessage = message => {
        message.start && start(message)
        message.stop && stop(message)
        message.value && next(message)
        message.response && response$.next(message.response)
    }

    const init = () => {
        log.trace(msg('ready'))
        jobPort.on('message', handleMessage)
        parentPort.postMessage('READY')
    }

    init()
})

module.exports = exported
<commit_msg>Movied context initialization.<commit_after>require('module-alias/register')
const {parentPort} = require('worker_threads')
const {ReplaySubject, Subject, of, concat} = require('rxjs')
const {map, mergeMap, takeUntil, tap, filter, share} = require('rxjs/operators')
const {serializeError} = require('serialize-error')
const _ = require('lodash')
const log = require('@sepal/log')
const context = require('./context')

const exported = {}
const request$ = new ReplaySubject()
const response$ = new Subject()
context.request$ = request$
context.response$ = response$.pipe(share())

parentPort.once('message', ({name, ports}) => {
    const args$ = new Subject()
    const stop$ = new Subject()
    const jobPort = ports.job
    const conversationPort = ports.conversation
    conversationPort.on('message', message => response$.next(message))
    exported.ports = ports

    const msg = (msg, jobId) => [
        `Worker [${name}${jobId ? `.${jobId.substr(-4)}` : ''}]`,
        msg
    ].join(' ')

    const start = ({jobId, start: {jobPath, args}}) => {
        log.trace(msg('start', jobId))
        const tasks = require(jobPath)()

        const tasks$ = _.chain(tasks)
            .zip(args)
            .map(([{jobName, worker$}, args]) =>
                of({jobName, worker$, args})
            )
            .value()

        const jobArgs$ = args$.pipe(
            filter(arg => arg.jobId === jobId),
            map(({value}) => value)
        )

        run(jobId, tasks$, jobArgs$)
    }

    const run = (jobId, tasks$, args$) => {
        const next = value => {
            log.trace(msg(`value: ${JSON.stringify(value)}`, jobId))
            return jobPort.postMessage({jobId, ...value})
        }

        const error = error => {
            log.trace(msg(`error: ${error}`, jobId))
            return jobPort.postMessage({jobId, error: serializeError(error)})
        }

        const complete = () => {
            log.trace(msg('complete', jobId))
            return jobPort.postMessage({jobId, complete: true})
        }

        const job$ = concat(...tasks$).pipe(
            tap(({jobName, args}) =>
                log.trace(msg(`running <${jobName}> with args:`, jobId), args)
            ),
            mergeMap(({worker$, args}) => worker$(...args, args$), 1),
            takeUntil(stop$.pipe(filter(id => id === jobId)))
        )

        request$.pipe(
            map(request => ({request}))
        ).subscribe(next)

        job$.pipe(
            map(value => ({value}))
        ).subscribe({next, error, complete})
    }

    const stop = ({jobId}) => {
        log.trace(msg('stop', jobId))
        stop$.next(jobId)
    }

    const next = ({jobId, value}) => {
        args$.next({jobId, value})
    }

    const handleMessage = message => {
        message.start && start(message)
        message.stop && stop(message)
        message.value && next(message)
        message.response && response$.next(message.response)
    }

    const init = () => {
        log.trace(msg('ready'))
        jobPort.on('message', handleMessage)
        parentPort.postMessage('READY')
    }

    init()
})

module.exports = exported
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router';
import Loading from '../../../components/shared/Loading';
import Price from '../../../components/shared/Price';
import EventInfo from '../../../components/shared/EventInfo/EventInfo';
import TicketViewModal from './TicketViewModal';
import TicketTransferModal from './TicketTransferModal';
import Order from '../../Checkout/components/Order';
import Payment from '../../Checkout/components/Payment';
import Register from '../../Checkout/components/Register';

import './Ticket.scss';

class Ticket extends Component {
  constructor(props) {
    super(props);
    this.state = {
      serviceFee: 1,
      cardFee: 2
    };
    this.openTicketViewModal = this.openTicketViewModal.bind(this);
    this.openTicketTransferModal = this.openTicketTransferModal.bind(this);
  }

  componentDidMount() {
    let { serviceFee, cardFee } = this.state;
    this.props.getTicketInfo(this.props.params.ticketId);
    this.setState({ total: this.calculateTotal(serviceFee + cardFee)});
  }

  calculateTotal(fees) {
    let { event, order } = this.props;
    return (event.price * 1) + fees;
  }

  openTicketViewModal(ticket) {
    this.setState({viewTicketModalOpen: true, selectedTicket: ticket});
  }

  openTicketTransferModal(ticket) {
    this.setState({transferTicketModalOpen: true, selectedTicket: ticket});
  }

  toggleForSale() {
    this.props.toggleForSale(this.props.ticket);
  }

  isOwner() {
    console.log('isOwner: ', this.props.user._id, this.props.ticket.ownerId);
    if (this.props.user._id !== this.props.ticket.ownerId) return true;
    return false;
  }

  async registerUser() {
    let { signup } = this.props;
    let { userData } = this.state;
    if (userData) await signup(userData.email, userData.password);
    // user is defined after this point
    console.log(this.props.user);
  }

  async buyTicketsWithStripe(token, order) {
    await this.registerUser();
    let { buyTicketsStripe } = this.props;
    await buyTicketsStripe(token, order);
  }

  render() {
    let { ticket, user, event } = this.props;
    console.log('Ticket this.props: ', this.props);
    let order = { _id: this.props.params.ticketId, ticketQty: 1 }
    if (!this.props.ticket._id) {
      return (
        <Loading />
      );
    }
    return (

            {/* {ticket.eventId.name} */}
            share

            This is the barcode that will be scanned to get you into the event.

            {/* Ticket Details */}

                  Date
                  Type
                  Price
                  For Sale

                  {ticket.eventId.date}
                  {ticket.type}

                      {ticket._id}
                  <Price price={ticket.price} />

                    <input type="checkbox"
                      checked={ticket.isForSale}
                      onChange={() => this.toggleForSale()}
                    />

                  <button className="activator terrapin-green white-text btn hide-on-large-only">Actions</button>
                  more_vert

              close

                 this.toggleForSale()}>
                  attach_money{(ticket.isForSale) ? 'Unmark as For Sale' : 'Mark as For Sale'}

                  emailTransfer via Email

                  historyView History

        { user ? () : (<Register onRegister={this.onRegister.bind(this)} />) }

        {this.isOwner() ? (null) : (
          <Order
            serviceFee={this.state.serviceFee}
            cardFee={this.state.cardFee}
            total={this.state.total}
            order={order}
            event={event}
            user={user}
            buyTicketsWithStripe={this.buyTicketsWithStripe.bind(this)}
          />
        )}

        {this.isOwner() ? (null) : (
          <Payment
            order={order}
            event={event}
            user={user}
            buyTicketsWithStripe={this.buyTicketsWithStripe.bind(this)}
          />
        )}

Venue Information

              {ticket.eventId.venue.name}

              {ticket.eventId.venue.address}

              {ticket.eventId.venue.city}, {ticket.eventId.venue.state} {ticket.eventId.venue.zip}

        <TicketViewModal
          ticket={this.state.selectedTicket}
          closeModal={() => this.setState({viewTicketModalOpen: false, selectedTicket: null })}
          isOpen={this.state.viewTicketModalOpen}
          user={user}
          />

        <TicketTransferModal
          ticket={this.state.selectedTicket}
          closeModal={() => this.setState({transferTicketModalOpen: false, selectedTicket: null })}
          isOpen={this.state.transferTicketModalOpen}
          transferTicket={this.props.transferTicket} />

    );
  }
}

export default Ticket;
<commit_msg>updated routes<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router';
import Loading from '../../../components/shared/Loading';
import Price from '../../../components/shared/Price';
import EventInfo from '../../../components/shared/EventInfo/EventInfo';

import TicketViewModal from './TicketViewModal';
import TicketTransferModal from './TicketTransferModal';

import Order from '../../../components/shared/Checkout/Order';
import Payment from '../../../components/shared/Checkout/Payment';
import Register from '../../Checkout/components/Register';

import './Ticket.scss';

class Ticket extends Component {
  constructor(props) {
    super(props);
    this.state = {
      serviceFee: 1,
      cardFee: 2
    };
    this.openTicketViewModal = this.openTicketViewModal.bind(this);
    this.openTicketTransferModal = this.openTicketTransferModal.bind(this);
  }

  componentDidMount() {
    let { serviceFee, cardFee } = this.state;
    this.props.getTicketInfo(this.props.params.ticketId);
    this.setState({ total: this.calculateTotal(serviceFee + cardFee)});
  }

  calculateTotal(fees) {
    let { event, order } = this.props;
    return (event.price * 1) + fees;
  }

  openTicketViewModal(ticket) {
    this.setState({viewTicketModalOpen: true, selectedTicket: ticket});
  }

  openTicketTransferModal(ticket) {
    this.setState({transferTicketModalOpen: true, selectedTicket: ticket});
  }

  toggleForSale() {
    this.props.toggleForSale(this.props.ticket);
  }

  isOwner() {
    console.log('isOwner: ', this.props.user._id, this.props.ticket.ownerId);
    if (this.props.user._id !== this.props.ticket.ownerId) return true;
    return false;
  }

  async registerUser() {
    let { signup } = this.props;
    let { userData } = this.state;
    if (userData) await signup(userData.email, userData.password);
    // user is defined after this point
    console.log(this.props.user);
  }

  async buyTicketsWithStripe(token, order) {
    await this.registerUser();
    let { buyTicketsStripe } = this.props;
    await buyTicketsStripe(token, order);
  }

  render() {
    let { ticket, user, event } = this.props;
    console.log('Ticket this.props: ', this.props);
    let order = { _id: this.props.params.ticketId, ticketQty: 1 }
    if (!this.props.ticket._id) {
      return (
        <Loading />
      );
    }
    return (

            {/* {ticket.eventId.name} */}
            share

            This is the barcode that will be scanned to get you into the event.

            {/* Ticket Details */}

                  Date
                  Type
                  Price
                  For Sale

                  {ticket.eventId.date}
                  {ticket.type}

                      {ticket._id}
                  <Price price={ticket.price} />

                    <input type="checkbox"
                      checked={ticket.isForSale}
                      onChange={() => this.toggleForSale()}
                    />

                  <button className="activator terrapin-green white-text btn hide-on-large-only">Actions</button>
                  more_vert

              close

                 this.toggleForSale()}>
                  attach_money{(ticket.isForSale) ? 'Unmark as For Sale' : 'Mark as For Sale'}

                  emailTransfer via Email

                  historyView History

        { user ? () : (<Register onRegister={this.onRegister.bind(this)} />) }

        {this.isOwner() ? (null) : (
          <Order
            serviceFee={this.state.serviceFee}
            cardFee={this.state.cardFee}
            total={this.state.total}
            order={order}
            event={event}
            user={user}
            buyTicketsWithStripe={this.buyTicketsWithStripe.bind(this)}
          />
        )}

        {this.isOwner() ? (null) : (
          <Payment
            order={order}
            event={event}
            user={user}
            buyTicketsWithStripe={this.buyTicketsWithStripe.bind(this)}
          />
        )}

Venue Information

              {ticket.eventId.venue.name}

              {ticket.eventId.venue.address}

              {ticket.eventId.venue.city}, {ticket.eventId.venue.state} {ticket.eventId.venue.zip}

        <TicketViewModal
          ticket={this.state.selectedTicket}
          closeModal={() => this.setState({viewTicketModalOpen: false, selectedTicket: null })}
          isOpen={this.state.viewTicketModalOpen}
          user={user}
          />

        <TicketTransferModal
          ticket={this.state.selectedTicket}
          closeModal={() => this.setState({transferTicketModalOpen: false, selectedTicket: null })}
          isOpen={this.state.transferTicketModalOpen}
          transferTicket={this.props.transferTicket} />

    );
  }
}

export default Ticket;
<|endoftext|>