<commit_before>import {createEidsArray} from 'modules/userId/eids.js';
import {expect} from 'chai';

//  Note: In unit tets cases for bidders, call the createEidsArray function over userId object that is used for calling fetchBids
//      this way the request will stay consistent and unit test cases will not need lots of changes.

describe('eids array generation for known sub-modules', function() {
  it('pubCommonId', function() {
    const userId = {
      pubcid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'pubcid.org',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('unifiedId: ext generation', function() {
    const userId = {
      tdid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'adserver.org',
      uids: [{id: 'some-random-id-value', atype: 1, ext: { rtiPartner: 'TDID' }}]
    });
  });

  describe('id5Id', function() {
    it('does not include an ext if not provided', function() {
      const userId = {
        id5id: {
          uid: 'some-random-id-value'
        }
      };
      const newEids = createEidsArray(userId);
      expect(newEids.length).to.equal(1);
      expect(newEids[0]).to.deep.equal({
        source: 'id5-sync.com',
        uids: [{ id: 'some-random-id-value', atype: 1 }]
      });
    });

    it('includes ext if provided', function() {
      const userId = {
        id5id: {
          uid: 'some-random-id-value',
          ext: {
            linkType: 0
          }
        }
      };
      const newEids = createEidsArray(userId);
      expect(newEids.length).to.equal(1);
      expect(newEids[0]).to.deep.equal({
        source: 'id5-sync.com',
        uids: [{
          id: 'some-random-id-value',
          atype: 1,
          ext: {
            linkType: 0
          }
        }]
      });
    });
  });

  it('parrableId', function() {
    const userId = {
      parrableId: {
        eid: 'some-random-id-value'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'parrable.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('merkleId', function() {
    const userId = {
      merkleId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'merkleinc.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('identityLink', function() {
    const userId = {
      idl_env: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveramp.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('liveIntentId; getValue call and ext', function() {
    const userId = {
      lipb: {
        lipbid: 'some-random-id-value',
        segments: ['s1', 's2']
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveintent.com',
      uids: [{id: 'some-random-id-value', atype: 3}],
      ext: {segments: ['s1', 's2']}
    });
  });

  it('liveIntentId; getValue call and NO ext', function() {
    const userId = {
      lipb: {
        lipbid: 'some-random-id-value'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveintent.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('britepoolId', function() {
    const userId = {
      britepoolid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'britepool.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('lotamePanoramaId', function () {
    const userId = {
      lotamePanoramaId: 'some-random-id-value',
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'crwdcntrl.net',
      uids: [{ id: 'some-random-id-value', atype: 1 }],
    });
  });

  it('criteo', function() {
    const userId = {
      criteoId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'criteo.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('tapadId', function() {
    const userId = {
      tapadId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'tapad.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('NetId', function() {
    const userId = {
      netId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'netid.de',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });
  it('Sharedid', function() {
    const userId = {
      sharedid: {
        id: 'test_sharedId',
        third: 'test_sharedId'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'sharedid.org',
      uids: [{
        id: 'test_sharedId',
        atype: 1,
        ext: {
          third: 'test_sharedId'
        }
      }]
    });
  });
  it('Sharedid: Not Synched', function() {
    const userId = {
      sharedid: {
        id: 'test_sharedId'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'sharedid.org',
      uids: [{
        id: 'test_sharedId',
        atype: 1
      }]
    });
  });

  it('zeotapIdPlus', function() {
    const userId = {
      IDP: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'zeotap.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });

  it('haloId', function() {
    const userId = {
      haloId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'audigent.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });

  it('quantcastId', function() {
    const userId = {
      quantcastId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'quantcast.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });
  it('pubProvidedId', function() {
    const userId = {
      pubProvidedId: [{
        source: 'example.com',
        uids: [{
          id: 'value read from cookie or local storage',
          ext: {
            stype: 'ppuid'
          }
        }]
      }, {
        source: 'id-partner.com',
        uids: [{
          id: 'value read from cookie or local storage'
        }]
      }]
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(2);
    expect(newEids[0]).to.deep.equal({
      source: 'example.com',
      uids: [{
        id: 'value read from cookie or local storage',
        ext: {
          stype: 'ppuid'
        }
      }]
    });
    expect(newEids[1]).to.deep.equal({
      source: 'id-partner.com',
      uids: [{
        id: 'value read from cookie or local storage'
      }]
    });
  });
});
describe('Negative case', function() {
  it('eids array generation for UN-known sub-module', function() {
    // UnknownCommonId
    const userId = {
      unknowncid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
  });

  it('eids array generation for known sub-module with non-string value', function() {
    // pubCommonId
    let userId = {
      pubcid: undefined
    };
    let newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = 123;
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = [];
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = {};
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = null;
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
  });
});
<commit_msg>Update eids_spec.js<commit_after>import {createEidsArray} from 'modules/userId/eids.js';
import {expect} from 'chai';

//  Note: In unit tets cases for bidders, call the createEidsArray function over userId object that is used for calling fetchBids
//      this way the request will stay consistent and unit test cases will not need lots of changes.

describe('eids array generation for known sub-modules', function() {
  it('pubCommonId', function() {
    const userId = {
      pubcid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'pubcid.org',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('unifiedId: ext generation', function() {
    const userId = {
      tdid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'adserver.org',
      uids: [{id: 'some-random-id-value', atype: 1, ext: { rtiPartner: 'TDID' }}]
    });
  });

  describe('id5Id', function() {
    it('does not include an ext if not provided', function() {
      const userId = {
        id5id: {
          uid: 'some-random-id-value'
        }
      };
      const newEids = createEidsArray(userId);
      expect(newEids.length).to.equal(1);
      expect(newEids[0]).to.deep.equal({
        source: 'id5-sync.com',
        uids: [{ id: 'some-random-id-value', atype: 1 }]
      });
    });

    it('includes ext if provided', function() {
      const userId = {
        id5id: {
          uid: 'some-random-id-value',
          ext: {
            linkType: 0
          }
        }
      };
      const newEids = createEidsArray(userId);
      expect(newEids.length).to.equal(1);
      expect(newEids[0]).to.deep.equal({
        source: 'id5-sync.com',
        uids: [{
          id: 'some-random-id-value',
          atype: 1,
          ext: {
            linkType: 0
          }
        }]
      });
    });
  });

  it('parrableId', function() {
    const userId = {
      parrableId: {
        eid: 'some-random-id-value'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'parrable.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('merkleId', function() {
    const userId = {
      merkleId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'merkleinc.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('identityLink', function() {
    const userId = {
      idl_env: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveramp.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('liveIntentId; getValue call and ext', function() {
    const userId = {
      lipb: {
        lipbid: 'some-random-id-value',
        segments: ['s1', 's2']
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveintent.com',
      uids: [{id: 'some-random-id-value', atype: 3}],
      ext: {segments: ['s1', 's2']}
    });
  });

  it('liveIntentId; getValue call and NO ext', function() {
    const userId = {
      lipb: {
        lipbid: 'some-random-id-value'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'liveintent.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('britepoolId', function() {
    const userId = {
      britepoolid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'britepool.com',
      uids: [{id: 'some-random-id-value', atype: 3}]
    });
  });

  it('lotamePanoramaId', function () {
    const userId = {
      lotamePanoramaId: 'some-random-id-value',
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'crwdcntrl.net',
      uids: [{ id: 'some-random-id-value', atype: 1 }],
    });
  });

  it('criteo', function() {
    const userId = {
      criteoId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'criteo.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('tapadId', function() {
    const userId = {
      tapadId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'tapad.com',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });

  it('NetId', function() {
    const userId = {
      netId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'netid.de',
      uids: [{id: 'some-random-id-value', atype: 1}]
    });
  });
  it('Sharedid', function() {
    const userId = {
      sharedid: {
        id: 'test_sharedId',
        third: 'test_sharedId'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'sharedid.org',
      uids: [{
        id: 'test_sharedId',
        atype: 1,
        ext: {
          third: 'test_sharedId'
        }
      }]
    });
  });
  it('Sharedid: Not Synched', function() {
    const userId = {
      sharedid: {
        id: 'test_sharedId'
      }
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'sharedid.org',
      uids: [{
        id: 'test_sharedId',
        atype: 1
      }]
    });
  });

  it('zeotapIdPlus', function() {
    const userId = {
      IDP: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'zeotap.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });

  it('haloId', function() {
    const userId = {
      haloId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'audigent.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });

  it('quantcastId', function() {
    const userId = {
      quantcastId: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(1);
    expect(newEids[0]).to.deep.equal({
      source: 'quantcast.com',
      uids: [{
        id: 'some-random-id-value',
        atype: 1
      }]
    });
  });
  it('pubProvidedId', function() {
    const userId = {
      pubProvidedId: [{
        source: 'example.com',
        uids: [{
          id: 'value read from cookie or local storage',
          ext: {
            stype: 'ppuid'
          }
        }]
      }, {
        source: 'id-partner.com',
        uids: [{
          id: 'value read from cookie or local storage'
        }]
      }]
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(2);
    expect(newEids[0]).to.deep.equal({
      source: 'example.com',
      uids: [{
        id: 'value read from cookie or local storage',
        ext: {
          stype: 'ppuid'
        }
      }]
    });
    expect(newEids[1]).to.deep.equal({
      source: 'id-partner.com',
      uids: [{
        id: 'value read from cookie or local storage'
      }]
    });
  });
});
describe('Negative case', function() {
  it('eids array generation for UN-known sub-module', function() {
    // UnknownCommonId
    const userId = {
      unknowncid: 'some-random-id-value'
    };
    const newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
  });

  it('eids array generation for known sub-module with non-string value', function() {
    // pubCommonId
    let userId = {
      pubcid: undefined
    };
    let newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = 123;
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = [];
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = {};
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
    userId.pubcid = null;
    newEids = createEidsArray(userId);
    expect(newEids.length).to.equal(0);
  });
});
<|endoftext|>


<commit_before>/* globals $, chrome */
var usedOn = {};
var openedOn = {};
var accessed = {};
var activeTabId;
var timeout;
var activeInterval = 2500;

function _debug() {
    // console.log.apply(console, arguments);
}

function _getMax() {
    return parseInt(localStorage.max || 20);
}

function _getAlgo() {
    return localStorage.algo || 'used';
}

function _markActive(tabId) {
    _debug('marked active', tabId);
    usedOn[tabId] = new Date().getTime();
    accessed[tabId] += 1;
}

function _handleTabActivated(data) {
    var tabId = data.tabId;
    activeTabId = tabId;
    _debug('activated', tabId);

    clearTimeout(timeout);

    // after 3 seconds mark this tab as active
    // this is so if you are quickly switching tabs
    // they are not considered active
    timeout = setTimeout(function() {
        _markActive(tabId);
    }, activeInterval);
}

function _handleTabRemoved(tabId) {
    clearTimeout(timeout);

    _debug('removed', tabId);
    delete usedOn[tabId];
    delete openedOn[tabId];
    delete accessed[tabId];
}

function _removeTab(tabId) {
    _debug('_removeTab', tabId);
    if (tabId) {
        chrome.tabs.remove(tabId, function() {});
        // _handleTabRemoved(tabId);
    }
}

function _getLowestIn(data, tabs) {
    var lowest;
    var lowestIndex;
    var tabId;
    var value;
    for (var i = 0; i < tabs.length; i++) {
        tabId = tabs[i].id;

        // never close the currently active tab
        if (tabId === activeTabId) {
            continue;
        }

        // if you have never been to this tab then skip it
        if (!data.hasOwnProperty(tabId)) {
            continue;
        }

        value = data[tabId] || 0;

        if (lowest === undefined) {
            lowest = value;
        }

        if (value <= lowest) {
            lowestIndex = i;
            lowest = value;
        }
    }

    return lowestIndex;
}

function _removeLeastAccessed(tabs) {
    var removeTabIndex = _getLowestIn(accessed, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeOldest(tabs) {
    var removeTabIndex = _getLowestIn(openedOn, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeLeastRecentlyUsed(tabs) {
    var removeTabIndex = _getLowestIn(usedOn, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeTabs(tabs) {
    var length = tabs.length;
    _debug('there are', tabs.length, 'tabs open');
    _debug('max is', _getMax());
    while (length >= _getMax()) {
        _debug('removing a tab with length', length);
        switch (_getAlgo()) {
            case 'oldest':
                tabs = _removeOldest(tabs);
                break;
            case 'accessed':
                tabs = _removeLeastAccessed(tabs);
                break;
            default:
                tabs = _removeLeastRecentlyUsed(tabs);
                break;
        }
        length -= 1;
    }
}

function _handleTabAdded(data) {
    var tabId = data.id || data;

    _debug('added', tabId);

    // find tab to remove
    chrome.tabs.query({currentWindow: true}, function(tabs) {
        tabs = tabs.filter(function(tab) {
            return !tab.pinned && tab.id != tabId;
        });

        _debug('Total tabs', tabs.length);
        _debug('Max tabs', _getMax());

        if (tabs.length >= _getMax()) {

            // If this is set to block just immediately remove this tab before
            // even adding info about it
            if (_getAlgo() === 'block') {
                _removeTab(tabId);
                return;
            }

            _removeTabs(tabs);
        }

        openedOn[tabId] = new Date().getTime();
        accessed[tabId] = 0;
    });
}

function _bindEvents() {
    chrome.tabs.onActivated.addListener(_handleTabActivated);
    chrome.tabs.onCreated.addListener(_handleTabAdded);
    chrome.tabs.onAttached.addListener(_handleTabAdded);
    chrome.tabs.onRemoved.addListener(_handleTabRemoved);
    chrome.tabs.onDetached.addListener(_handleTabRemoved);
}

function _init() {

    // on startup loop through all existing tabs and set them to active
    // this is only needed so that if you first install the extension
    // or bring a bunch of tabs in on startup it will work
    //
    // setting the time to their tab id ensures they will be closed in
    // the order they were opened in and there is no way to figure
    // out what time a tab was opened from chrome apis
    chrome.tabs.query({}, function(tabs) {
        for (var i = 0; i < tabs.length; i++) {
            if (!usedOn.hasOwnProperty(tabs[i].id)) {
                openedOn[tabs[i].id] = tabs[i].id;
                usedOn[tabs[i].id] = tabs[i].id;
                accessed[tabs[i].id] = 0;
            }
        }

        _bindEvents();
    });
}

$.ready(_init);
<commit_msg>Handle when tabs get replaced with new ids<commit_after>/* globals $, chrome */
var usedOn = {};
var openedOn = {};
var accessed = {};
var activeTabId;
var timeout;
var activeInterval = 2500;

function _debug() {
    // console.log.apply(console, arguments);
}

function _getMax() {
    return parseInt(localStorage.max || 20);
}

function _getAlgo() {
    return localStorage.algo || 'used';
}

function _markActive(tabId) {
    _debug('marked active', tabId);
    usedOn[tabId] = new Date().getTime();
    accessed[tabId] += 1;
}

function _handleTabActivated(data) {
    var tabId = data.tabId;
    activeTabId = tabId;
    _debug('activated', tabId);

    clearTimeout(timeout);

    // after 3 seconds mark this tab as active
    // this is so if you are quickly switching tabs
    // they are not considered active
    timeout = setTimeout(function() {
        _markActive(tabId);
    }, activeInterval);
}

function _handleTabRemoved(tabId) {
    clearTimeout(timeout);

    _debug('removed', tabId);
    delete usedOn[tabId];
    delete openedOn[tabId];
    delete accessed[tabId];
}

function _handleTabReplaced(newTabId, oldTabId) {
    if (usedOn[oldTabId]) {
        usedOn[newTabId] = usedOn[oldTabId];
    }

    if (openedOn[oldTabId]) {
        openedOn[newTabId] = openedOn[oldTabId];
    }

    if (accessed[oldTabId]) {
        accessed[newTabId] = accessed[oldTabId];
    }

    delete usedOn[oldTabId];
    delete openedOn[oldTabId];
    delete accessed[oldTabId];
}

function _removeTab(tabId) {
    _debug('_removeTab', tabId);
    if (tabId) {
        chrome.tabs.remove(tabId, function() {});
        // _handleTabRemoved(tabId);
    }
}

function _getLowestIn(data, tabs) {
    var lowest;
    var lowestIndex;
    var tabId;
    var value;
    for (var i = 0; i < tabs.length; i++) {
        tabId = tabs[i].id;

        // never close the currently active tab
        if (tabId === activeTabId) {
            continue;
        }

        // if you have never been to this tab then skip it
        if (!data.hasOwnProperty(tabId)) {
            continue;
        }

        value = data[tabId] || 0;

        if (lowest === undefined) {
            lowest = value;
        }

        if (value <= lowest) {
            lowestIndex = i;
            lowest = value;
        }
    }

    return lowestIndex;
}

function _removeLeastAccessed(tabs) {
    var removeTabIndex = _getLowestIn(accessed, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeOldest(tabs) {
    var removeTabIndex = _getLowestIn(openedOn, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeLeastRecentlyUsed(tabs) {
    var removeTabIndex = _getLowestIn(usedOn, tabs);
    if (removeTabIndex >= 0) {
        _removeTab(tabs[removeTabIndex].id);
        tabs.splice(removeTabIndex, 1);
    }
    return tabs;
}

function _removeTabs(tabs) {
    var length = tabs.length;
    _debug('there are', tabs.length, 'tabs open');
    _debug('max is', _getMax());
    while (length >= _getMax()) {
        _debug('removing a tab with length', length);
        switch (_getAlgo()) {
            case 'oldest':
                tabs = _removeOldest(tabs);
                break;
            case 'accessed':
                tabs = _removeLeastAccessed(tabs);
                break;
            default:
                tabs = _removeLeastRecentlyUsed(tabs);
                break;
        }
        length -= 1;
    }
}

function _handleTabAdded(data) {
    var tabId = data.id || data;

    _debug('added', tabId);

    // find tab to remove
    chrome.tabs.query({currentWindow: true}, function(tabs) {
        tabs = tabs.filter(function(tab) {
            return !tab.pinned && tab.id != tabId;
        });

        _debug('Total tabs', tabs.length);
        _debug('Max tabs', _getMax());

        if (tabs.length >= _getMax()) {

            // If this is set to block just immediately remove this tab before
            // even adding info about it
            if (_getAlgo() === 'block') {
                _removeTab(tabId);
                return;
            }

            _removeTabs(tabs);
        }

        openedOn[tabId] = new Date().getTime();
        accessed[tabId] = 0;
    });
}

function _bindEvents() {
    chrome.tabs.onActivated.addListener(_handleTabActivated);
    chrome.tabs.onCreated.addListener(_handleTabAdded);
    chrome.tabs.onAttached.addListener(_handleTabAdded);
    chrome.tabs.onRemoved.addListener(_handleTabRemoved);
    chrome.tabs.onDetached.addListener(_handleTabRemoved);
    chrome.tabs.onReplaced.addListener(_handleTabReplaced);
}

function _init() {

    // on startup loop through all existing tabs and set them to active
    // this is only needed so that if you first install the extension
    // or bring a bunch of tabs in on startup it will work
    //
    // setting the time to their tab id ensures they will be closed in
    // the order they were opened in and there is no way to figure
    // out what time a tab was opened from chrome apis
    chrome.tabs.query({}, function(tabs) {
        for (var i = 0; i < tabs.length; i++) {
            if (!usedOn.hasOwnProperty(tabs[i].id)) {
                openedOn[tabs[i].id] = tabs[i].id;
                usedOn[tabs[i].id] = tabs[i].id;
                accessed[tabs[i].id] = 0;
            }
        }

        _bindEvents();
    });
}

$.ready(_init);
<|endoftext|>


<commit_before>// EMAIL NEWSLETTER SIGNUPS

const changeEmailContainerBackground = elem => {
	// If background image is so complex that email signup form needs a dark background instead of a transparent background...
	let visible = false
	for (let i = 0; i < elem.children.length; i++) {
		// Element with class `email container background` has conditional visibility in Webflow, so Webflow tags a new class called `w-condition-invisible` if Collection determines it invisible
		visible = elem.children[i].className.includes('w-condition-invisible')
		if (visible) {
			break
		}
	}
	const color = !visible
		? '#fff'
		: '#333'
	const mode = !visible
		? 'add'
		: 'remove'
	for (let i = 0; i < elem.children.length; i++) {
		// Elements are contained inside `email-form` class...
		if (elem.children[i].className === 'email-form') {
      console.log(elem.children[i])
			for (let j = 0; j < elem.children[i].length; j++) {
				const element = elem.children[i][j]
				console.log(element)
				// ...then make the email signup box title white instead of charcoal.
				if (element.className.includes('title small') || element.className.includes('button transparent')) {
					element.style.color = color
				}
				else if (element.className.includes('input') || element.className.includes('textarea')) {
					if (mode === 'add') {
						element.classList.add('white-placeholder')
					}
					else {
						element.classList.remove('white-placeholder')
					}
				}
			}
		}
	}

	}

// 1. Define all input fields
const formNames = [
	'hero',
]
const formFields = [
	'first_name',
	'last_name',
	'email',
	'verification'
]

// 2. Only once all fields are entered, enable button.
const verifyEmailSignup = e => {
	formNames.forEach(inputCategory => {
		// If change was made in a certain email signup category...
		if (e.target.id.includes(inputCategory)) {
			// ...check to see if every field has been filled out correctly...
			const complete = formFields.every(inputField => {
				const field = document.getElementById(inputCategory + '_' + inputField)
				if (inputField === 'first_name' || inputField === 'last_name') {
					// Prevent ALL CAPS
					field.value = field.value.toLowerCase()
					// Title case
					field.value = field.value.charAt(0).toUpperCase() + field.value.slice(1)
					// No empty spaces
					if (field.value.includes(' ')) {
						field.value = field.value.replace(' ', '')
					}
				}
				const emailRegex = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/igm
				// return true if all fields have been filled out
				return (
					((inputField === 'first_name' || inputField === 'last_name') && field.value.length > 1)
					|| (inputField === 'email' && field.value.length > 4 && emailRegex.test(field.value))
				)
			})
			const showAlert = formFields.every(inputField => {
				const field = document.getElementById(inputCategory + '_' + inputField)
				return (
					// Only show alert once every field has been touched...
					field.value.length > 0
				)
			})
			// ...and if so, change button class to active, and submit form.
			const buttonField = document.getElementById(inputCategory + '_button')
			const alertField = document.getElementById(inputCategory + '_alert')
			// Only show alert if all fields have been filled out somewhat, but not yet validated
			if (showAlert) {
				alertField.classList.remove('hidden')
			}
			else {
				alertField.classList.add('hidden')
			}
			if (complete && !showAlert) {
				buttonField.classList.remove('disabled')
				const formField = document.getElementById(inputCategory + '_form')
				formField.action = 'https://app.getresponse.com/add_subscriber.html'
				buttonField.addEventListener('click', () => formField.submit())
			}
			// ...otherwise, disable form.
			else {
				buttonField.classList.add('disabled')
				const formField = document.getElementById(inputCategory + '_form')
				formField.action = ''
				buttonField.removeEventListener('click', () => null)
			}
		}
	})
}

// 3. Assign enable button function to all relevant fields, and trigger submit if user presses enter
formNames.forEach(inputCategory => {
	formFields.forEach(inputField => {
		const field = document.getElementById(inputCategory + '_' + inputField)
		if (field) {
			field.oninput = verifyEmailSignup
			field.addEventListener('keypress', e => {
				const key = e.which || e.keyCode
				// If `enter` key is pressed, attempt to submit form
				if (key === 13) {
					const buttonField = document.getElementById(inputCategory + '_button')
					buttonField.click()
				}
			})
		}
	})
})<commit_msg>Reg form modal display.<commit_after>// EMAIL NEWSLETTER SIGNUPS

const changeEmailContainerBackground = elem => {
	// If background image is so complex that email signup form needs a dark background instead of a transparent background...
	let visible = false
	for (let i = 0; i < elem.children.length; i++) {
		// Element with class `email container background` has conditional visibility in Webflow, so Webflow tags a new class called `w-condition-invisible` if Collection determines it invisible
		visible = elem.children[i].className.includes('w-condition-invisible')
		if (visible) {
			break
		}
	}
	const color = !visible
		? '#fff'
		: '#333'
	const mode = !visible
		? 'add'
		: 'remove'
	for (let i = 0; i < elem.children.length; i++) {
		// Elements are contained inside `email-form` class...
		if (elem.children[i].className === 'email-form') {
      console.log(elem.children[i].querySelectorAll('title small'))
			for (let j = 0; j < elem.children[i].length; j++) {
				const element = elem.children[i][j]
				console.log(element)
				// ...then make the email signup box title white instead of charcoal.
				if (element.className.includes('title small') || element.className.includes('button transparent')) {
					element.style.color = color
				}
				else if (element.className.includes('input') || element.className.includes('textarea')) {
					if (mode === 'add') {
						element.classList.add('white-placeholder')
					}
					else {
						element.classList.remove('white-placeholder')
					}
				}
			}
		}
	}

	}

// 1. Define all input fields
const formNames = [
	'hero',
]
const formFields = [
	'first_name',
	'last_name',
	'email',
	'verification'
]

// 2. Only once all fields are entered, enable button.
const verifyEmailSignup = e => {
	formNames.forEach(inputCategory => {
		// If change was made in a certain email signup category...
		if (e.target.id.includes(inputCategory)) {
			// ...check to see if every field has been filled out correctly...
			const complete = formFields.every(inputField => {
				const field = document.getElementById(inputCategory + '_' + inputField)
				if (inputField === 'first_name' || inputField === 'last_name') {
					// Prevent ALL CAPS
					field.value = field.value.toLowerCase()
					// Title case
					field.value = field.value.charAt(0).toUpperCase() + field.value.slice(1)
					// No empty spaces
					if (field.value.includes(' ')) {
						field.value = field.value.replace(' ', '')
					}
				}
				const emailRegex = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/igm
				// return true if all fields have been filled out
				return (
					((inputField === 'first_name' || inputField === 'last_name') && field.value.length > 1)
					|| (inputField === 'email' && field.value.length > 4 && emailRegex.test(field.value))
				)
			})
			const showAlert = formFields.every(inputField => {
				const field = document.getElementById(inputCategory + '_' + inputField)
				return (
					// Only show alert once every field has been touched...
					field.value.length > 0
				)
			})
			// ...and if so, change button class to active, and submit form.
			const buttonField = document.getElementById(inputCategory + '_button')
			const alertField = document.getElementById(inputCategory + '_alert')
			// Only show alert if all fields have been filled out somewhat, but not yet validated
			if (showAlert) {
				alertField.classList.remove('hidden')
			}
			else {
				alertField.classList.add('hidden')
			}
			if (complete && !showAlert) {
				buttonField.classList.remove('disabled')
				const formField = document.getElementById(inputCategory + '_form')
				formField.action = 'https://app.getresponse.com/add_subscriber.html'
				buttonField.addEventListener('click', () => formField.submit())
			}
			// ...otherwise, disable form.
			else {
				buttonField.classList.add('disabled')
				const formField = document.getElementById(inputCategory + '_form')
				formField.action = ''
				buttonField.removeEventListener('click', () => null)
			}
		}
	})
}

// 3. Assign enable button function to all relevant fields, and trigger submit if user presses enter
formNames.forEach(inputCategory => {
	formFields.forEach(inputField => {
		const field = document.getElementById(inputCategory + '_' + inputField)
		if (field) {
			field.oninput = verifyEmailSignup
			field.addEventListener('keypress', e => {
				const key = e.which || e.keyCode
				// If `enter` key is pressed, attempt to submit form
				if (key === 13) {
					const buttonField = document.getElementById(inputCategory + '_button')
					buttonField.click()
				}
			})
		}
	})
})<|endoftext|>


<commit_before>'use strict';
let event = require('./event');
let container = require('./container');
let recorder = require('./recorder');
let getParamNames = require('./utils').getParamNames;

/**
 * Wraps test function, injects support objects from container,
 * starts promise chain with recorder, performs before/after hooks
 * through event system.
 */
module.exports.test = (test) => {
  let testFn = test.fn;
  if (!testFn) {
    return test;
  }

  test.steps = [];
  test.fn = function (done) {
    recorder.errHandler(function (err) {
      recorder.session.start('teardown');
      event.emit(event.test.failed, test, err);
      recorder.add(() => done(err));
    });

    try {
      event.emit(event.test.started, test);
      let res = testFn.apply(test, getInjectedArguments(testFn));
      if (isGenerator(testFn)) {
        try {
          res.next(); // running test
        } catch (err) {
          done(err);
          return test;
        }
        recorder.catch(); // catching possible errors in promises
        let resumeTest = function () {
          recorder.add('create new promises queue for generator',function (data) {
            recorder.session.start('generator'); // creating a new promise chain
            try {
              let resume = res.next(data);
              if (resume.done) {
                recorder.add('finish generator with no error', () => done()); // finish him
              } else {
                resumeTest();
              }
            } catch (err) {
              recorder.throw(err); // catch error in test and rethrow into promise
            }
            recorder.catch(); // handle all errors in promise chain
          });
        };
        resumeTest();
      }
    } catch (err) {
      recorder.throw(err);
    } finally {
      if (!isGenerator(testFn)) {
        recorder.add('finish test', () => done());
        recorder.catch();
      }
    }
  };
  return test;
};

/**
 * Injects arguments to function from controller
 */
module.exports.injected = function (fn) {
  return function() {
    try {
      fn.apply(this, getInjectedArguments(fn));
    } catch (err) {
      recorder.throw(err);
    }
    return recorder.promise();
  };
};

/**
 * Starts promise chain, so helpers could enqueue their hooks
 */
module.exports.setup = function () {
  recorder.start();
  event.emit(event.test.before);
};

module.exports.teardown = function () {
  event.emit(event.test.after);
};

module.exports.suiteSetup = function () {
  recorder.start();
  event.emit(event.suite.before);
};

module.exports.suiteTeardown = function () {
  recorder.start();
  event.emit(event.suite.after);
};

function isGenerator(fn) {
  return fn.constructor.name === 'GeneratorFunction';
}

function getInjectedArguments(fn) {
  let testArguments = [];
  let params = getParamNames(fn) || [];
  let objects = container.support();
  for (var key in params) {
    let obj = params[key];
    if (!objects[obj]) {
      throw new Error(`Object of type ${obj} is not defined in container`);
    }
    testArguments.push(container.support(obj));
  }
  return testArguments;
}
<commit_msg>fixed exit code for Before hook. Closes #279 (#289)<commit_after>'use strict';
let event = require('./event');
let container = require('./container');
let recorder = require('./recorder');
let getParamNames = require('./utils').getParamNames;

/**
 * Wraps test function, injects support objects from container,
 * starts promise chain with recorder, performs before/after hooks
 * through event system.
 */
module.exports.test = (test) => {
  let testFn = test.fn;
  if (!testFn) {
    return test;
  }

  test.steps = [];
  test.fn = function (done) {
    recorder.errHandler(function (err) {
      recorder.session.start('teardown');
      event.emit(event.test.failed, test, err);
      recorder.add(() => done(err));
    });

    try {
      event.emit(event.test.started, test);
      let res = testFn.apply(test, getInjectedArguments(testFn));
      if (isGenerator(testFn)) {
        try {
          res.next(); // running test
        } catch (err) {
          done(err);
          return test;
        }
        recorder.catch(); // catching possible errors in promises
        let resumeTest = function () {
          recorder.add('create new promises queue for generator',function (data) {
            recorder.session.start('generator'); // creating a new promise chain
            try {
              let resume = res.next(data);
              if (resume.done) {
                recorder.add('finish generator with no error', () => done()); // finish him
              } else {
                resumeTest();
              }
            } catch (err) {
              recorder.throw(err); // catch error in test and rethrow into promise
            }
            recorder.catch(); // handle all errors in promise chain
          });
        };
        resumeTest();
      }
    } catch (err) {
      recorder.throw(err);
    } finally {
      if (!isGenerator(testFn)) {
        recorder.add('finish test', () => done());
        recorder.catch();
      }
    }
  };
  return test;
};

/**
 * Injects arguments to function from controller
 */
module.exports.injected = function (fn) {
  return function() {
    try {
      fn.apply(this, getInjectedArguments(fn));
    } catch (err) {
      recorder.throw(err);
    }
    recorder.catch((err) => {
      event.emit(event.test.failed, {}, err); // emit
      throw err;
    });
    return recorder.promise();
  };
};

/**
 * Starts promise chain, so helpers could enqueue their hooks
 */
module.exports.setup = function () {
  recorder.start();
  event.emit(event.test.before);
};

module.exports.teardown = function () {
  event.emit(event.test.after);
};

module.exports.suiteSetup = function () {
  recorder.start();
  event.emit(event.suite.before);
};

module.exports.suiteTeardown = function () {
  recorder.start();
  event.emit(event.suite.after);
};

function isGenerator(fn) {
  return fn.constructor.name === 'GeneratorFunction';
}

function getInjectedArguments(fn) {
  let testArguments = [];
  let params = getParamNames(fn) || [];
  let objects = container.support();
  for (var key in params) {
    let obj = params[key];
    if (!objects[obj]) {
      throw new Error(`Object of type ${obj} is not defined in container`);
    }
    testArguments.push(container.support(obj));
  }
  return testArguments;
}
<|endoftext|>


<commit_before>var socketClusterServer = require('./server');
var EventEmitter = require('events').EventEmitter;
var crypto = require('crypto');
var domain = require('domain');
var http = require('http');
var https = require('https');
var fs = require('fs');
var base64id = require('base64id');
var async = require('async');
var AuthEngine = require('./auth').AuthEngine;

var SCWorker = function (options) {
  var self = this;

  this.EVENT_ERROR = 'error';
  this.EVENT_NOTICE = 'notice';
  this.EVENT_EXIT = 'exit';
  this.EVENT_READY = 'ready';
  this.EVENT_CONNECTION = 'connection';

  this.MIDDLEWARE_START = 'start';

  this._errorDomain = domain.create();
  this._errorDomain.on('error', function () {
    self.errorHandler.apply(self, arguments);
    if (self.options.rebootWorkerOnCrash) {
      self.emit(self.EVENT_EXIT);
    }
  });

  this.start = this._errorDomain.bind(this._start);
  this._errorDomain.run(function () {
    self._init(options);
  });
};

SCWorker.prototype = Object.create(EventEmitter.prototype);

SCWorker.prototype.setAuthEngine = function (authEngine) {
  this.auth = authEngine;

  this.httpServer.auth = this.auth;
  this.scServer.setAuthEngine(this.auth);
};

SCWorker.prototype._init = function (options) {
  var self = this;

  this.options = {};

  for (var i in options) {
    if (options.hasOwnProperty(i)) {
      this.options[i] = options[i];
    }
  }

  this.id = this.options.id;
  this.isLeader = this.id == 0;

  this._middleware = {};
  this._middleware[this.MIDDLEWARE_START] = [];

  if (this.options.downgradeToUser && process.setuid) {
    try {
      process.setuid(this.options.downgradeToUser);
    } catch (err) {
      this._errorDomain.emit('error', new Error('Could not downgrade to user "' + this.options.downgradeToUser +
        '" - Either this user does not exist or the current process does not have the permission' +
        ' to switch to it.'));
    }
  }

  this._clusterEngine = require(this.options.clusterEngine);

  this._paths = options.paths;

  this._httpRequestCount = 0;
  this._wsRequestCount = 0;
  this._httpRPM = 0;
  this._wsRPM = 0;

  this._ioClusterClient = new this._clusterEngine.IOClusterClient({
    brokers: this.options.brokers,
    secretKey: this.options.secretKey,
    socketChannelLimit: this.options.socketChannelLimit
  });

  this._errorDomain.add(this._ioClusterClient);
  this._ioClusterClient.on('notice', function () {
    self.noticeHandler.apply(self, arguments);
  });
  this.global = this._ioClusterClient.global();

  if (this.options.httpServerModule) {
    var httpServerFactory = require(this.options.httpServerModule);
    this.httpServer = httpServerFactory.createServer(this.options.protocolOptions);
  } else {
    if (this.options.protocol == 'https') {
      this.httpServer = https.createServer(this.options.protocolOptions);
    } else {
      this.httpServer = http.createServer();
    }
  }
  this.httpServer.on('request', this._httpRequestHandler.bind(this));
  this.httpServer.on('upgrade', this._httpRequestHandler.bind(this));

  this.httpServer.global = this.global;

  this._errorDomain.add(this.httpServer);

  var secure = this.options.protocol == 'https' ? 1 : 0;

  this.scServer = socketClusterServer.attach(this.httpServer, {
    ioClusterClient: this._ioClusterClient,
    allowClientPublish: this.options.allowClientPublish,
    ackTimeout: this.options.ackTimeout,
    pingTimeout: this.options.pingTimeout,
    pingInterval: this.options.pingInterval,
    origins: this.options.origins,
    appName: this.options.appName,
    defaultAuthTokenExpiryInMinutes: this.options.defaultAuthTokenExpiryInMinutes,
    path: this.options.path,
    authKey: this.options.authKey,
    middlewareEmitNotices: this.options.middlewareEmitNotices
  });

  // Default authentication engine
  this.setAuthEngine(new AuthEngine());

  this.scServer.on('_connection', function (socket) {
    // The connection event counts as a WS request
    self._wsRequestCount++;
    socket.on('message', function () {
      self._wsRequestCount++;
    });
    self.emit(self.EVENT_CONNECTION, socket);
  });

  this.scServer.on('notice', function () {
    self.noticeHandler.apply(self, arguments);
  });

  this._socketPath = this.scServer.getPath();
  this._socketPathRegex = new RegExp('^' + this._socketPath);

  this._errorDomain.add(this.scServer);

  this.scServer.on('ready', function () {
    self.emit(self.EVENT_READY);
  });
};

SCWorker.prototype.open = function () {
  this._startServer();
};

SCWorker.prototype.close = function (callback) {
  this.scServer.close();
  this.httpServer.close(callback);
};

// getSocketURL is deprecated
SCWorker.prototype.getSocketPath = SCWorker.prototype.getSocketURL = function () {
  return this._socketPath;
};

SCWorker.prototype.addMiddleware = function (type, middleware) {
  this._middleware[type].push(middleware);
};

SCWorker.prototype.removeMiddleware = function (type, middleware) {
  var middlewareFunctions = this._middleware[type];

  this._middleware[type] = middlewareFunctions.filter(function (fn) {
    return fn != middleware;
  });
};

SCWorker.prototype._startServer = function () {
  var self = this;

  var options = this.options;

  var start = function () {
    if (options.tcpSynBacklog != null) {
      self.httpServer.listen(options.sourcePort, options.host, options.tcpSynBacklog);
    } else if (options.host != null) {
      self.httpServer.listen(options.sourcePort, options.host);
    } else {
      self.httpServer.listen(options.sourcePort);
    }
  };

  var startMiddleware = this._middleware[this.MIDDLEWARE_START];
  if (startMiddleware.length) {
    async.applyEachSeries(startMiddleware, function (err) {
      if (err) {
        throw err;
      } else {
        start();
      }
    });
  } else {
    start();
  }
};

SCWorker.prototype._start = function () {
  var self = this;

  this._httpRequestCount = 0;
  this._wsRequestCount = 0;
  this._httpRPM = 0;
  this._wsRPM = 0;

  if (this._statusInterval != null) {
    clearInterval(this._statusInterval);
  }
  this._statusInterval = setInterval(this._calculateStatus.bind(this), this.options.workerStatusInterval);

  // Run the initController to initialize the global context
  if(this._paths.appInitControllerPath != null) {
      this._initController = require(this._paths.appInitControllerPath);
      this._initController.run(this);
  }

  this._workerController = require(this._paths.appWorkerControllerPath);
  this._workerController.run(this);

  this._startServer();
};

SCWorker.prototype._httpRequestHandler = function (req, res) {
  var self = this;

  this._httpRequestCount++;

  req.global = this.global;

  var forwardedFor = req.headers['x-forwarded-for'];

  if (forwardedFor) {
    var forwardedClientIP;
    if (forwardedFor.indexOf(',') > -1) {
      forwardedClientIP = forwardedFor.split(',')[0];
    } else {
      forwardedClientIP = forwardedFor;
    }
    req.remoteAddress = forwardedClientIP;
  } else {
    if (req.connection) {
      req.remoteAddress = req.connection.remoteAddress;
    } else if (req.socket) {
      req.remoteAddress = req.socket.remoteAddress;
    }
  }
};

SCWorker.prototype.getSCServer = function () {
  return this.scServer;
};

SCWorker.prototype.getHTTPServer = function () {
  return this.httpServer;
};

SCWorker.prototype._calculateStatus = function () {
  var perMinuteFactor = 60000 / this.options.workerStatusInterval;
  this._httpRPM = this._httpRequestCount * perMinuteFactor;
  this._wsRPM = this._wsRequestCount * perMinuteFactor;
  this._httpRequestCount = 0;
  this._wsRequestCount = 0;

  var memThreshold = this.options.killWorkerMemoryThreshold;

  if (memThreshold != null) {
    var memoryUsage = process.memoryUsage();
    if (memoryUsage.heapUsed > memThreshold) {
      var message = 'Worker killed itself because its memory ';
      message += 'usage of ' + memoryUsage.heapUsed + ' exceeded ';
      message += 'the killWorkerMemoryThreshold of ' + memThreshold;
      var notice = new Error(message);
      this.noticeHandler(notice);
      process.exit();
    }
  }
};

SCWorker.prototype.getStatus = function () {
  return {
    clientCount: this.scServer.clientsCount,
    httpRPM: this._httpRPM,
    wsRPM: this._wsRPM
  };
};

SCWorker.prototype.sendToMaster = function (data) {
  process.send({
    type: 'workerMessage',
    data: data,
    workerId: this.id
  });
};

SCWorker.prototype.handleMasterEvent = function () {
  this.emit.apply(this, arguments);
};

SCWorker.prototype.handleMasterMessage = function (message) {
  this.emit('masterMessage', message.data);
};

SCWorker.prototype.errorHandler = function (err) {
  this.emit(this.EVENT_ERROR, err);
};

SCWorker.prototype.noticeHandler = function (notice) {
  if (notice.stack != null) {
    notice = notice.stack;
  } else if (notice.message != null) {
    notice = notice.message;
  }
  this.emit(this.EVENT_NOTICE, notice);
};

module.exports = SCWorker;
<commit_msg>Added type to worker instance<commit_after>var socketClusterServer = require('./server');
var EventEmitter = require('events').EventEmitter;
var crypto = require('crypto');
var domain = require('domain');
var http = require('http');
var https = require('https');
var fs = require('fs');
var base64id = require('base64id');
var async = require('async');
var AuthEngine = require('./auth').AuthEngine;

var SCWorker = function (options) {
  var self = this;

  this.EVENT_ERROR = 'error';
  this.EVENT_NOTICE = 'notice';
  this.EVENT_EXIT = 'exit';
  this.EVENT_READY = 'ready';
  this.EVENT_CONNECTION = 'connection';

  this.MIDDLEWARE_START = 'start';

  this.type = 'worker';

  this._errorDomain = domain.create();
  this._errorDomain.on('error', function () {
    self.errorHandler.apply(self, arguments);
    if (self.options.rebootWorkerOnCrash) {
      self.emit(self.EVENT_EXIT);
    }
  });

  this.start = this._errorDomain.bind(this._start);
  this._errorDomain.run(function () {
    self._init(options);
  });
};

SCWorker.prototype = Object.create(EventEmitter.prototype);

SCWorker.prototype.setAuthEngine = function (authEngine) {
  this.auth = authEngine;

  this.httpServer.auth = this.auth;
  this.scServer.setAuthEngine(this.auth);
};

SCWorker.prototype._init = function (options) {
  var self = this;

  this.options = {};

  for (var i in options) {
    if (options.hasOwnProperty(i)) {
      this.options[i] = options[i];
    }
  }

  this.id = this.options.id;
  this.isLeader = this.id == 0;

  this._middleware = {};
  this._middleware[this.MIDDLEWARE_START] = [];

  if (this.options.downgradeToUser && process.setuid) {
    try {
      process.setuid(this.options.downgradeToUser);
    } catch (err) {
      this._errorDomain.emit('error', new Error('Could not downgrade to user "' + this.options.downgradeToUser +
        '" - Either this user does not exist or the current process does not have the permission' +
        ' to switch to it.'));
    }
  }

  this._clusterEngine = require(this.options.clusterEngine);

  this._paths = options.paths;

  this._httpRequestCount = 0;
  this._wsRequestCount = 0;
  this._httpRPM = 0;
  this._wsRPM = 0;

  this._ioClusterClient = new this._clusterEngine.IOClusterClient({
    brokers: this.options.brokers,
    secretKey: this.options.secretKey,
    socketChannelLimit: this.options.socketChannelLimit
  });

  this._errorDomain.add(this._ioClusterClient);
  this._ioClusterClient.on('notice', function () {
    self.noticeHandler.apply(self, arguments);
  });
  this.global = this._ioClusterClient.global();

  if (this.options.httpServerModule) {
    var httpServerFactory = require(this.options.httpServerModule);
    this.httpServer = httpServerFactory.createServer(this.options.protocolOptions);
  } else {
    if (this.options.protocol == 'https') {
      this.httpServer = https.createServer(this.options.protocolOptions);
    } else {
      this.httpServer = http.createServer();
    }
  }
  this.httpServer.on('request', this._httpRequestHandler.bind(this));
  this.httpServer.on('upgrade', this._httpRequestHandler.bind(this));

  this.httpServer.global = this.global;

  this._errorDomain.add(this.httpServer);

  var secure = this.options.protocol == 'https' ? 1 : 0;

  this.scServer = socketClusterServer.attach(this.httpServer, {
    ioClusterClient: this._ioClusterClient,
    allowClientPublish: this.options.allowClientPublish,
    ackTimeout: this.options.ackTimeout,
    pingTimeout: this.options.pingTimeout,
    pingInterval: this.options.pingInterval,
    origins: this.options.origins,
    appName: this.options.appName,
    defaultAuthTokenExpiryInMinutes: this.options.defaultAuthTokenExpiryInMinutes,
    path: this.options.path,
    authKey: this.options.authKey,
    middlewareEmitNotices: this.options.middlewareEmitNotices
  });

  // Default authentication engine
  this.setAuthEngine(new AuthEngine());

  this.scServer.on('_connection', function (socket) {
    // The connection event counts as a WS request
    self._wsRequestCount++;
    socket.on('message', function () {
      self._wsRequestCount++;
    });
    self.emit(self.EVENT_CONNECTION, socket);
  });

  this.scServer.on('notice', function () {
    self.noticeHandler.apply(self, arguments);
  });

  this._socketPath = this.scServer.getPath();
  this._socketPathRegex = new RegExp('^' + this._socketPath);

  this._errorDomain.add(this.scServer);

  this.scServer.on('ready', function () {
    self.emit(self.EVENT_READY);
  });
};

SCWorker.prototype.open = function () {
  this._startServer();
};

SCWorker.prototype.close = function (callback) {
  this.scServer.close();
  this.httpServer.close(callback);
};

// getSocketURL is deprecated
SCWorker.prototype.getSocketPath = SCWorker.prototype.getSocketURL = function () {
  return this._socketPath;
};

SCWorker.prototype.addMiddleware = function (type, middleware) {
  this._middleware[type].push(middleware);
};

SCWorker.prototype.removeMiddleware = function (type, middleware) {
  var middlewareFunctions = this._middleware[type];

  this._middleware[type] = middlewareFunctions.filter(function (fn) {
    return fn != middleware;
  });
};

SCWorker.prototype._startServer = function () {
  var self = this;

  var options = this.options;

  var start = function () {
    if (options.tcpSynBacklog != null) {
      self.httpServer.listen(options.sourcePort, options.host, options.tcpSynBacklog);
    } else if (options.host != null) {
      self.httpServer.listen(options.sourcePort, options.host);
    } else {
      self.httpServer.listen(options.sourcePort);
    }
  };

  var startMiddleware = this._middleware[this.MIDDLEWARE_START];
  if (startMiddleware.length) {
    async.applyEachSeries(startMiddleware, function (err) {
      if (err) {
        throw err;
      } else {
        start();
      }
    });
  } else {
    start();
  }
};

SCWorker.prototype._start = function () {
  var self = this;

  this._httpRequestCount = 0;
  this._wsRequestCount = 0;
  this._httpRPM = 0;
  this._wsRPM = 0;

  if (this._statusInterval != null) {
    clearInterval(this._statusInterval);
  }
  this._statusInterval = setInterval(this._calculateStatus.bind(this), this.options.workerStatusInterval);

  // Run the initController to initialize the global context
  if(this._paths.appInitControllerPath != null) {
      this._initController = require(this._paths.appInitControllerPath);
      this._initController.run(this);
  }

  this._workerController = require(this._paths.appWorkerControllerPath);
  this._workerController.run(this);

  this._startServer();
};

SCWorker.prototype._httpRequestHandler = function (req, res) {
  var self = this;

  this._httpRequestCount++;

  req.global = this.global;

  var forwardedFor = req.headers['x-forwarded-for'];

  if (forwardedFor) {
    var forwardedClientIP;
    if (forwardedFor.indexOf(',') > -1) {
      forwardedClientIP = forwardedFor.split(',')[0];
    } else {
      forwardedClientIP = forwardedFor;
    }
    req.remoteAddress = forwardedClientIP;
  } else {
    if (req.connection) {
      req.remoteAddress = req.connection.remoteAddress;
    } else if (req.socket) {
      req.remoteAddress = req.socket.remoteAddress;
    }
  }
};

SCWorker.prototype.getSCServer = function () {
  return this.scServer;
};

SCWorker.prototype.getHTTPServer = function () {
  return this.httpServer;
};

SCWorker.prototype._calculateStatus = function () {
  var perMinuteFactor = 60000 / this.options.workerStatusInterval;
  this._httpRPM = this._httpRequestCount * perMinuteFactor;
  this._wsRPM = this._wsRequestCount * perMinuteFactor;
  this._httpRequestCount = 0;
  this._wsRequestCount = 0;

  var memThreshold = this.options.killWorkerMemoryThreshold;

  if (memThreshold != null) {
    var memoryUsage = process.memoryUsage();
    if (memoryUsage.heapUsed > memThreshold) {
      var message = 'Worker killed itself because its memory ';
      message += 'usage of ' + memoryUsage.heapUsed + ' exceeded ';
      message += 'the killWorkerMemoryThreshold of ' + memThreshold;
      var notice = new Error(message);
      this.noticeHandler(notice);
      process.exit();
    }
  }
};

SCWorker.prototype.getStatus = function () {
  return {
    clientCount: this.scServer.clientsCount,
    httpRPM: this._httpRPM,
    wsRPM: this._wsRPM
  };
};

SCWorker.prototype.sendToMaster = function (data) {
  process.send({
    type: 'workerMessage',
    data: data,
    workerId: this.id
  });
};

SCWorker.prototype.handleMasterEvent = function () {
  this.emit.apply(this, arguments);
};

SCWorker.prototype.handleMasterMessage = function (message) {
  this.emit('masterMessage', message.data);
};

SCWorker.prototype.errorHandler = function (err) {
  this.emit(this.EVENT_ERROR, err);
};

SCWorker.prototype.noticeHandler = function (notice) {
  if (notice.stack != null) {
    notice = notice.stack;
  } else if (notice.message != null) {
    notice = notice.message;
  }
  this.emit(this.EVENT_NOTICE, notice);
};

module.exports = SCWorker;
<|endoftext|>


<commit_before>'use strict';

/* selector.js
 * Object to represent CSS selectors.
 */

const Property = require('./property');

module.exports = exports = Selector;

function Selector(sel, properties) {
  if (!(this instanceof Selector)) return new Selector(sel, properties);

  // Type checking
  if (typeof sel !== 'string')
    throw new TypeError('sel must be a string');
  if (Array.isArray(properties))
    properties.forEach((x) => {
      if (!(x instanceof Property))
        throw new TypeError('properties must only contain Property objects');
    });
  else if (typeof properties === 'undefined');
  else
    throw new TypeError('properties must be an array of Property objects');

  this.sel = sel;
  this.properties = Array.isArray(properties) ? properties : [];
}

Selector.prototype.add = function(prop){
  if (!(prop instanceof Property))
    throw new TypeError('prop must be a Property object');

  this.properties.push(prop);
};

Selector.prototype.set = function(index, property){
  if (typeof index !== 'number')
    throw new TypeError('index must be a number');
  if (!(property instanceof Property))
    throw new TypeError('property must be a Property object');

  this.properties[index] = property;
};

Selector.prototype.remove = function(index){
  this.properties.splice(index, 1);
};
<commit_msg>New start on Selector<commit_after>'use strict';

/* selector.js
 * Expresses CSS properties.
 */

const Property = require('./property');

module.exports = exports = Selector;

function Selector(){

}
<|endoftext|>


<commit_before>/**
 * The Services class initializes the Shell's API services.
 */

'use strict';

const _ = require('lodash'),
    express = require('express'),
    cors = require('cors'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    morgan = require('morgan'),
    helmet = require('helmet'),
    serverUtils = require('./server-utils'),
    {SocketIOLoader, Loader} = require('./api');

class Services {

    /**
     * @description Sets up HTTP and Socket APIs using routes, socket connections, and configuration functions defined by LabShare API packages
     * @param {Object} [options]
     * @param {Object} [options.security] - Options to pass to the helmet, cors, and express-session libraries
     * @param {Boolean} [options.loadServices] - Do not load APIs if false. Default: true
     * @param {String} [options.main] - A relative or absolute path to a directory containing a LabShare package. Default: process.cwd()
     * @param {String} [options.pattern] - The pattern used to match LabShare API modules
     * @param {Object} [options.logger] - Error logging provider. It must define an `error` function. Default: console
     * @param {Array} [options.directories] - A list of paths to LabShare packages that should be searched for API modules. Directories
     * that do not contain a package.json are ignored. Default: []
     * @param {Array} [options.ignore] - A list of LabShare package names that should be ignored by the API and Socket loaders. Default: []
     */
    constructor(options = {}) {
        let logger = _.get(global.LabShare, 'Logger', console);  // Default to the logger instance initialized by the LSC LabShare package

        this._app = express();
        this._initialized = false;
        this._servicesActive = false;
        this._isProduction = this._app.get('env') === 'production';
        this._options = _.defaultsDeep(options, _.defaultsDeep(_.get(global.LabShare, 'Config.services'), {
            logger,
            connections: [],
            loadServices: true,
            pattern: '{src/api,api}/*.js',
            main: process.cwd(),
            directories: [],
            morgan: {
                enable: true,
                format: this._isProduction ? 'dev' : 'combined',
                options: {
                    // Workaround to add fluentD integration with the morgan logging library
                    stream: _.get(this.logger, 'stream.write')
                }
            },
            security: {
                sessionOptions: {
                    secret: require('crypto').randomBytes(64).toString('hex'),
                    resave: false,
                    saveUninitialized: false,
                    name: 'sessionID',
                    cookie: {
                        httpOnly: true,
                        maxAge: 60 * 60 * 1000,      // 1 hour
                        secure: this._isProduction   // only allow SSL cookies in production by default
                    }
                },
                contentSecurityPolicy: false,
                hpkp: false,
                referrerPolicy: {
                    policy: 'no-referrer'
                },
                corsOptions: {
                    origin: '*',
                    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
                    preflightContinue: false
                }
            }
        }));

        this.server = serverUtils.createServer(this._app, this.logger);
        this._apiLoader = new Loader(this._app, this._options);
        this._socketLoader = new SocketIOLoader(this.server, this._options);
    }

    /**
     * @description Load the services and assign middleware but do not start up the server or establish
     * any socket connections yet
     * @api
     */
    initialize() {
        this._initialized = true;

        this._app.use(helmet(this._options.security));
        this._app.use(bodyParser.json());
        this._app.use(bodyParser.urlencoded({extended: true}));
        this._app.use(cors(this._options.security.corsOptions));

        if (this._options.morgan.enable) {
            this._app.use(morgan(this._options.morgan.format, this._options.morgan.options));
        }

        this._app.use(cookieParser());

        // See: https://github.com/expressjs/session#cookiesecure
        if (this._isProduction) {
            this._app.set('trust proxy', 1);  // trust first proxy
        }

        this._app.use(require('express-session')(this._options.security.sessionOptions));
        this._apiLoader.initialize();
    }

    /**
     * @description Allows additional modifications to be made to the Express instance and routes before the services are started up.
     * @param {Function} func - A configuration function that receives all the API routes and the express app as arguments
     * @api
     */
    config(func) {
        if (!this._initialized) {
            this.initialize();
        }

        if (this._servicesActive) {
            throw new Error('You cannot modify the LabShare API services after starting up the server!');
        }

        func({
            services: this._apiLoader.services,
            app: this._app,
            io: this.io()
        });
    }

    /**
     * @description Starts the server and sets up socket connections
     * @returns {Object} The Node.js HTTP or HTTPS server
     * @api
     */
    start() {
        if (!this._initialized) {
            this.initialize();
        }

        // Run all the package API 'config' functions
        this._apiLoader.setConfig({
            apiLoader: this._apiLoader,
            app: this._app
        });

        this._servicesActive = true;

        serverUtils.startServer(this.server, this._options.logger);

        // add API routes and socket connections unless configured not to
        if (this._options.loadServices) {
            this._apiLoader.setAPIs(_.get(global.LabShare, 'Config.services.ServicePath') || '/');

            this._socketLoader.connect();
            this._socketLoader.on('error', error => {
                this._options.logger.error(error);
            });
            this._socketLoader.on('status', message => {
                this._options.logger.info(message);
            });

            // TODO: perform this global assignment OUTSIDE of the Services class if possible

            _.set(global, 'LabShare.IO', this.io());
        } else {
            this._options.logger.warn('API services are disabled because Service\'s `options.loadServices` is missing or set to false!');
        }

        return this.server;
    }

    io() {
        return this._socketLoader.getIO();
    }
}

module.exports = Services;

// if executed as a standalone script...
if (!module.parent) {
    let services = new Services();
    services.start();
}
<commit_msg>syntax modification<commit_after>/**
 * The Services class initializes the Shell's API services.
 */

'use strict';

const _ = require('lodash'),
    express = require('express'),
    cors = require('cors'),
    cookieParser = require('cookie-parser'),
    bodyParser = require('body-parser'),
    morgan = require('morgan'),
    helmet = require('helmet'),
    serverUtils = require('./server-utils'),
    {SocketIOLoader, Loader} = require('./api');

class Services {

    /**
     * @description Sets up HTTP and Socket APIs using routes, socket connections, and configuration functions defined by LabShare API packages
     * @param {Object} [options]
     * @param {Object} [options.security] - Options to pass to the helmet, cors, and express-session libraries
     * @param {Boolean} [options.loadServices] - Do not load APIs if false. Default: true
     * @param {String} [options.main] - A relative or absolute path to a directory containing a LabShare package. Default: process.cwd()
     * @param {String} [options.pattern] - The pattern used to match LabShare API modules
     * @param {Object} [options.logger] - Error logging provider. It must define an `error` function. Default: console
     * @param {Array} [options.directories] - A list of paths to LabShare packages that should be searched for API modules. Directories
     * that do not contain a package.json are ignored. Default: []
     * @param {Array} [options.ignore] - A list of LabShare package names that should be ignored by the API and Socket loaders. Default: []
     */
    constructor(options = {}) {
        let logger = _.get(global.LabShare, 'Logger', console);  // Default to the logger instance initialized by the LSC LabShare package

        this._app = express();
        this._initialized = false;
        this._servicesActive = false;
        this._isProduction = this._app.get('env') === 'production';
        this._options = _.defaultsDeep(options, _.defaultsDeep(_.get(global.LabShare, 'Config.services'), {
            logger,
            connections: [],
            loadServices: true,
            pattern: '{src/api,api}/*.js',
            main: process.cwd(),
            directories: [],
            morgan: {
                enable: true,
                format: this._isProduction ? 'dev' : 'combined',
                options: {
                    // Workaround to add fluentD integration with the morgan logging library
                    stream: _.get(this.logger, 'stream.write')
                }
            },
            security: {
                sessionOptions: {
                    secret: require('crypto').randomBytes(64).toString('hex'),
                    resave: false,
                    saveUninitialized: false,
                    name: 'sessionID',
                    cookie: {
                        httpOnly: true,
                        maxAge: 60 * 60 * 1000,      // 1 hour
                        secure: this._isProduction   // only allow SSL cookies in production by default
                    }
                },
                contentSecurityPolicy: false,
                hpkp: false,
                referrerPolicy: {
                    policy: 'no-referrer'
                },
                corsOptions: {
                    origin: '*',
                    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
                    preflightContinue: false
                }
            }
        }));

        this.server = serverUtils.createServer(this._app, this._options.logger);
        this._apiLoader = new Loader(this._app, this._options);
        this._socketLoader = new SocketIOLoader(this.server, this._options);
    }

    /**
     * @description Load the services and assign middleware but do not start up the server or establish
     * any socket connections yet
     * @api
     */
    initialize() {
        this._initialized = true;

        this._app.use(helmet(this._options.security));
        this._app.use(bodyParser.json());
        this._app.use(bodyParser.urlencoded({extended: true}));
        this._app.use(cors(this._options.security.corsOptions));

        if (this._options.morgan.enable) {
            this._app.use(morgan(this._options.morgan.format, this._options.morgan.options));
        }

        this._app.use(cookieParser());

        // See: https://github.com/expressjs/session#cookiesecure
        if (this._isProduction) {
            this._app.set('trust proxy', 1);  // trust first proxy
        }

        this._app.use(require('express-session')(this._options.security.sessionOptions));
        this._apiLoader.initialize();
    }

    /**
     * @description Allows additional modifications to be made to the Express instance and routes before the services are started up.
     * @param {Function} func - A configuration function that receives all the API routes and the express app as arguments
     * @api
     */
    config(func) {
        if (!this._initialized) {
            this.initialize();
        }

        if (this._servicesActive) {
            throw new Error('You cannot modify the LabShare API services after starting up the server!');
        }

        func({
            services: this._apiLoader.services,
            app: this._app,
            io: this.io()
        });
    }

    /**
     * @description Starts the server and sets up socket connections
     * @returns {Object} The Node.js HTTP or HTTPS server
     * @api
     */
    start() {
        if (!this._initialized) {
            this.initialize();
        }

        // Run all the package API 'config' functions
        this._apiLoader.setConfig({
            apiLoader: this._apiLoader,
            app: this._app
        });

        this._servicesActive = true;

        serverUtils.startServer(this.server, this._options.logger);

        // add API routes and socket connections unless configured not to
        if (this._options.loadServices) {
            this._apiLoader.setAPIs(_.get(global.LabShare, 'Config.services.ServicePath') || '/');

            this._socketLoader.connect();
            this._socketLoader.on('error', error => {
                this._options.logger.error(error);
            });
            this._socketLoader.on('status', message => {
                this._options.logger.info(message);
            });

            // TODO: perform this global assignment OUTSIDE of the Services class if possible

            _.set(global, 'LabShare.IO', this.io());
        } else {
            this._options.logger.warn('API services are disabled because Service\'s `options.loadServices` is missing or set to false!');
        }

        return this.server;
    }

    io() {
        return this._socketLoader.getIO();
    }
}

module.exports = Services;

// if executed as a standalone script...
if (!module.parent) {
    let services = new Services();
    services.start();
}
<|endoftext|>


<commit_before>
/*!
 * simplexn
 * dimension-independent geometric kernel based on simplicial complex
 * Copyright (c) 2011 cvd-lab <cvd-lab@email.com> (https://github.com/cvd-lab/)
 * MIT License
 */

!(function (exports) {

  /**
   * Library namespace.
   */
  var simplexn = exports.simplexn = {};

  /**
   * Library version.
   */

  simplexn.version = '0.0.0';

}(this));<commit_msg>init pointset<commit_after>
/*!
 * simplexn
 * dimension-independent geometric kernel based on simplicial complex
 * Copyright (c) 2011 cvd-lab <cvd-lab@email.com> (https://github.com/cvd-lab/)
 * MIT License
 */

!(function (exports) {

  /**
   * Library namespace.
   */
  var simplexn = exports.simplexn = {};

  /**
   * Library version.
   */

  simplexn.version = '0.0.0';

  simplexn.PointSet = function (vertices, dim, precision) {
    this.vertices = new Float32Array(vertices);
    this.dim = dim;
    this.indices = new Float32Array(vertices.length);
    this.precision = precision || 10e-7;
  };

  /**
   * merge
   *
   * @param {Number} precision
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.merge = function (precision) {
    // body...

    return this;
  };

  /**
   * rotate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.rotate = function (dims, values) {
    // body...

    return this;
  };

  /**
   * scale
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.scale = function (dims, values) {
    // body...

    return this;
  };

  /**
   * translate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.translate = function (dims, values) {
    // body...

    return this;
  };

  /**
   * transform
   *
   * @param {Array|Float32Array} matrix
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.transform = function (matrix) {
    // body...

    return this;
  };

  /**
   * embed
   *
   * @param {Number} dim
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.embed = function (dim) {
    // body...

    return this;
  };

}(this));<|endoftext|>


<commit_before>
/*!
 * simplexn
 * dimension-independent geometric kernel based on simplicial complex
 * Copyright (c) 2011 cvd-lab <cvd-lab@email.com> (https://github.com/cvd-lab/)
 * MIT License
 */

!(function (exports) {

  /**
   * Library namespace.
   */
  var simplexn = exports.simplexn = {};

  /**
   * Library version.
   */

  simplexn.version = '0.0.0';

  simplexn.PointSet = function (vertices, dim, precision) {
    this.vertices = new Float32Array(vertices);
    this.dim = dim;
    this.indices = new Float32Array(vertices.length);
    this.precision = precision || 10e-7;
  };

  /**
   * merge
   *
   * @param {Number} precision
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.merge = function (precision) {
    // body...

    return this;
  };

  /**
   * rotate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.rotate = function (dims, values) {
    // body...

    return this;
  };

  /**
   * scale
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.scale = function (dims, values) {
    // body...

    return this;
  };

  /**
   * translate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.translate = function (dims, values) {
    var vertices = this.vertices
      , length = vertices.length
      , i
      , j
      ;

    for (i = 0; i < length; i += dim) {
      for (j = 0: j < dims; j += 1) {
        vertices[i+dims[j]] += values[j];
      }
    }
    return this;
  };

  /**
   * transform
   *
   * @param {Array|Float32Array} matrix
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.transform = function (matrix) {
    // body...

    return this;
  };

  /**
   * embed
   *
   * @param {Number} dim
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.embed = function (dim) {
    // body...

    return this;
  };

}(this));<commit_msg>added method pointset scale<commit_after>
/*!
 * simplexn
 * dimension-independent geometric kernel based on simplicial complex
 * Copyright (c) 2011 cvd-lab <cvd-lab@email.com> (https://github.com/cvd-lab/)
 * MIT License
 */

!(function (exports) {

  /**
   * Library namespace.
   */
  var simplexn = exports.simplexn = {};

  /**
   * Library version.
   */

  simplexn.version = '0.0.0';

  simplexn.PointSet = function (vertices, dim, precision) {
    this.vertices = new Float32Array(vertices);
    this.dim = dim;
    this.indices = new Float32Array(vertices.length);
    this.precision = precision || 10e-7;
  };

  /**
   * merge
   *
   * @param {Number} precision
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.merge = function (precision) {
    // body...

    return this;
  };

  /**
   * rotate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.rotate = function (dims, values) {
    // body...

    return this;
  };

  /**
   * scale
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.scale = function (dims, values) {
    var vertices = this.vertices
      , length = vertices.length
      , i
      , j
      ;

    for (i = 0; i < length; i += dim) {
      for (j = 0: j < dims; j += 1) {
        vertices[i+dims[j]] *= values[j];
      }
    }
    return this;
  };

  /**
   * translate
   *
   * @param {Array|Uint32Array} dims
   * @param {Array|Float32Array} values
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.translate = function (dims, values) {
    var vertices = this.vertices
      , length = vertices.length
      , i
      , j
      ;

    for (i = 0; i < length; i += dim) {
      for (j = 0: j < dims; j += 1) {
        vertices[i+dims[j]] += values[j];
      }
    }
    return this;
  };

  /**
   * transform
   *
   * @param {Array|Float32Array} matrix
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.transform = function (matrix) {
    // body...

    return this;
  };

  /**
   * embed
   *
   * @param {Number} dim
   * @return {simplex.PointSet} this for chaining
   * @api public
   */

  simplexn.PointSet.prototype.embed = function (dim) {
    // body...

    return this;
  };

}(this));<|endoftext|>


<commit_before>'use strict';

const WebpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
const _ = require('lodash');
const chalk = require('chalk');

const metalsmith = require('./metalsmith');
const Logger = require('./logger');
const watch = require('./watch');
const webpackConfig = require('../webpack.config.development');

const PORT = 9200;

function serv() {

  Logger.info('Starting development server');

  return new Promise( (resolve, reject) => {

    const compiler = webpack(webpackConfig);

    compiler.plugin('compile', () => {
      Logger.info('Started compiling');
    });

    const message = _.once(stats => {

      const hasErrors = stats.hasErrors();
      const hasWarnings = stats.hasWarnings();

      if (!hasErrors && !hasWarnings) {

        const statistics = stats.toString({
          colors: true,
          cached: true,
          reasons: false,
          source: false,
          chunks: false,
          children: false
        });

        const uri = `http://localhost:${PORT}/`;

        Logger.info(statistics);
        Logger.ok('Finished webpack compiling');
        Logger.log(`The app is running at ${chalk.magenta(uri)}`);

        return;

      }

      if (hasErrors) {
        Logger.failed('Failed webpack compiling');
        reject('Failed webpack compiling');
      }

    });

    compiler.plugin('done', stats => {

      // The bless-webpack-plugin listens on the "optimize-assets" and triggers an "emit" event if changes are
      // made to any css chunks.  This makes it appear that Webpack is bundling everything twice in the logs.
      // Removing the bless-webpack-plugin resolves the issue but then we run the risk of creating css bundles
      // great than the IE9 limit.
      //
      // https://blogs.msdn.microsoft.com/ieinternals/2011/05/14/stylesheet-limits-in-internet-explorer
      //
      message(stats);

    });

    const server = new WebpackDevServer(compiler, {
      contentBase: './build',
      noInfo: true, // display no info to console (only warnings and errors)
      quiet: true, // display nothing to the console
      compress: true,
      hot: true,
      watchOptions: {
        ignored: /node_modules/
      }
    });

    server.listen(PORT, () => {
      Logger.ok('Finished development server');
      resolve();
    });
  });

}

function start() {

  return metalsmith()
    .then(serv)
    .then(watch);
}

module.exports = start;
<commit_msg>update start task<commit_after>'use strict';

const WebpackDevServer = require('webpack-dev-server');
const webpack = require('webpack');
const _ = require('lodash');
const chalk = require('chalk');

const metalsmith = require('./metalsmith');
const Logger = require('./logger');
const watch = require('./watch');
const webpackConfig = require('../webpack.config.development');

const PORT = 9200;

function serv() {

  Logger.info('Starting development server');

  return new Promise( (resolve, reject) => {

    const compiler = webpack(webpackConfig);

    compiler.plugin('compile', () => {
      Logger.info('Started compiling');
    });

    const message = _.once(stats => {

      const hasErrors = stats.hasErrors();
      const hasWarnings = stats.hasWarnings();

      if (!hasErrors && !hasWarnings) {

        const statistics = stats.toString({
          colors: true,
          cached: true,
          reasons: false,
          source: false,
          chunks: false,
          children: false
        });

        const uri = `http://localhost:${PORT}/`;

        Logger.info(statistics);
        Logger.ok('Finished webpack compiling');
        Logger.log(`The app is running at ${chalk.magenta(uri)}`);

        return;

      }

      if (hasErrors) {

        Logger.failed('Failed compiling');
        Logger.info(stats.compilation.errors);
        reject(stats.compilation.errors);
      }

    });

    compiler.plugin('done', stats => {

      // The bless-webpack-plugin listens on the "optimize-assets" and triggers an "emit" event if changes are
      // made to any css chunks.  This makes it appear that Webpack is bundling everything twice in the logs.
      // Removing the bless-webpack-plugin resolves the issue but then we run the risk of creating css bundles
      // great than the IE9 limit.
      //
      // https://blogs.msdn.microsoft.com/ieinternals/2011/05/14/stylesheet-limits-in-internet-explorer
      //
      message(stats);

    });

    const server = new WebpackDevServer(compiler, {
      contentBase: './build',
      noInfo: true, // display no info to console (only warnings and errors)
      quiet: true, // display nothing to the console
      compress: true,
      hot: true,
      watchOptions: {
        ignored: /node_modules/
      }
    });

    server.listen(PORT, (err) => {

      if (err) {
        Logger.failed(err);
        reject(err);
      }

      Logger.ok('Finished development server');
      resolve();
    });
  });

}

function start() {

  return metalsmith()
    .then(serv)
    .then(watch);
}

module.exports = start;
<|endoftext|>