<commit_before>var demo = demo || {};

demo.Controller = (function ($) {

    // HTML Imports support feature test
    var supportsHTMLImports = Boolean('import' in document.createElement('link'));

    // Test to see if the browser supports the HTML template element by checking
    // for the presence of the template element's content attribute.
    var supportsHTMLTemplate = Boolean('content' in document.createElement('template'));

    // Replace location hash without new history entry
    var replaceHash;
    if ('replaceState' in history) {
        replaceHash = function (newhash) {
            if (('' + newhash).charAt(0) !== '#') {
                newhash = '#' + newhash;
            }
            history.replaceState('', '', newhash);
        };
    } else {
        var hash = location.hash;
        replaceHash = function (newhash) {
            if (location.hash !== hash) {
                history.back();
            }
            location.hash = newhash;
        };
    }

    var mainPage, mainPageId;

    var init = function (config) {

        // Always redirect to main page
        $(window).bind('hashchange', function () {
            var hash = window.location.hash.replace(/^#/, '');
            if (hash === '') {
                replaceHash(mainPageId);
            }
        });

        // Use jQuery.load() if we don't have native HTML Imports support
        if (!supportsHTMLImports) {
            var imports = $('link[rel=import]');
            for (var i = 0, len = imports.length; i < len; i++) {
                $('<template/>').appendTo(document.body).load($(imports[i]).attr('href'), function (response, status, xhr) {
                    if (status === 'error') {
                        throw msg + xhr.status + ' ' + xhr.statusText;
                    }
                });
            }
        }
    };

    var injectTemplate = function (options) {

        // Use an empty page for main page placeholder
        // and prevent jQuery Mobile to inject a blank page
        if (!mainPage) {
            mainPage = $('div[data-main-page]');
            mainPageId = mainPage.attr('data-main-page');
        }

        var templateDoc = document;

        if (supportsHTMLImports) {

            // templateDoc refers to the "importee", which is template.html
            var templateDoc = options.context.ownerDocument;
        }

        // Grab the contents of the template from templateDoc
        // and append it to the importing document.
        var template = templateDoc.querySelector('template[data-template-id="' + options.templateId + '"]');

        if (!template) {
            throw 'template with data-template-id="' + options.templateId + '"] not found';
        }

        var component;

        // If the browser supports HTML Template, we have to import the page Element
        // otherwise we will get the HTML Element already injected by jQuery.load()
        if (supportsHTMLTemplate) {
            component = document.importNode(template.content, true);
        } else {
            component = template.querySelector('#' + options.templateId);

            // remove component from the DOM
            $(component).remove();
        }

        var callback = function (component) {

            // If component is main page, replace it, if not, append
            // component maybe DOM Element or DocumentFragment
            if (options.templateId === mainPageId) {
                mainPage.replaceWith(component);
            } else {
                $(document.body).append(component);
            }

            component = $('#' + options.templateId); // Get injected DOM Element
            if (!component.hasClass('ui-' + component.attr('data-role'))) { // If not already enhanced
                component[component.attr('data-role')](); // enhance ;)
            }

            // If this template is the main page, show it instantly
            if (options.templateId === mainPageId) {
                $.mobile.changePage(component, {
                    transition: 'none',
                    changeHash: false
                });
                replaceHash(mainPageId);
            }
        };

        // maybe we have to wait until the DOM is ready
        if (!document.body) {
            $(document).ready(function () {
                callback(component);
            }, false);
        } else {
            callback(component);
        }
    };

    var public = {
        init: init,
        injectTemplate: injectTemplate
    };

    return public;

})(jQuery);<commit_msg>remove unnecessary scope<commit_after>var demo = demo || {};

demo.Controller = (function ($) {

    // HTML Imports support feature test
    var supportsHTMLImports = Boolean('import' in document.createElement('link'));

    // Test to see if the browser supports the HTML template element by checking
    // for the presence of the template element's content attribute.
    var supportsHTMLTemplate = Boolean('content' in document.createElement('template'));

    // Replace location hash without new history entry
    var replaceHash;
    if ('replaceState' in history) {
        replaceHash = function (newhash) {
            if (('' + newhash).charAt(0) !== '#') {
                newhash = '#' + newhash;
            }
            history.replaceState('', '', newhash);
        };
    } else {
        var hash = location.hash;
        replaceHash = function (newhash) {
            if (location.hash !== hash) {
                history.back();
            }
            location.hash = newhash;
        };
    }

    var mainPage, mainPageId;

    var init = function (config) {

        // Always redirect to main page
        $(window).bind('hashchange', function () {
            var hash = location.hash.replace(/^#/, '');
            if (hash === '') {
                replaceHash(mainPageId);
            }
        });

        // Use jQuery.load() if we don't have native HTML Imports support
        if (!supportsHTMLImports) {
            var imports = $('link[rel=import]');
            for (var i = 0, len = imports.length; i < len; i++) {
                $('<template/>').appendTo(document.body).load($(imports[i]).attr('href'), function (response, status, xhr) {
                    if (status === 'error') {
                        throw msg + xhr.status + ' ' + xhr.statusText;
                    }
                });
            }
        }
    };

    var injectTemplate = function (options) {

        // Use an empty page for main page placeholder
        // and prevent jQuery Mobile to inject a blank page
        if (!mainPage) {
            mainPage = $('div[data-main-page]');
            mainPageId = mainPage.attr('data-main-page');
        }

        var templateDoc = document;

        if (supportsHTMLImports) {

            // templateDoc refers to the "importee", which is template.html
            var templateDoc = options.context.ownerDocument;
        }

        // Grab the contents of the template from templateDoc
        // and append it to the importing document.
        var template = templateDoc.querySelector('template[data-template-id="' + options.templateId + '"]');

        if (!template) {
            throw 'template with data-template-id="' + options.templateId + '"] not found';
        }

        var component;

        // If the browser supports HTML Template, we have to import the page Element
        // otherwise we will get the HTML Element already injected by jQuery.load()
        if (supportsHTMLTemplate) {
            component = document.importNode(template.content, true);
        } else {
            component = template.querySelector('#' + options.templateId);

            // remove component from the DOM
            $(component).remove();
        }

        var callback = function (component) {

            // If component is main page, replace it, if not, append
            // component maybe DOM Element or DocumentFragment
            if (options.templateId === mainPageId) {
                mainPage.replaceWith(component);
            } else {
                $(document.body).append(component);
            }

            component = $('#' + options.templateId); // Get injected DOM Element
            if (!component.hasClass('ui-' + component.attr('data-role'))) { // If not already enhanced
                component[component.attr('data-role')](); // enhance ;)
            }

            // If this template is the main page, show it instantly
            if (options.templateId === mainPageId) {
                $.mobile.changePage(component, {
                    transition: 'none',
                    changeHash: false
                });
                replaceHash(mainPageId);
            }
        };

        // maybe we have to wait until the DOM is ready
        if (!document.body) {
            $(document).ready(function () {
                callback(component);
            }, false);
        } else {
            callback(component);
        }
    };

    var public = {
        init: init,
        injectTemplate: injectTemplate
    };

    return public;

})(jQuery);<|endoftext|>


<commit_before>/*
	*************************

	Conflicting Options Tests

	*************************

	This spec has tests for checking if two or more options do not conflict with one another
	As option conflicts are reported and resolved, write tests for them here.
	This will help ensure that they are accounted for and do not arise again.
*/
describe("Conflicting Options Tests", function() {

	it("Should have the value zero when it is slided to zero", function() {
		var testSlider = $("#testSlider1").slider({
			value: 0,
			step: 1
		});
		var flag = false;
		var mouse = document.createEvent('MouseEvents');

		testSlider.on('slide', function(slideEvt) {
			expect(slideEvt.value).toBe(0);
			flag = true;
		});

	      	testSlider.data('slider')._mousemove(mouse);
		expect(flag).toBeTruthy();

    	});

	it("should set the `precision` to be the number of digits after the decimal of the `step` (assuming no `precision` is specified)", function() {
		// Create Slider
		var $testSlider = $("#testSlider1").slider({
			value: 8.115,
			step: 0.01
		});
		// Retrieve slider value
		var value = $testSlider.slider("getValue");
		// Run tests
		expect(value).toBe(8.12);
	});
});
<commit_msg>Cleanig everything after each test<commit_after>/*
	*************************

	Conflicting Options Tests

	*************************

	This spec has tests for checking if two or more options do not conflict with one another
	As option conflicts are reported and resolved, write tests for them here.
	This will help ensure that they are accounted for and do not arise again.
*/
describe("Conflicting Options Tests", function() {

	var testSlider;

	it("Should have the value zero when it is slided to zero", function() {
		var testSlider = $("#testSlider1").slider({
			value: 0,
			step: 1
		});
		var flag = false;
		var mouse = document.createEvent('MouseEvents');

		testSlider.on('slide', function(slideEvt) {
			expect(slideEvt.value).toBe(0);
			flag = true;
		});

	      	testSlider.data('slider')._mousemove(mouse);
		expect(flag).toBeTruthy();

    	});

	it("should set the `precision` to be the number of digits after the decimal of the `step` (assuming no `precision` is specified)", function() {
		// Create Slider
		var $testSlider = $("#testSlider1").slider({
			value: 8.115,
			step: 0.01
		});
		// Retrieve slider value
		var value = $testSlider.slider("getValue");
		// Run tests
		expect(value).toBe(8.12);
	});

	afterEach(function() {
	    if(testSlider) {
	      testSlider.slider('destroy');
	      testSlider = null;
	    }
  	});
});
<|endoftext|>


<commit_before>const sleep = require('../../utils/sleep')
const { newLogger } = require('testHelpers')
const InstrumentationEventEmitter = require('../../instrumentation/emitter')
const events = require('../instrumentationEvents')
const RequestQueue = require('./index')

describe('Network > RequestQueue', () => {
  let requestQueue
  let correlationId = 0

  const createEntry = () => ({
    correlationId: correlationId++,
    resolve: jest.fn(),
    reject: jest.fn(),
  })

  const createRequestQueue = (args = {}) =>
    new RequestQueue({
      maxInFlightRequests: 2,
      requestTimeout: 50,
      clientId: 'KafkaJS',
      broker: 'localhost:9092',
      logger: newLogger(),
      ...args,
    })

  beforeEach(() => {
    requestQueue = createRequestQueue()
  })

  describe('#push', () => {
    let request, send

    beforeEach(() => {
      send = jest.fn()
      request = {
        sendRequest: send,
        entry: createEntry(),
        expectResponse: true,
      }
    })

    it('calls send on the request', () => {
      requestQueue.push(request)
      expect(send).toHaveBeenCalledTimes(1)
    })

    describe('when the request does not require a response', () => {
      beforeEach(() => {
        request.expectResponse = false
      })

      it('deletes the inflight request and complete the request', () => {
        requestQueue.push(request)
        expect(request.entry.resolve).toHaveBeenCalledWith(
          expect.objectContaining({ size: 0, payload: null })
        )

        expect(requestQueue.inflight.size).toEqual(0)
      })
    })

    describe('when there are many inflight requests', () => {
      beforeEach(() => {
        while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
          const request = {
            sendRequest: jest.fn(),
            entry: createEntry(),
            expectResponse: true,
          }

          requestQueue.push(request)
        }
      })

      it('adds the new request to the pending queue', () => {
        expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
        requestQueue.push(request)
        expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
        expect(requestQueue.pending.length).toEqual(1)
      })

      describe('when maxInFlightRequests is null', () => {
        let maxInFlightRequests

        beforeEach(() => {
          maxInFlightRequests = requestQueue.maxInFlightRequests
          requestQueue.maxInFlightRequests = null
        })

        it('does not enforce the number of inflight requests', () => {
          expect(requestQueue.inflight.size).toEqual(maxInFlightRequests)
          requestQueue.push(request)
          expect(requestQueue.inflight.size).toEqual(maxInFlightRequests + 1)
        })
      })
    })
  })

  describe('#fulfillRequest', () => {
    let request, send, size, payload

    beforeEach(() => {
      send = jest.fn()
      payload = { ok: true }
      size = 32
      request = {
        sendRequest: send,
        entry: createEntry(),
        expectResponse: true,
      }

      requestQueue.push(request)
    })

    it('deletes the inflight request and calls completed on the request', () => {
      expect(requestQueue.inflight.size).toEqual(1)

      requestQueue.fulfillRequest({
        correlationId: request.entry.correlationId,
        payload,
        size,
      })

      expect(requestQueue.inflight.size).toEqual(0)
      expect(request.entry.resolve).toHaveBeenCalledWith(expect.objectContaining({ size, payload }))
    })

    describe('when there are pending requests', () => {
      beforeEach(() => {
        while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
          const request = {
            sendRequest: jest.fn(),
            entry: createEntry(),
            expectResponse: true,
          }

          requestQueue.push(request)
        }
      })

      it('calls send on the latest pending request', () => {
        requestQueue.push(request)
        expect(requestQueue.pending.length).toEqual(1)

        const currentInflightSize = requestQueue.inflight.size

        requestQueue.fulfillRequest({
          correlationId: request.entry.correlationId,
          payload,
          size,
        })

        expect(send).toHaveBeenCalled()
        expect(requestQueue.pending.length).toEqual(0)
        expect(requestQueue.inflight.size).toEqual(currentInflightSize - 1)
      })
    })
  })

  describe('#rejectAll', () => {
    it('calls rejected on all requests (inflight + pending)', () => {
      const allRequests = []
      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
        allRequests.push(request)
      }

      const pendingRequest = {
        sendRequest: jest.fn(),
        entry: createEntry(),
        expectResponse: true,
      }

      requestQueue.push(pendingRequest)
      allRequests.push(pendingRequest)

      expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
      expect(requestQueue.pending.length).toEqual(1)

      const error = new Error('Broker closed the connection')
      requestQueue.rejectAll(error)

      expect(requestQueue.inflight.size).toEqual(0)
      expect(requestQueue.pending.length).toEqual(0)

      for (const request of allRequests) {
        expect(request.entry.reject).toHaveBeenCalledWith(error)
      }
    })
  })

  describe('instrumentation events', () => {
    let emitter, removeListener, eventCalled, request, payload, size, requestTimeout

    beforeEach(() => {
      requestTimeout = 1
      eventCalled = jest.fn()
      emitter = new InstrumentationEventEmitter()
      requestQueue = createRequestQueue({
        instrumentationEmitter: emitter,
        enforceRequestTimeout: true,
        requestTimeout,
      })
      request = {
        sendRequest: jest.fn(),
        entry: createEntry(),
        expectResponse: true,
      }
      payload = { ok: true }
      size = 32
    })

    afterEach(() => {
      removeListener && removeListener()
    })

    it('does not emit the event if the queue size remains the same', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)
      expect(requestQueue.pending.length).toEqual(0)
      requestQueue.push(request)
      expect(requestQueue.pending.length).toEqual(0)
      expect(eventCalled).not.toHaveBeenCalled()
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when a new request is added', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)

      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
      }

      requestQueue.push(request)
      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: requestQueue.pending.length,
        },
      })
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when a request is removed', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)

      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
      }

      requestQueue.push(request)
      requestQueue.fulfillRequest({
        correlationId: request.entry.correlationId,
        payload,
        size,
      })

      expect(eventCalled).toHaveBeenCalledTimes(2)
      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: 0,
        },
      })
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when the requests are rejected', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)
      const error = new Error('Broker closed the connection')
      requestQueue.rejectAll(error)

      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: 0,
        },
      })
    })

    it('emits NETWORK_REQUEST_TIMEOUT', async () => {
      emitter.addListener(events.NETWORK_REQUEST_TIMEOUT, eventCalled)
      requestQueue.scheduleRequestTimeoutCheck()
      requestQueue.push(request)

      await sleep(requestTimeout + 1)

      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_timeout',
        timestamp: expect.any(Number),
        payload: {
          apiKey: request.entry.apiKey,
          apiName: request.entry.apiName,
          apiVersion: request.entry.apiVersion,
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          correlationId: expect.any(Number),
          createdAt: expect.any(Number),
          pendingDuration: expect.any(Number),
          sentAt: expect.any(Number),
        },
      })
    })
  })
})
<commit_msg>Give more room for NETWORK_REQUEST_TIMEOUT to emit<commit_after>const sleep = require('../../utils/sleep')
const { newLogger } = require('testHelpers')
const InstrumentationEventEmitter = require('../../instrumentation/emitter')
const events = require('../instrumentationEvents')
const RequestQueue = require('./index')

describe('Network > RequestQueue', () => {
  let requestQueue
  let correlationId = 0

  const createEntry = () => ({
    correlationId: correlationId++,
    resolve: jest.fn(),
    reject: jest.fn(),
  })

  const createRequestQueue = (args = {}) =>
    new RequestQueue({
      maxInFlightRequests: 2,
      requestTimeout: 50,
      clientId: 'KafkaJS',
      broker: 'localhost:9092',
      logger: newLogger(),
      ...args,
    })

  beforeEach(() => {
    requestQueue = createRequestQueue()
  })

  describe('#push', () => {
    let request, send

    beforeEach(() => {
      send = jest.fn()
      request = {
        sendRequest: send,
        entry: createEntry(),
        expectResponse: true,
      }
    })

    it('calls send on the request', () => {
      requestQueue.push(request)
      expect(send).toHaveBeenCalledTimes(1)
    })

    describe('when the request does not require a response', () => {
      beforeEach(() => {
        request.expectResponse = false
      })

      it('deletes the inflight request and complete the request', () => {
        requestQueue.push(request)
        expect(request.entry.resolve).toHaveBeenCalledWith(
          expect.objectContaining({ size: 0, payload: null })
        )

        expect(requestQueue.inflight.size).toEqual(0)
      })
    })

    describe('when there are many inflight requests', () => {
      beforeEach(() => {
        while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
          const request = {
            sendRequest: jest.fn(),
            entry: createEntry(),
            expectResponse: true,
          }

          requestQueue.push(request)
        }
      })

      it('adds the new request to the pending queue', () => {
        expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
        requestQueue.push(request)
        expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
        expect(requestQueue.pending.length).toEqual(1)
      })

      describe('when maxInFlightRequests is null', () => {
        let maxInFlightRequests

        beforeEach(() => {
          maxInFlightRequests = requestQueue.maxInFlightRequests
          requestQueue.maxInFlightRequests = null
        })

        it('does not enforce the number of inflight requests', () => {
          expect(requestQueue.inflight.size).toEqual(maxInFlightRequests)
          requestQueue.push(request)
          expect(requestQueue.inflight.size).toEqual(maxInFlightRequests + 1)
        })
      })
    })
  })

  describe('#fulfillRequest', () => {
    let request, send, size, payload

    beforeEach(() => {
      send = jest.fn()
      payload = { ok: true }
      size = 32
      request = {
        sendRequest: send,
        entry: createEntry(),
        expectResponse: true,
      }

      requestQueue.push(request)
    })

    it('deletes the inflight request and calls completed on the request', () => {
      expect(requestQueue.inflight.size).toEqual(1)

      requestQueue.fulfillRequest({
        correlationId: request.entry.correlationId,
        payload,
        size,
      })

      expect(requestQueue.inflight.size).toEqual(0)
      expect(request.entry.resolve).toHaveBeenCalledWith(expect.objectContaining({ size, payload }))
    })

    describe('when there are pending requests', () => {
      beforeEach(() => {
        while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
          const request = {
            sendRequest: jest.fn(),
            entry: createEntry(),
            expectResponse: true,
          }

          requestQueue.push(request)
        }
      })

      it('calls send on the latest pending request', () => {
        requestQueue.push(request)
        expect(requestQueue.pending.length).toEqual(1)

        const currentInflightSize = requestQueue.inflight.size

        requestQueue.fulfillRequest({
          correlationId: request.entry.correlationId,
          payload,
          size,
        })

        expect(send).toHaveBeenCalled()
        expect(requestQueue.pending.length).toEqual(0)
        expect(requestQueue.inflight.size).toEqual(currentInflightSize - 1)
      })
    })
  })

  describe('#rejectAll', () => {
    it('calls rejected on all requests (inflight + pending)', () => {
      const allRequests = []
      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
        allRequests.push(request)
      }

      const pendingRequest = {
        sendRequest: jest.fn(),
        entry: createEntry(),
        expectResponse: true,
      }

      requestQueue.push(pendingRequest)
      allRequests.push(pendingRequest)

      expect(requestQueue.inflight.size).toEqual(requestQueue.maxInFlightRequests)
      expect(requestQueue.pending.length).toEqual(1)

      const error = new Error('Broker closed the connection')
      requestQueue.rejectAll(error)

      expect(requestQueue.inflight.size).toEqual(0)
      expect(requestQueue.pending.length).toEqual(0)

      for (const request of allRequests) {
        expect(request.entry.reject).toHaveBeenCalledWith(error)
      }
    })
  })

  describe('instrumentation events', () => {
    let emitter, removeListener, eventCalled, request, payload, size, requestTimeout

    beforeEach(() => {
      requestTimeout = 1
      eventCalled = jest.fn()
      emitter = new InstrumentationEventEmitter()
      requestQueue = createRequestQueue({
        instrumentationEmitter: emitter,
        enforceRequestTimeout: true,
        requestTimeout,
      })
      request = {
        sendRequest: jest.fn(),
        entry: createEntry(),
        expectResponse: true,
      }
      payload = { ok: true }
      size = 32
    })

    afterEach(() => {
      removeListener && removeListener()
    })

    it('does not emit the event if the queue size remains the same', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)
      expect(requestQueue.pending.length).toEqual(0)
      requestQueue.push(request)
      expect(requestQueue.pending.length).toEqual(0)
      expect(eventCalled).not.toHaveBeenCalled()
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when a new request is added', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)

      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
      }

      requestQueue.push(request)
      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: requestQueue.pending.length,
        },
      })
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when a request is removed', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)

      while (requestQueue.inflight.size < requestQueue.maxInFlightRequests) {
        const request = {
          sendRequest: jest.fn(),
          entry: createEntry(),
          expectResponse: true,
        }

        requestQueue.push(request)
      }

      requestQueue.push(request)
      requestQueue.fulfillRequest({
        correlationId: request.entry.correlationId,
        payload,
        size,
      })

      expect(eventCalled).toHaveBeenCalledTimes(2)
      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: 0,
        },
      })
    })

    it('emits NETWORK_REQUEST_QUEUE_SIZE when the requests are rejected', () => {
      emitter.addListener(events.NETWORK_REQUEST_QUEUE_SIZE, eventCalled)
      const error = new Error('Broker closed the connection')
      requestQueue.rejectAll(error)

      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_queue_size',
        timestamp: expect.any(Number),
        payload: {
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          queueSize: 0,
        },
      })
    })

    it('emits NETWORK_REQUEST_TIMEOUT', async () => {
      emitter.addListener(events.NETWORK_REQUEST_TIMEOUT, eventCalled)
      requestQueue.scheduleRequestTimeoutCheck()
      requestQueue.push(request)

      await sleep(requestTimeout + 10)

      expect(eventCalled).toHaveBeenCalledWith({
        id: expect.any(Number),
        type: 'network.request_timeout',
        timestamp: expect.any(Number),
        payload: {
          apiKey: request.entry.apiKey,
          apiName: request.entry.apiName,
          apiVersion: request.entry.apiVersion,
          broker: 'localhost:9092',
          clientId: 'KafkaJS',
          correlationId: expect.any(Number),
          createdAt: expect.any(Number),
          pendingDuration: expect.any(Number),
          sentAt: expect.any(Number),
        },
      })
    })
  })
})
<|endoftext|>


<commit_before>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Shows the home screen for a multi-tab simulation, which lets the user see all of the tabs and select one.
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var PhetButton = require( 'JOIST/PhetButton' );
  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var Text = require( 'SCENERY/nodes/Text' );
  var inherit = require( 'PHET_CORE/inherit' );
  var TabView = require( 'JOIST/TabView' );
  var Frame = require( 'JOIST/Frame' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var Highlight = require( 'JOIST/Highlight' );
  var Property = require( 'AXON/Property' );

  var HEIGHT = 70;

  function HomeScreen( sim ) {
    var homeScreen = this;

    //Rendering in SVG seems to solve the problem that the home screen consumes 100% disk and crashes, see https://github.com/phetsims/joist/issues/17
    //Also makes it more responsive (and crisper on retina displays)
    TabView.call( this, {renderer: 'svg'} );

    this.backgroundColor = 'black';

    //iPad doesn't support Century Gothic, so fall back to Futura, see http://wordpress.org/support/topic/font-not-working-on-ipad-browser
    var title = new Text( sim.name, {fontSize: 52, fontFamily: 'Century Gothic, Futura', fill: 'white', y: 110, centerX: this.layoutBounds.width / 2} );
    this.addChild( title );

    //Keep track of which tab is highlighted so the same tab can remain highlighted even if nodes are replaced (say when one grows larger or smaller)
    var highlightedIndex = new Property( -1 );

    var tabChildren = _.map( sim.tabs, function( tab ) {
      var index = sim.tabs.indexOf( tab );
      var largeIcon = new Node( {children: [tab.icon], scale: HEIGHT / tab.icon.height * 2} );
      var largeIconWithFrame = new Node( {children: [new Frame( largeIcon ), largeIcon]} );
      var large = new VBox( {cursor: 'pointer', children: [
        largeIconWithFrame,
        new Text( tab.name, {fontSize: 42, fill: 'yellow'} )
      ]} );
      large.addInputListener( { down: function() {
        sim.simModel.showHomeScreen = false;
        highlightedIndex.value = -1;
      }} );

      var small = new VBox( {spacing: 3, cursor: 'pointer', children: [
        new Node( {opacity: 0.5, children: [tab.icon], scale: sim.tabs.length === 4 ? HEIGHT / tab.icon.height :
                                                              sim.tabs.length === 3 ? 1.25 * HEIGHT / tab.icon.height :
                                                              sim.tabs.length === 2 ? 1.75 * HEIGHT / tab.icon.height :
                                                              HEIGHT / tab.icon.height} ),
        new Text( tab.name, {fontSize: 18, fill: 'gray'} )
      ]} );
      small.mouseArea = small.bounds; //cover the gap in the vbox
      small.addInputListener( { down: function() { sim.simModel.tabIndex = index; }} );

      var smallHighlight = Highlight.createHighlight( small.width + 6, small.height );
      smallHighlight.centerX = small.centerX;
      small.addChild( smallHighlight );
      var highlightListener = {
        over: function( event ) {
          if ( event.pointer.isMouse ) {
            highlightedIndex.value = index;
          }
        },
        out: function( event ) { if ( event.pointer.isMouse ) {highlightedIndex.value = -1;} }
      };
      highlightedIndex.valueEquals( index ).linkAttribute( smallHighlight, 'visible' );
      small.addInputListener( highlightListener );

      var largeHighlight = Highlight.createHighlight( large.width + 8, large.height );
      largeHighlight.centerX = large.centerX;
      highlightedIndex.valueEquals( index ).linkAttribute( largeHighlight, 'visible' );
      large.addChild( largeHighlight );
      large.addInputListener( highlightListener );
      large.mouseArea = large.bounds; //cover the gap in the vbox

      //TODO: Add accessibility peers
      //      tabChild.addPeer( '<input type="button" aria-label="' + tabChild.tab.name + '">', {click: function() {
//        var tab = tabChild.tab;
//        if ( sim.simModel.tabIndex === tab.index ) {
//          sim.simModel.showHomeScreen = false;
//        }
//        else {
//          sim.simModel.tabIndex = tab.index;
//        }
//      }} );
//    } );

      return {tab: tab, small: small, large: large, index: index};
    } );

    var center = new Node( {y: 170} );
    homeScreen.addChild( center );
    sim.simModel.tabIndexProperty.link( function( tabIndex ) {

      //Space the icons out more if there are fewer, so they will be spaced nicely
      //Cannot have only 1 tab because for 1-tab sims there is no home screen.
      var spacing = sim.tabs.length === 2 ? 60 :
                    sim.tabs.length === 3 ? 60 :
                    33;

      var icons = _.map( tabChildren, function( tabChild ) {return tabChild.index === tabIndex ? tabChild.large : tabChild.small;} );
      center.children = [new HBox( {spacing: spacing, children: icons, align: 'top'} )];
      center.centerX = homeScreen.layoutBounds.width / 2;
    } );

    var phetButton = new PhetButton( sim, {right: this.layoutBounds.maxX - 5, bottom: this.layoutBounds.maxY - 5} );
    this.addChild( phetButton );
  }

  inherit( TabView, HomeScreen );

  return HomeScreen;
} );<commit_msg>On the home screen if you touch an inactive tab thumbnail, it grows.  If then without lifting your finger you swipe over to the next thumbnail, that one would grow<commit_after>// Copyright 2002-2013, University of Colorado Boulder

/**
 * Shows the home screen for a multi-tab simulation, which lets the user see all of the tabs and select one.
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  var PhetButton = require( 'JOIST/PhetButton' );
  var Node = require( 'SCENERY/nodes/Node' );
  var HBox = require( 'SCENERY/nodes/HBox' );
  var VBox = require( 'SCENERY/nodes/VBox' );
  var Text = require( 'SCENERY/nodes/Text' );
  var inherit = require( 'PHET_CORE/inherit' );
  var TabView = require( 'JOIST/TabView' );
  var Frame = require( 'JOIST/Frame' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var Highlight = require( 'JOIST/Highlight' );
  var Property = require( 'AXON/Property' );

  var HEIGHT = 70;

  function HomeScreen( sim ) {
    var homeScreen = this;

    //Rendering in SVG seems to solve the problem that the home screen consumes 100% disk and crashes, see https://github.com/phetsims/joist/issues/17
    //Also makes it more responsive (and crisper on retina displays)
    TabView.call( this, {renderer: 'svg'} );

    this.backgroundColor = 'black';

    //iPad doesn't support Century Gothic, so fall back to Futura, see http://wordpress.org/support/topic/font-not-working-on-ipad-browser
    var title = new Text( sim.name, {fontSize: 52, fontFamily: 'Century Gothic, Futura', fill: 'white', y: 110, centerX: this.layoutBounds.width / 2} );
    this.addChild( title );

    //Keep track of which tab is highlighted so the same tab can remain highlighted even if nodes are replaced (say when one grows larger or smaller)
    var highlightedIndex = new Property( -1 );

    var tabChildren = _.map( sim.tabs, function( tab ) {
      var index = sim.tabs.indexOf( tab );
      var largeIcon = new Node( {children: [tab.icon], scale: HEIGHT / tab.icon.height * 2} );
      var largeIconWithFrame = new Node( {children: [new Frame( largeIcon ), largeIcon]} );
      var large = new VBox( {cursor: 'pointer', children: [
        largeIconWithFrame,
        new Text( tab.name, {fontSize: 42, fill: 'yellow'} )
      ]} );
      large.addInputListener( { down: function() {
        sim.simModel.showHomeScreen = false;
        highlightedIndex.value = -1;
      }} );

      var small = new VBox( {spacing: 3, cursor: 'pointer', children: [
        new Node( {opacity: 0.5, children: [tab.icon], scale: sim.tabs.length === 4 ? HEIGHT / tab.icon.height :
                                                              sim.tabs.length === 3 ? 1.25 * HEIGHT / tab.icon.height :
                                                              sim.tabs.length === 2 ? 1.75 * HEIGHT / tab.icon.height :
                                                              HEIGHT / tab.icon.height} ),
        new Text( tab.name, {fontSize: 18, fill: 'gray'} )
      ]} );
      small.mouseArea = small.bounds; //cover the gap in the vbox
      small.addInputListener( {
        down: function() { sim.simModel.tabIndex = index; },

        //On the home screen if you touch an inactive tab thumbnail, it grows.  If then without lifting your finger you swipe over
        // to the next thumbnail, that one would grow.
        over: function( event ) {
          if ( !event.pointer.isMouse ) {
            sim.simModel.tabIndex = index;
          }
        }
      } );

      var smallHighlight = Highlight.createHighlight( small.width + 6, small.height );
      smallHighlight.centerX = small.centerX;
      small.addChild( smallHighlight );
      var highlightListener = {
        over: function( event ) {
          if ( event.pointer.isMouse ) {
            highlightedIndex.value = index;
          }
        },
        out: function( event ) { if ( event.pointer.isMouse ) {highlightedIndex.value = -1;} }
      };
      highlightedIndex.valueEquals( index ).linkAttribute( smallHighlight, 'visible' );
      small.addInputListener( highlightListener );

      var largeHighlight = Highlight.createHighlight( large.width + 8, large.height );
      largeHighlight.centerX = large.centerX;
      highlightedIndex.valueEquals( index ).linkAttribute( largeHighlight, 'visible' );
      large.addChild( largeHighlight );
      large.addInputListener( highlightListener );
      large.mouseArea = large.bounds; //cover the gap in the vbox

      //TODO: Add accessibility peers
      //      tabChild.addPeer( '<input type="button" aria-label="' + tabChild.tab.name + '">', {click: function() {
//        var tab = tabChild.tab;
//        if ( sim.simModel.tabIndex === tab.index ) {
//          sim.simModel.showHomeScreen = false;
//        }
//        else {
//          sim.simModel.tabIndex = tab.index;
//        }
//      }} );
//    } );

      return {tab: tab, small: small, large: large, index: index};
    } );

    var center = new Node( {y: 170} );
    homeScreen.addChild( center );
    sim.simModel.tabIndexProperty.link( function( tabIndex ) {

      //Space the icons out more if there are fewer, so they will be spaced nicely
      //Cannot have only 1 tab because for 1-tab sims there is no home screen.
      var spacing = sim.tabs.length === 2 ? 60 :
                    sim.tabs.length === 3 ? 60 :
                    33;

      var icons = _.map( tabChildren, function( tabChild ) {return tabChild.index === tabIndex ? tabChild.large : tabChild.small;} );
      center.children = [new HBox( {spacing: spacing, children: icons, align: 'top'} )];
      center.centerX = homeScreen.layoutBounds.width / 2;
    } );

    var phetButton = new PhetButton( sim, {right: this.layoutBounds.maxX - 5, bottom: this.layoutBounds.maxY - 5} );
    this.addChild( phetButton );
  }

  inherit( TabView, HomeScreen );

  return HomeScreen;
} );<|endoftext|>


<commit_before>// colors is a color library for random color generation in representations
colors = [0xFF1E00, 0xFFB300, 0x1533AD, 0x00BF32, 0xBF4030,
          0xBF9430, 0x2C3D82, 0x248F40, 0xA61300, 0xA67400,
          0x071C71, 0x007C21, 0xFF5640, 0xFFC640, 0x4965D6,
          0x38DF64, 0xFF8373, 0xFFD573, 0x6F83D6, 0x64DF85,
          0xFF5600, 0xFF7C00, 0x04859D, 0x00AA72, 0x60D4AE,
          0xBF6030, 0xBF7630, 0x206876, 0x207F60, 0x5FBDCE,
          0xA63800, 0xA65100, 0x015666, 0x006E4A, 0xFFB773,
          0xFF8040, 0xFF9D40, 0x37B6CE, 0x35D4A0, 0xFFA273];

/* FiberSkeleton creates 3D representation of control points and fiber path
  from a given fiber.
  Subject-Observer pattern must be enabled and fired from subject with .refresh();
  Input: fiber - FiberSource object.

  Main properties:
    .line - the thread representing the path. Ready for scene.add.
    .spheres - the mesh of all the spheres representing the control points.
          ready for scene.add.

  Other properties:
    .fiber - The fiber from which the representation constructed (FiberSource)
    .segments - The amount of length segments in which the fiber is divided
        for representation. By default, 256.
    .color - color of the thread

  Methods:
    .refresh() - Updates meshes after fiber change. No input no output.

*/
function FiberSkeleton(fiber) {
  this.fiber = fiber;
  points = fiber.controlPoints;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);
  // Segments by default
  this.segments = 256;

  // Create line thread
  // Interpolate points for THREE.BufferAttribute needs
  discrete_points = new Float32Array(3*this.segments+3);
  for (var i = 0; i <= this.segments; i++) {
    discrete_points.set([fiber.interpolate(i/this.segments)[0][0],
                         fiber.interpolate(i/this.segments)[0][1],
                         fiber.interpolate(i/this.segments)[0][2]], 3*i);
  }
  // Create trajectory
  var trajectory = new THREE.BufferGeometry();
  trajectory.addAttribute('position', new THREE.BufferAttribute(discrete_points, 3));
  // Create thread material
  var thread = new THREE.LineBasicMaterial({ color:this.color, linewidth: 1 });
  // / Build line
  this.line = new THREE.Line(trajectory, thread);

  // Create sphere mesh for controlPoints
  // sphere is the prototype sphere
  var sphere = new THREE.SphereGeometry(fiber.radius/5, 32, 32 );
  var sphereGeometry = new THREE.Geometry();
  // All spheres to be added are meshed in one single geometry
  var meshes = [];
  for (var i = 0; i < points.length; i++) {
    meshes[i] = new THREE.Mesh(sphere);
    meshes[i].position.set(points[i][0], points[i][1], points[i][2]);
    meshes[i].updateMatrix();
    sphereGeometry.merge(meshes[i].geometry, meshes[i].matrix);
  }
  var surface = new THREE.MeshBasicMaterial( {color: 0xffff00} );
  // Build spheres mesh
  this.spheres = new THREE.Mesh(sphereGeometry, surface);
}

FiberSkeleton.prototype.refresh = function() {
  // Spheres mesh must be built again
  var sphere = new THREE.SphereGeometry(this.fiber.radius/5, 32, 32 );
  var sphereGeometry = new THREE.Geometry();
  var meshes = [];
  for (var i = 0; i < points.length; i++) {
    meshes[i] = new THREE.Mesh(sphere);
    meshes[i].position.set(points[i][0], points[i][1], points[i][2]);
    meshes[i].updateMatrix();
    sphereGeometry.merge(meshes[i].geometry, meshes[i].matrix);
  }
  this.spheres.geometry = sphereGeometry;

  // Thread trajectory must be built again as well
  var discrete_points = new Float32Array(3*this.segments+3);
  for (var i = 0; i <= this.segments; i++) {
    discrete_points.set([this.fiber.interpolate(i/this.segments)[0][0],
                         this.fiber.interpolate(i/this.segments)[0][1],
                         this.fiber.interpolate(i/this.segments)[0][2]], 3*i);
  }
  var trajectory = new THREE.BufferGeometry();
  trajectory.addAttribute('position', new THREE.BufferAttribute(discrete_points, 3));
  this.line.geometry = trajectory;
  // Line color is to be kept
  this.line.material.color = this.color;
}

/* FiberTube creates a 3D representation of a given fiber in a tubular form
 of given radius.
 Subject-Observer pattern must be enabled and fired from subject with .refresh();
 Inputs: fiber - FiberSource object.

 Main properties:
   .mesh - the mesh of the fiber Ready for scene.add.

 Other properties:
   .fiber - The fiber from which the representation constructed (FiberSource)
   .curve - THREE.Curve object used for representation
   .axialSegments and .radialSegments: The segments that make up the tube in
      each dimension. Default is 256 and 64.
   .color - color of the tube

  Methods:
   .refresh() - Updates mesh after fiber change. No input no output.
 */
function FiberTube(fiber) {
  this.fiber = fiber;
  // Check if radius was specified. If not, set default.
  if (fiber.radius === undefined) fiber.radius = 1;
  this.radius = fiber.radius;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);
  // Segments by default
  this.axialSegments = 256;
  this.radialSegments = 64;

  //Curve is part of tube geometry
  this.curve = Object.create(THREE.Curve.prototype);
  // .getPoint must be part of curve object
  this.curve.getPoint = function(t) {
      var tx = fiber.interpolate(t)[0][0];
      var ty = fiber.interpolate(t)[0][1];
      var tz = fiber.interpolate(t)[0][2];
  return new THREE.Vector3(tx, ty, tz);
  }
  // Geometry and materials are created
  var geometry = new THREE.TubeGeometry(this.curve,
                        this.axialSegments , this.radius, this.radialSegments);
  var material = new THREE.MeshPhongMaterial( { color:this.color, shading: THREE.FlatShading } );
  // Transparency must be enabled so to be able to fade the tube
  material.transparent = true;
  // Double side is needed so a tube appareance is acquired
  material.side = THREE.DoubleSide;
  this.mesh = new THREE.Mesh(geometry, material);
}
FiberTube.prototype.refresh = function() {
  this.mesh.geometry = new THREE.TubeGeometry(this.curve,
                this.axialSegments, this.radius, this.radialSegments);
}

/* IsotropicRegion creates a mesh from an IsotropicRegionSource.
  Subject-Observer pattern must be enabled and fired from subject with .refresh();
  Input: source - IsotropicRegionSource

  Main properties:
    .mesh - the mesh of the region ready for scene.add.

  Other properties:
    .source - The region from which the representation constructed (IsotropicRegionSource)
    .widthSegments and .heightSegments: The segments that make up the sphere in
       each dimension. Default is 128.
    .color - color of the sphere

   Methods:
    .refresh() - Updates mesh after source change. No input no output.
*/
function IsotropicRegion(source) {
  this.source = source;
  this.widthSegments = 128;
  this.heightSegments = 128;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);

  var geometry = new THREE.SphereGeometry( source.radius, this.widthSegments, this.heightSegments );
  var material = new THREE.MeshPhongMaterial( { color:this.color, shading: THREE.FlatShading } );
  // Transparency must be enabled so to be able to fade the tube
  material.transparent = true;
  this.mesh = new THREE.Mesh(geometry, material);
  this.mesh.position.set(source.center[0], source.center[1], source.center[2]);
}
IsotropicRegion.prototype.refresh = function() {
    this.mesh.geometry = new THREE.SphereGeometry( this.source.radius, this.widthSegments, this.heightSegments );
    this.mesh.position.set(this.source.center[0], this.source.center[1], this.source.center[2]);
}
<commit_msg>MeshSource.js vars to camelCase.<commit_after>// colors is a color library for random color generation in representations
colors = [0xFF1E00, 0xFFB300, 0x1533AD, 0x00BF32, 0xBF4030,
          0xBF9430, 0x2C3D82, 0x248F40, 0xA61300, 0xA67400,
          0x071C71, 0x007C21, 0xFF5640, 0xFFC640, 0x4965D6,
          0x38DF64, 0xFF8373, 0xFFD573, 0x6F83D6, 0x64DF85,
          0xFF5600, 0xFF7C00, 0x04859D, 0x00AA72, 0x60D4AE,
          0xBF6030, 0xBF7630, 0x206876, 0x207F60, 0x5FBDCE,
          0xA63800, 0xA65100, 0x015666, 0x006E4A, 0xFFB773,
          0xFF8040, 0xFF9D40, 0x37B6CE, 0x35D4A0, 0xFFA273];

/* FiberSkeleton creates 3D representation of control points and fiber path
  from a given fiber.
  Subject-Observer pattern must be enabled and fired from subject with .refresh();
  Input: fiber - FiberSource object.

  Main properties:
    .line - the thread representing the path. Ready for scene.add.
    .spheres - the mesh of all the spheres representing the control points.
          ready for scene.add.

  Other properties:
    .fiber - The fiber from which the representation constructed (FiberSource)
    .segments - The amount of length segments in which the fiber is divided
        for representation. By default, 256.
    .color - color of the thread

  Methods:
    .refresh() - Updates meshes after fiber change. No input no output.

*/
function FiberSkeleton(fiber) {
  this.fiber = fiber;
  points = fiber.controlPoints;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);
  // Segments by default
  this.segments = 256;

  // Create line thread
  // Interpolate points for THREE.BufferAttribute needs
  discretePoints = new Float32Array(3*this.segments+3);
  for (var i = 0; i <= this.segments; i++) {
    discretePoints.set([fiber.interpolate(i/this.segments)[0][0],
                         fiber.interpolate(i/this.segments)[0][1],
                         fiber.interpolate(i/this.segments)[0][2]], 3*i);
  }
  // Create trajectory
  var trajectory = new THREE.BufferGeometry();
  trajectory.addAttribute('position', new THREE.BufferAttribute(discretePoints, 3));
  // Create thread material
  var thread = new THREE.LineBasicMaterial({ color:this.color, linewidth: 1 });
  // / Build line
  this.line = new THREE.Line(trajectory, thread);

  // Create sphere mesh for controlPoints
  // sphere is the prototype sphere
  var sphere = new THREE.SphereGeometry(fiber.radius/5, 32, 32 );
  var sphereGeometry = new THREE.Geometry();
  // All spheres to be added are meshed in one single geometry
  var meshes = [];
  for (var i = 0; i < points.length; i++) {
    meshes[i] = new THREE.Mesh(sphere);
    meshes[i].position.set(points[i][0], points[i][1], points[i][2]);
    meshes[i].updateMatrix();
    sphereGeometry.merge(meshes[i].geometry, meshes[i].matrix);
  }
  var surface = new THREE.MeshBasicMaterial( {color: 0xffff00} );
  // Build spheres mesh
  this.spheres = new THREE.Mesh(sphereGeometry, surface);
}

FiberSkeleton.prototype.refresh = function() {
  // Spheres mesh must be built again
  var sphere = new THREE.SphereGeometry(this.fiber.radius/5, 32, 32 );
  var sphereGeometry = new THREE.Geometry();
  var meshes = [];
  for (var i = 0; i < points.length; i++) {
    meshes[i] = new THREE.Mesh(sphere);
    meshes[i].position.set(points[i][0], points[i][1], points[i][2]);
    meshes[i].updateMatrix();
    sphereGeometry.merge(meshes[i].geometry, meshes[i].matrix);
  }
  this.spheres.geometry = sphereGeometry;

  // Thread trajectory must be built again as well
  var discretePoints = new Float32Array(3*this.segments+3);
  for (var i = 0; i <= this.segments; i++) {
    discretePoints.set([this.fiber.interpolate(i/this.segments)[0][0],
                         this.fiber.interpolate(i/this.segments)[0][1],
                         this.fiber.interpolate(i/this.segments)[0][2]], 3*i);
  }
  var trajectory = new THREE.BufferGeometry();
  trajectory.addAttribute('position', new THREE.BufferAttribute(discretePoints, 3));
  this.line.geometry = trajectory;
  // Line color is to be kept
  this.line.material.color = this.color;
}

/* FiberTube creates a 3D representation of a given fiber in a tubular form
 of given radius.
 Subject-Observer pattern must be enabled and fired from subject with .refresh();
 Inputs: fiber - FiberSource object.

 Main properties:
   .mesh - the mesh of the fiber Ready for scene.add.

 Other properties:
   .fiber - The fiber from which the representation constructed (FiberSource)
   .curve - THREE.Curve object used for representation
   .axialSegments and .radialSegments: The segments that make up the tube in
      each dimension. Default is 256 and 64.
   .color - color of the tube

  Methods:
   .refresh() - Updates mesh after fiber change. No input no output.
 */
function FiberTube(fiber) {
  this.fiber = fiber;
  // Check if radius was specified. If not, set default.
  if (fiber.radius === undefined) fiber.radius = 1;
  this.radius = fiber.radius;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);
  // Segments by default
  this.axialSegments = 256;
  this.radialSegments = 64;

  //Curve is part of tube geometry
  this.curve = Object.create(THREE.Curve.prototype);
  // .getPoint must be part of curve object
  this.curve.getPoint = function(t) {
      var tx = fiber.interpolate(t)[0][0];
      var ty = fiber.interpolate(t)[0][1];
      var tz = fiber.interpolate(t)[0][2];
  return new THREE.Vector3(tx, ty, tz);
  }
  // Geometry and materials are created
  var geometry = new THREE.TubeGeometry(this.curve,
                        this.axialSegments , this.radius, this.radialSegments);
  var material = new THREE.MeshPhongMaterial( { color:this.color, shading: THREE.FlatShading } );
  // Transparency must be enabled so to be able to fade the tube
  material.transparent = true;
  // Double side is needed so a tube appareance is acquired
  material.side = THREE.DoubleSide;
  this.mesh = new THREE.Mesh(geometry, material);
}
FiberTube.prototype.refresh = function() {
  this.mesh.geometry = new THREE.TubeGeometry(this.curve,
                this.axialSegments, this.radius, this.radialSegments);
}

/* IsotropicRegion creates a mesh from an IsotropicRegionSource.
  Subject-Observer pattern must be enabled and fired from subject with .refresh();
  Input: source - IsotropicRegionSource

  Main properties:
    .mesh - the mesh of the region ready for scene.add.

  Other properties:
    .source - The region from which the representation constructed (IsotropicRegionSource)
    .widthSegments and .heightSegments: The segments that make up the sphere in
       each dimension. Default is 128.
    .color - color of the sphere

   Methods:
    .refresh() - Updates mesh after source change. No input no output.
*/
function IsotropicRegion(source) {
  this.source = source;
  this.widthSegments = 128;
  this.heightSegments = 128;
  this.color = new THREE.Color(colors[Math.floor(Math.random()*colors.length)]);

  var geometry = new THREE.SphereGeometry( source.radius, this.widthSegments, this.heightSegments );
  var material = new THREE.MeshPhongMaterial( { color:this.color, shading: THREE.FlatShading } );
  // Transparency must be enabled so to be able to fade the tube
  material.transparent = true;
  this.mesh = new THREE.Mesh(geometry, material);
  this.mesh.position.set(source.center[0], source.center[1], source.center[2]);
}
IsotropicRegion.prototype.refresh = function() {
    this.mesh.geometry = new THREE.SphereGeometry( this.source.radius, this.widthSegments, this.heightSegments );
    this.mesh.position.set(this.source.center[0], this.source.center[1], this.source.center[2]);
}
<|endoftext|>


<commit_before>'use strict';

var Promise = global.Promise || require('promise');

var glob       = require('glob'),
    Handlebars = require('handlebars'),
    fs         = require('graceful-fs'),
    path       = require('path'),
    semver     = require('semver'),
    utils      = require('./utils');

module.exports = ExpressHandlebars;

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

function ExpressHandlebars(config) {
    config || (config = {});

    this.handlebars  = config.handlebars  || this.handlebars;
    this.extname     = config.extname     || this.extname;
    this.layoutsDir  = config.layoutsDir  || this.layoutsDir;
    this.partialsDir = config.partialsDir || this.partialsDir;

    this.handlebarsVersion =
            ExpressHandlebars.getHandlebarsSemver(this.handlebars);

    if (this.extname.charAt(0) !== '.') {
        this.extname = '.' + this.extname;
    }

    this.defaultLayout = config.defaultLayout;
    this.helpers       = config.helpers;

    this.compiled    = {};
    this.precompiled = {};

    this.engine = this.renderView.bind(this);
}

ExpressHandlebars._fsCache = {};

ExpressHandlebars.getHandlebarsSemver = function (handlebars) {
    var version = handlebars.VERSION || '';

    // Makes sure the Handlebars version is a valid semver.
    if (version && !semver.valid(version)) {
        version = version.replace(/(\d\.\d)\.(\D.*)/, '$1.0-$2');
    }

    return version;
};

ExpressHandlebars.prototype.handlebars  = Handlebars;
ExpressHandlebars.prototype.extname     = '.handlebars';
ExpressHandlebars.prototype.layoutsDir  = 'views/layouts/';
ExpressHandlebars.prototype.partialsDir = 'views/partials/';

ExpressHandlebars.prototype.compileTemplate = function (template, options) {
    options || (options = {});

    var compiler = options.precompiled ? 'precompile' : 'compile',
        compile  = this.handlebars[compiler];

    return compile(template);
};

ExpressHandlebars.prototype.getTemplate = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var precompiled = options.precompiled,
        cache       = precompiled ? this.precompiled : this.compiled,
        template    = options.cache && cache[filePath];

    if (template) {
        return template;
    }

    // Optimistically cache template promise to reduce file system I/O, but
    // remove from cache if there was a problem.
    template = cache[filePath] = this._getFile(filePath, options)
        .then(function (file) {
            return this.compileTemplate(file, options);
        }.bind(this));

    return template.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressHandlebars.prototype.getPartials = function (options) {
    options || (options = {});

    var partialsDirs = Array.isArray(this.partialsDir) ?
            this.partialsDir : [this.partialsDir];

    partialsDirs = partialsDirs.map(function (dir) {
        var getTemplates = this.getTemplates.bind(this);
        if (typeof dir === 'string') {
            dir = {dir: dir};
        }

        return new Promise(function (resolve, reject) {
            getTemplates(dir.dir, options).then(function (templates) {
                resolve({templates: templates, namespace: dir.namespace});
            }, reject);
        });
    }, this);

    return Promise.all(partialsDirs).then(function (dirs) {
        var getPartialName = this._getPartialName.bind(this);

        return dirs.reduce(function (partials, dir) {
            Object.keys(dir.templates).forEach(function (filePath) {
                partials[getPartialName(filePath, dir.namespace)] = dir.templates[filePath];
            });

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

ExpressHandlebars.prototype.getTemplates = function (dirPath, options) {
    options || (options = {});

    return this._getDir(dirPath, options).then(function (filePaths) {
        var templates = filePaths.map(function (filePath) {
            return this.getTemplate(path.join(dirPath, filePath), options);
        }, this);

        return Promise.all(templates).then(function (templates) {
            return filePaths.reduce(function (map, filePath, i) {
                map[filePath] = templates[i];
                return map;
            }, {});
        });
    }.bind(this));
};

ExpressHandlebars.prototype.render = function (filePath, context, options) {
    options || (options = {});

    // Force `precompiled` to `false` since we're rendering to HTML.
    if (options.precompiled) {
        options = utils.extend({}, options, {precompiled: false});
    }

    return Promise.all([
        this.getTemplate(filePath, options),
        options.partials || this.getPartials(options)
    ]).then(function (templates) {
        var template = templates[0],
            partials = templates[1],
            data     = options.data;

        var helpers = options.helpers ||
                utils.extend({}, this.handlebars.helpers, this.helpers);

        return this._renderTemplate(template, context, {
            data    : data,
            helpers : helpers,
            partials: partials
        });
    }.bind(this));
};

ExpressHandlebars.prototype.renderView = function (viewPath, options, callback) {
    var context = options,
        data    = options.data;

    var helpers = utils.extend({},
            this.handlebars.helpers, this.helpers, options.helpers);

    // Pluck-out ExpressHandlebars-specific options.
    options = {
        cache      : options.cache,
        layout     : 'layout' in options ? options.layout : this.defaultLayout,
        precompiled: false
    };

    // Extend `options` with Handlebars-specific rendering options.
    utils.extend(options, {
        data    : data,
        helpers : helpers,
        partials: this.getPartials(options)
    });

    this.render(viewPath, context, options)
        .then(function (body) {
            var layoutPath = this._resolveLayoutPath(options.layout);

            if (layoutPath) {
                context = utils.extend({}, context, {body: body});
                return this.render(layoutPath, context, options);
            }
        }.bind(this))
        .then(utils.passValue(callback))
        .catch(utils.passError(callback));
};

ExpressHandlebars.prototype._getDir = function (dirPath, options) {
    dirPath = path.resolve(dirPath);

    var cache = ExpressHandlebars._fsCache,
        dir   = options.cache && cache[dirPath];

    if (dir) {
        return dir.then(function (dir) {
            return dir.concat();
        });
    }

    var pattern = '**/*' + this.extname;

    // Optimistically cache dir promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    dir = cache[dirPath] = new Promise(function (resolve, reject) {
        glob(pattern, {cwd: dirPath}, function (err, dir) {
            if (err) {
                reject(err);
            } else {
                resolve(dir);
            }
        });
    });

    return dir.then(function (dir) {
        return dir.concat();
    }).catch(function (err) {
        delete cache[dirPath];
        throw err;
    });
};

ExpressHandlebars.prototype._getFile = function (filePath, options) {
    filePath = path.resolve(filePath);

    var cache = ExpressHandlebars._fsCache,
        file  = options.cache && cache[filePath];

    if (file) {
        return file;
    }

    // Optimistically cache file promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    file = cache[filePath] = new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', function (err, file) {
            if (err) {
                reject(err);
            } else {
                resolve(file);
            }
        });
    });

    return file.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressHandlebars.prototype._getPartialName = function (filePath, namespace) {
    var extRegex = new RegExp(this.extname + '$'),
        name     = filePath.replace(extRegex, ''),
        version  = this.handlebarsVersion;

    if (namespace) {
        name = namespace + '/' + name;
    }

    // Fixes a Handlebars bug in versions prior to 1.0.rc.2 which caused
    // partials with "/"s in their name to not be found.
    // https://github.com/wycats/handlebars.js/pull/389
    if (version && !semver.satisfies(version, '>=1.0.0-rc.2')) {
        name = name.replace('/', '.');
    }

    return name;
};

ExpressHandlebars.prototype._renderTemplate = function (template, context, options) {
    return template(context, options);
};

ExpressHandlebars.prototype._resolveLayoutPath = function (layoutPath) {
    if (!layoutPath) {
        return null;
    }

    if (!path.extname(layoutPath)) {
        layoutPath += this.extname;
    }

    if (layoutPath.charAt(0) !== '/') {
        layoutPath = path.join(this.layoutsDir, layoutPath);
    }

    return layoutPath;
};
<commit_msg>Tweak impl of namespaced partials support<commit_after>'use strict';

var Promise = global.Promise || require('promise');

var glob       = require('glob'),
    Handlebars = require('handlebars'),
    fs         = require('graceful-fs'),
    path       = require('path'),
    semver     = require('semver'),
    utils      = require('./utils');

module.exports = ExpressHandlebars;

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

function ExpressHandlebars(config) {
    config || (config = {});

    this.handlebars  = config.handlebars  || this.handlebars;
    this.extname     = config.extname     || this.extname;
    this.layoutsDir  = config.layoutsDir  || this.layoutsDir;
    this.partialsDir = config.partialsDir || this.partialsDir;

    this.handlebarsVersion =
            ExpressHandlebars.getHandlebarsSemver(this.handlebars);

    if (this.extname.charAt(0) !== '.') {
        this.extname = '.' + this.extname;
    }

    this.defaultLayout = config.defaultLayout;
    this.helpers       = config.helpers;

    this.compiled    = {};
    this.precompiled = {};

    this.engine = this.renderView.bind(this);
}

ExpressHandlebars._fsCache = {};

ExpressHandlebars.getHandlebarsSemver = function (handlebars) {
    var version = handlebars.VERSION || '';

    // Makes sure the Handlebars version is a valid semver.
    if (version && !semver.valid(version)) {
        version = version.replace(/(\d\.\d)\.(\D.*)/, '$1.0-$2');
    }

    return version;
};

ExpressHandlebars.prototype.handlebars  = Handlebars;
ExpressHandlebars.prototype.extname     = '.handlebars';
ExpressHandlebars.prototype.layoutsDir  = 'views/layouts/';
ExpressHandlebars.prototype.partialsDir = 'views/partials/';

ExpressHandlebars.prototype.compileTemplate = function (template, options) {
    options || (options = {});

    var compiler = options.precompiled ? 'precompile' : 'compile',
        compile  = this.handlebars[compiler];

    return compile(template);
};

ExpressHandlebars.prototype.getTemplate = function (filePath, options) {
    filePath = path.resolve(filePath);
    options || (options = {});

    var precompiled = options.precompiled,
        cache       = precompiled ? this.precompiled : this.compiled,
        template    = options.cache && cache[filePath];

    if (template) {
        return template;
    }

    // Optimistically cache template promise to reduce file system I/O, but
    // remove from cache if there was a problem.
    template = cache[filePath] = this._getFile(filePath, options)
        .then(function (file) {
            return this.compileTemplate(file, options);
        }.bind(this));

    return template.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressHandlebars.prototype.getPartials = function (options) {
    options || (options = {});

    var partialsDirs = Array.isArray(this.partialsDir) ?
            this.partialsDir : [this.partialsDir];

    partialsDirs = partialsDirs.map(function (dir) {
        var namespace;

        // Support `partialsDir` collection with object entries that contain a
        // namespace.
        if (dir && typeof dir !== 'string') {
            dir       = dir.dir;
            namespace = dir.namespace;
        }

        return this.getTemplates(dir).then(function (templates) {
            return {
                templates: templates,
                namespace: namespace
            };
        });
    }, this);

    return Promise.all(partialsDirs).then(function (dirs) {
        var getPartialName = this._getPartialName.bind(this);

        return dirs.reduce(function (partials, dir) {
            var templates = dir.templates,
                namespace = dir.namespace,
                filePaths = Object.keys(templates);

            filePaths.forEach(function (filePath) {
                var partialName = getPartialName(filePath, namespace);
                partials[partialName] = templates[filePath];
            });

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

ExpressHandlebars.prototype.getTemplates = function (dirPath, options) {
    options || (options = {});

    return this._getDir(dirPath, options).then(function (filePaths) {
        var templates = filePaths.map(function (filePath) {
            return this.getTemplate(path.join(dirPath, filePath), options);
        }, this);

        return Promise.all(templates).then(function (templates) {
            return filePaths.reduce(function (map, filePath, i) {
                map[filePath] = templates[i];
                return map;
            }, {});
        });
    }.bind(this));
};

ExpressHandlebars.prototype.render = function (filePath, context, options) {
    options || (options = {});

    // Force `precompiled` to `false` since we're rendering to HTML.
    if (options.precompiled) {
        options = utils.extend({}, options, {precompiled: false});
    }

    return Promise.all([
        this.getTemplate(filePath, options),
        options.partials || this.getPartials(options)
    ]).then(function (templates) {
        var template = templates[0],
            partials = templates[1],
            data     = options.data;

        var helpers = options.helpers ||
                utils.extend({}, this.handlebars.helpers, this.helpers);

        return this._renderTemplate(template, context, {
            data    : data,
            helpers : helpers,
            partials: partials
        });
    }.bind(this));
};

ExpressHandlebars.prototype.renderView = function (viewPath, options, callback) {
    var context = options,
        data    = options.data;

    var helpers = utils.extend({},
            this.handlebars.helpers, this.helpers, options.helpers);

    // Pluck-out ExpressHandlebars-specific options.
    options = {
        cache      : options.cache,
        layout     : 'layout' in options ? options.layout : this.defaultLayout,
        precompiled: false
    };

    // Extend `options` with Handlebars-specific rendering options.
    utils.extend(options, {
        data    : data,
        helpers : helpers,
        partials: this.getPartials(options)
    });

    this.render(viewPath, context, options)
        .then(function (body) {
            var layoutPath = this._resolveLayoutPath(options.layout);

            if (layoutPath) {
                context = utils.extend({}, context, {body: body});
                return this.render(layoutPath, context, options);
            }
        }.bind(this))
        .then(utils.passValue(callback))
        .catch(utils.passError(callback));
};

ExpressHandlebars.prototype._getDir = function (dirPath, options) {
    dirPath = path.resolve(dirPath);

    var cache = ExpressHandlebars._fsCache,
        dir   = options.cache && cache[dirPath];

    if (dir) {
        return dir.then(function (dir) {
            return dir.concat();
        });
    }

    var pattern = '**/*' + this.extname;

    // Optimistically cache dir promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    dir = cache[dirPath] = new Promise(function (resolve, reject) {
        glob(pattern, {cwd: dirPath}, function (err, dir) {
            if (err) {
                reject(err);
            } else {
                resolve(dir);
            }
        });
    });

    return dir.then(function (dir) {
        return dir.concat();
    }).catch(function (err) {
        delete cache[dirPath];
        throw err;
    });
};

ExpressHandlebars.prototype._getFile = function (filePath, options) {
    filePath = path.resolve(filePath);

    var cache = ExpressHandlebars._fsCache,
        file  = options.cache && cache[filePath];

    if (file) {
        return file;
    }

    // Optimistically cache file promise to reduce file system I/O, but remove
    // from cache if there was a problem.
    file = cache[filePath] = new Promise(function (resolve, reject) {
        fs.readFile(filePath, 'utf8', function (err, file) {
            if (err) {
                reject(err);
            } else {
                resolve(file);
            }
        });
    });

    return file.catch(function (err) {
        delete cache[filePath];
        throw err;
    });
};

ExpressHandlebars.prototype._getPartialName = function (filePath, namespace) {
    var extRegex = new RegExp(this.extname + '$'),
        name     = filePath.replace(extRegex, ''),
        version  = this.handlebarsVersion;

    if (namespace) {
        name = namespace + '/' + name;
    }

    // Fixes a Handlebars bug in versions prior to 1.0.rc.2 which caused
    // partials with "/"s in their name to not be found.
    // https://github.com/wycats/handlebars.js/pull/389
    if (version && !semver.satisfies(version, '>=1.0.0-rc.2')) {
        name = name.replace('/', '.');
    }

    return name;
};

ExpressHandlebars.prototype._renderTemplate = function (template, context, options) {
    return template(context, options);
};

ExpressHandlebars.prototype._resolveLayoutPath = function (layoutPath) {
    if (!layoutPath) {
        return null;
    }

    if (!path.extname(layoutPath)) {
        layoutPath += this.extname;
    }

    if (layoutPath.charAt(0) !== '/') {
        layoutPath = path.join(this.layoutsDir, layoutPath);
    }

    return layoutPath;
};
<|endoftext|>


<commit_before>(function() {
    'use strict';
    /**
     * Game Class
     *
     * @class
     * @name O.Game
     * @extends O.Class
     *
     * @constructor
     * @param options config settings of the game class
     * @param dependencies instances of other classes
     *
     * @exports Game as O.Game
     */
    var Game = O.Class.create('O.Game', function Game(options, dependencies) {

        this.dependencies = dependencies;
        this.options = O.Utils.extend({}, this.options, options);
        this.config = O.Config;

        this.init();
    });

    Game.prototype.init = function () {

        //Select Canvas
        this.canvas = document.getElementById("canvas");
        this.canvas.focus();

        this.context = (this.config.engine === "2d") ? this.canvas.getContext('2d') : this.canvas.getContext("experimental-webgl", {antialias: true}) || this.canvas.getContext("webgl");
        this.width = this.canvas.width = window.innerWidth;
        this.height = this.canvas.height = window.innerHeight;

        O.Logger.log(this.config.engine+" Engine Loaded");

        //add instances to the injector
        O.Injector.register('canvas', this.canvas);
        O.Injector.register('context', this.context);

        //Select FPS div
        this.fpsContainer = document.getElementById("fps");

        //Initialize timer
        this.startTime = Date.now();
        this.prevTime = this.startTime;

        this.ms = 0;
        this.msMin = Infinity;
        this.msMax = 0;

        this.fpsValue = 0;
        this.fpsMin = Infinity;
        this.fpsMax = 0;

        this.framesFps = 0;

        //List of Scenes
        this.sceneList = [];
        this.currentScene = 0;

        //Initialize game loop
        this.raf();

        O.Logger.log("Engine initialized v"+this.config.version);
    }

    Game.prototype.changeScene = function(sceneID){
    	this.currentScene = sceneID;
    	O.Logger.log("Current Scene is: "+sceneID);
    }

    /**
     * Adds Scene to current game instance
     * @param scene
     * @returns {scene}
     */
    Game.prototype.addScene = function(scene) {
        O.Logger.log("Add Scene - "+ scene.options.sceneName);
        this.sceneList.push(scene);
        return scene;
    }

    Game.prototype.raf = function () {

        //loop over update and draw functions
        this.timerBegin();
            this.update();
            this.draw();
        this.timerEnd();

        // call this.raf on every frame
        window.requestAnimationFrame(this.raf.bind(this));
    }

    Game.prototype.fps = function () {
        return this.fpsValue;
    }

    Game.prototype.timerBegin = function () {
        this.startTime = Date.now();
    }

    Game.prototype.timerEnd = function () {
        var time = Date.now();
        this.framesFps++;

        if ( time > this.prevTime + 1000) {
            this.fpsValue = Math.round((this.framesFps * 1000) / (time - this.prevTime));
            this.fpsMin = Math.min(this.fpsMin, this.fpsValue);
            this.fpsMax = Math.max(this.fpsMax, this.fpsValue);
            this.fpsContainer.innerHTML = this.fpsValue + ' FPS (' + this.fpsMin + '-' + this.fpsMax + ')';
            this.prevTime = time;
            this.framesFps = 0;
        }

        return time;
    }

    Game.prototype.update = function () {

        if( this.sceneList.length > 0){
            this.sceneList.forEach(function(item, i){
            	if(this.currentScene === i){
            		item.update();
            	}
            });
        }
    }

    Game.prototype.draw = function () {

        if( this.sceneList.length > 0){
            this.sceneList.forEach(function(item, i){
            	if(this.currentScene === i){
                	item.draw();
                }
            });
        }
    }

})();<commit_msg>fixed for current Scene selector<commit_after>(function() {
    'use strict';
    /**
     * Game Class
     *
     * @class
     * @name O.Game
     * @extends O.Class
     *
     * @constructor
     * @param options config settings of the game class
     * @param dependencies instances of other classes
     *
     * @exports Game as O.Game
     */
    var Game = O.Class.create('O.Game', function Game(options, dependencies) {

        this.dependencies = dependencies;
        this.options = O.Utils.extend({}, this.options, options);
        this.config = O.Config;

        this.init();
    });

    Game.prototype.init = function () {

        //Select Canvas
        this.canvas = document.getElementById("canvas");
        this.canvas.focus();

        this.context = (this.config.engine === "2d") ? this.canvas.getContext('2d') : this.canvas.getContext("experimental-webgl", {antialias: true}) || this.canvas.getContext("webgl");
        this.width = this.canvas.width = window.innerWidth;
        this.height = this.canvas.height = window.innerHeight;

        O.Logger.log(this.config.engine+" Engine Loaded");

        //add instances to the injector
        O.Injector.register('canvas', this.canvas);
        O.Injector.register('context', this.context);

        //Select FPS div
        this.fpsContainer = document.getElementById("fps");

        //Initialize timer
        this.startTime = Date.now();
        this.prevTime = this.startTime;

        this.ms = 0;
        this.msMin = Infinity;
        this.msMax = 0;

        this.fpsValue = 0;
        this.fpsMin = Infinity;
        this.fpsMax = 0;

        this.framesFps = 0;

        //List of Scenes
        this.sceneList = [];
        this.currentScene = 0;

        //Initialize game loop
        this.raf();

        O.Logger.log("Engine initialized v"+this.config.version);
    }

    Game.prototype.changeScene = function(sceneID){
    	this.currentScene = sceneID;
    	O.Logger.log("Current Scene is: "+sceneID);
    }

    /**
     * Adds Scene to current game instance
     * @param scene
     * @returns {scene}
     */
    Game.prototype.addScene = function(scene) {
        O.Logger.log("Add Scene - "+ scene.options.sceneName);
        this.sceneList.push(scene);
        return scene;
    }

    Game.prototype.raf = function () {

        //loop over update and draw functions
        this.timerBegin();
            this.update();
            this.draw();
        this.timerEnd();

        // call this.raf on every frame
        window.requestAnimationFrame(this.raf.bind(this));
    }

    Game.prototype.fps = function () {
        return this.fpsValue;
    }

    Game.prototype.timerBegin = function () {
        this.startTime = Date.now();
    }

    Game.prototype.timerEnd = function () {
        var time = Date.now();
        this.framesFps++;

        if ( time > this.prevTime + 1000) {
            this.fpsValue = Math.round((this.framesFps * 1000) / (time - this.prevTime));
            this.fpsMin = Math.min(this.fpsMin, this.fpsValue);
            this.fpsMax = Math.max(this.fpsMax, this.fpsValue);
            this.fpsContainer.innerHTML = this.fpsValue + ' FPS (' + this.fpsMin + '-' + this.fpsMax + ')';
            this.prevTime = time;
            this.framesFps = 0;
        }

        return time;
    }

    Game.prototype.update = function () {
        var _this = this;

        if( this.sceneList.length > 0){
            this.sceneList.forEach(function(item, i){
            	if(_this.currentScene === i){
            		item.update();
            	}
            });
        }
    }

    Game.prototype.draw = function () {
        var _this = this;
        if( this.sceneList.length > 0){
            this.sceneList.forEach(function(item, i){

            	if(_this.currentScene === i){
                	item.draw();
                }
            });
        }
    }

})();<|endoftext|>


<commit_before>// Copyright 2019-2021, University of Colorado Boulder

/**
 * Base view for all "show a single molecule in the center" screens
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Vector3 from '../../dot/js/Vector3.js';
import asyncLoader from '../../phet-core/js/asyncLoader.js';
import openPopup from '../../phet-core/js/openPopup.js';
import PhetFont from '../../scenery-phet/js/PhetFont.js';
import sceneryPhetStrings from '../../scenery-phet/js/sceneryPhetStrings.js';
import HBox from '../../scenery/js/nodes/HBox.js';
import Text from '../../scenery/js/nodes/Text.js';
import Utils from '../../scenery/js/util/Utils.js';
import FontAwesomeNode from '../../sun/js/FontAwesomeNode.js';
import mobius from './mobius.js';

const webglWarningBodyString = sceneryPhetStrings.webglWarning.body;

// {THREE.TextureLoader|null} - "singleton" for the texture loader
let textureLoader = null;

const ThreeUtils = {
  /**
   * Converts a Vector3 to a THREE.Vector3
   * @public
   *
   * @param {Vector3} vector
   * @returns {THREE.Vector3}
   */
  vectorToThree( vector ) {
    return new THREE.Vector3( vector.x, vector.y, vector.z );
  },

  /**
   * Converts a THREE.Vector3 to a Vector3
   * @public
   *
   * @param {THREE.Vector3} vector
   * @returns {Vector3}
   */
  threeToVector( vector ) {
    return new Vector3( vector.x, vector.y, vector.z );
  },

  /**
   * Converts a Color to a THREE.Color
   * @public
   *
   * @param {Color} color
   * @returns {THREE.Color}
   */
  colorToThree( color ) {
    return new THREE.Color( color.toNumber() );
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the camera.
   * @public
   *
   * @param {Bounds2} bounds2 - x,y
   * @param {number} z
   * @returns {Array.<number>}
   */
  frontVertices( bounds2, z ) {
    return [
      bounds2.minX, bounds2.maxY, z,
      bounds2.minX, bounds2.minY, z,
      bounds2.maxX, bounds2.maxY, z,
      bounds2.minX, bounds2.minY, z,
      bounds2.maxX, bounds2.minY, z,
      bounds2.maxX, bounds2.maxY, z
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed up.
   * @public
   *
   * @param {Bounds2} bounds2 - x,z
   * @param {number} y
   * @returns {Array.<number>}
   */
  topVertices( bounds2, y ) {
    return [
      bounds2.minX, y, bounds2.maxY,
      bounds2.maxX, y, bounds2.maxY,
      bounds2.minX, y, bounds2.minY,
      bounds2.minX, y, bounds2.minY,
      bounds2.maxX, y, bounds2.maxY,
      bounds2.maxX, y, bounds2.minY
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the right.
   * @public
   *
   * @param {Bounds2} bounds2 - z,y
   * @param {number} x
   * @returns {Array.<number>}
   */
  rightVertices( bounds2, x ) {
    return [
      x, bounds2.minY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the left.
   * @public
   *
   * @param {Bounds2} bounds2 - z,y
   * @param {number} x
   * @returns {Array.<number>}
   */
  leftVertices( bounds2, x ) {
    return [
      x, bounds2.minY, bounds2.maxX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.maxY, bounds2.minX
    ];
  },

  /**
   * Returns a THREE.TextureLoader instance (using a singleton so we don't create more than we need).
   * @public
   *
   * @returns {THREE.TextureLoader}
   */
  get textureLoader() {
    if ( !textureLoader ) {
      textureLoader = new THREE.TextureLoader();
    }
    return textureLoader;
  },

  /**
   * Returns a THREE.Texture for a given HTMLImageElement.
   * @public
   *
   * @param {HTMLImageElement} image
   * @param {boolean} [waitForLoad]
   * @returns {THREE.Texture}
   */
  imageToTexture( image, waitForLoad ) {
    if ( waitForLoad ) {
      return ThreeUtils.textureLoader.load( image.src, asyncLoader.createLock() );
    }
    else {
      return ThreeUtils.textureLoader.load( image.src );
    }
  },

  /**
   * Checks if webgl is enabled by the browser.
   * @public
   *
   * @returns {boolean}
   */
  isWebGLEnabled() {
    return phet.chipper.queryParameters.webgl && Utils.isWebGLSupported;
  },

  /**
   * Shows a warning with a link to more information about PhET simulation webgl compatibility.
   * @public
   *
   * @param {ScreenView} screenView
   */
  showWebGLWarning( screenView ) {
    const warningNode = new HBox( {
      children: [
        new FontAwesomeNode( 'warning_sign', {
          fill: '#E87600', // "safety orange", according to Wikipedia
          scale: 0.8
        } ),
        new Text( webglWarningBodyString, {
          font: new PhetFont( 16 ),
          fill: '#000',
          maxWidth: 600
        } )
      ],
      spacing: 12,
      align: 'center',
      cursor: 'pointer',
      center: screenView.layoutBounds.center
    } );
    screenView.addChild( warningNode );

    warningNode.mouseArea = warningNode.touchArea = warningNode.localBounds;

    warningNode.addInputListener( {
      up: function() {
        openPopup( `http://phet.colorado.edu/webgl-disabled-page?simLocale=${phet.joist.sim.locale}` );
      }
    } );
  }
};

mobius.register( 'ThreeUtils', ThreeUtils );
export default ThreeUtils;<commit_msg>FA5 conversion, see https://github.com/phetsims/sherpa/issues/83<commit_after>// Copyright 2019-2021, University of Colorado Boulder

/**
 * Base view for all "show a single molecule in the center" screens
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Vector3 from '../../dot/js/Vector3.js';
import asyncLoader from '../../phet-core/js/asyncLoader.js';
import openPopup from '../../phet-core/js/openPopup.js';
import PhetFont from '../../scenery-phet/js/PhetFont.js';
import sceneryPhetStrings from '../../scenery-phet/js/sceneryPhetStrings.js';
import HBox from '../../scenery/js/nodes/HBox.js';
import Path from '../../scenery/js/nodes/Path.js';
import Text from '../../scenery/js/nodes/Text.js';
import Utils from '../../scenery/js/util/Utils.js';
import exclamationTriangleSolidShape from '../../sherpa/js/fontawesome-5/exclamationTriangleSolidShape.js';
import mobius from './mobius.js';

const webglWarningBodyString = sceneryPhetStrings.webglWarning.body;

// {THREE.TextureLoader|null} - "singleton" for the texture loader
let textureLoader = null;

const ThreeUtils = {
  /**
   * Converts a Vector3 to a THREE.Vector3
   * @public
   *
   * @param {Vector3} vector
   * @returns {THREE.Vector3}
   */
  vectorToThree( vector ) {
    return new THREE.Vector3( vector.x, vector.y, vector.z );
  },

  /**
   * Converts a THREE.Vector3 to a Vector3
   * @public
   *
   * @param {THREE.Vector3} vector
   * @returns {Vector3}
   */
  threeToVector( vector ) {
    return new Vector3( vector.x, vector.y, vector.z );
  },

  /**
   * Converts a Color to a THREE.Color
   * @public
   *
   * @param {Color} color
   * @returns {THREE.Color}
   */
  colorToThree( color ) {
    return new THREE.Color( color.toNumber() );
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the camera.
   * @public
   *
   * @param {Bounds2} bounds2 - x,y
   * @param {number} z
   * @returns {Array.<number>}
   */
  frontVertices( bounds2, z ) {
    return [
      bounds2.minX, bounds2.maxY, z,
      bounds2.minX, bounds2.minY, z,
      bounds2.maxX, bounds2.maxY, z,
      bounds2.minX, bounds2.minY, z,
      bounds2.maxX, bounds2.minY, z,
      bounds2.maxX, bounds2.maxY, z
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed up.
   * @public
   *
   * @param {Bounds2} bounds2 - x,z
   * @param {number} y
   * @returns {Array.<number>}
   */
  topVertices( bounds2, y ) {
    return [
      bounds2.minX, y, bounds2.maxY,
      bounds2.maxX, y, bounds2.maxY,
      bounds2.minX, y, bounds2.minY,
      bounds2.minX, y, bounds2.minY,
      bounds2.maxX, y, bounds2.maxY,
      bounds2.maxX, y, bounds2.minY
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the right.
   * @public
   *
   * @param {Bounds2} bounds2 - z,y
   * @param {number} x
   * @returns {Array.<number>}
   */
  rightVertices( bounds2, x ) {
    return [
      x, bounds2.minY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX
    ];
  },

  /**
   * Returns an array of [ x, y, z, ... ] vertices for a quad pointed towards the left.
   * @public
   *
   * @param {Bounds2} bounds2 - z,y
   * @param {number} x
   * @returns {Array.<number>}
   */
  leftVertices( bounds2, x ) {
    return [
      x, bounds2.minY, bounds2.maxX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.minY, bounds2.minX,
      x, bounds2.maxY, bounds2.maxX,
      x, bounds2.maxY, bounds2.minX
    ];
  },

  /**
   * Returns a THREE.TextureLoader instance (using a singleton so we don't create more than we need).
   * @public
   *
   * @returns {THREE.TextureLoader}
   */
  get textureLoader() {
    if ( !textureLoader ) {
      textureLoader = new THREE.TextureLoader();
    }
    return textureLoader;
  },

  /**
   * Returns a THREE.Texture for a given HTMLImageElement.
   * @public
   *
   * @param {HTMLImageElement} image
   * @param {boolean} [waitForLoad]
   * @returns {THREE.Texture}
   */
  imageToTexture( image, waitForLoad ) {
    if ( waitForLoad ) {
      return ThreeUtils.textureLoader.load( image.src, asyncLoader.createLock() );
    }
    else {
      return ThreeUtils.textureLoader.load( image.src );
    }
  },

  /**
   * Checks if webgl is enabled by the browser.
   * @public
   *
   * @returns {boolean}
   */
  isWebGLEnabled() {
    return phet.chipper.queryParameters.webgl && Utils.isWebGLSupported;
  },

  /**
   * Shows a warning with a link to more information about PhET simulation webgl compatibility.
   * @public
   *
   * @param {ScreenView} screenView
   */
  showWebGLWarning( screenView ) {
    const warningNode = new HBox( {
      children: [
        new Path( exclamationTriangleSolidShape, {
          fill: '#E87600', // "safety orange", according to Wikipedia
          scale: 0.06
        } ),
        new Text( webglWarningBodyString, {
          font: new PhetFont( 16 ),
          fill: '#000',
          maxWidth: 600
        } )
      ],
      spacing: 12,
      align: 'center',
      cursor: 'pointer',
      center: screenView.layoutBounds.center
    } );
    screenView.addChild( warningNode );

    warningNode.mouseArea = warningNode.touchArea = warningNode.localBounds;

    warningNode.addInputListener( {
      up: function() {
        openPopup( `http://phet.colorado.edu/webgl-disabled-page?simLocale=${phet.joist.sim.locale}` );
      }
    } );
  }
};

mobius.register( 'ThreeUtils', ThreeUtils );
export default ThreeUtils;<|endoftext|>