<commit_before>'use strict';

import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import {ExtendModel} from '../../lib/Vogels/ExtendModel';
import {Exception} from '../../lib/Vogels/Exceptions/Exception';
import {UndefinedMethodException} from '../../lib/Vogels/Exceptions/UndefinedMethodException';
import {ModelMock} from '../../test/Mock/ModelMock';
import {ExtendModelMock} from '../../test/Mock/ExtendModelMock';
import resultSegments from './scan.segments';

chai.use(sinonChai);

suite('Vogels/ExtendModel', () => {
  let model = {
    Name: {
      Name: 'string',
      Id: 'timeUUID',
    },
  };
  let extendModel = new ExtendModel(model);

  let modelMock = new ModelMock();
  modelMock.setMode(ModelMock.NO_RESULT_MODE);
  let mockedExtendModel = new ExtendModel(modelMock);

  test('Class ExtendModel exists in Vogels/ExtendModel', () => {
    chai.expect(ExtendModel).to.be.an('function');
  });

  test('Check constructor sets _model', () => {
    chai.expect(extendModel.model).to.be.equal(model);
  });

  test('Check DEFAULT_LIMIT static getter returns value more than 0', () => {
    chai.expect(ExtendModel.DEFAULT_LIMIT).to.be.above(0);
  });

  test('Check DEFAULT_SEGMENTS_NUMBER static getter returns value more than 0', () => {
    chai.expect(ExtendModel.DEFAULT_SEGMENTS_NUMBER).to.be.above(0);
  });

  test('Check buildScanParameters static getter returns value more than 0', () => {
    let expectedResult = {
      filterExpression: '#firstKey = :firstKey AND #secondKey = :secondKey',
      filterExpressionNames: {
        '#firstKey': 'firstKey',
        '#secondKey': 'secondKey',
      },
      filterExpressionValues: {
        ':firstKey': 'Value0',
        ':secondKey': 'Value0',
      },
    };
    let acttualResult = ExtendModel.buildScanParameters({firstKey: 'Value0', secondKey: 'Value0',})
    chai.expect(acttualResult).to.be.eql(expectedResult);
  });

  test('Check inject() method with methods=null', () => {
    chai.expect(extendModel.inject()).to.be.eql(model);
  });

  test('Check methods() getter', () => {
    let actualResult = extendModel.methods;
    let methods = Object.keys(actualResult);

    let expectedMethodNames = ['findAll', 'findAllPaginated', 'findOneById', 'findOneBy',
      'findBy', 'findAllBy', 'findAllByPaginated', 'findMatching', 'findOneMatching',
      'findAllMatching', 'findAllMatchingPaginated', 'deleteById',
      'deleteByIdConditional', 'createItem', 'createUniqueOnFields',
      'updateItem', 'updateItemConditional', 'findItems'];

    //check all items is fucntions
    for (let methodName of expectedMethodNames) {
      chai.expect(methods).to.be.contains(methodName);
      chai.expect(typeof actualResult[methodName]).to.be.equal('function');
    }
  });

  // @todo move to a separate file
  const queryMock = (function() {
    let segmentKeys = Object.keys(resultSegments);
    let startKey = segmentKeys[0];

    return {
      segmentKeys() {
        return segmentKeys;
      },
      limit() {
        return this;
      },
      startKey(key) {
        startKey = key || startKey;
        return this;
      },
      exec(cb) {
        const result = resultSegments[startKey];

        cb(null, result);
      },
    };
  });

  test('Check method._findUntilLimit[Cb]() passes findOne* call', (done) => {
    mockedExtendModel.methods._findUntilLimitCb((error, result) => {
      chai.expect(error).to.be.null;
      chai.expect(result).to.deep.equal({
        ScannedCount: 3,
        Count: 1,
        Items: [ 'a1' ],
      });

      done();
    }, new queryMock, 1);
  });

  test('Check method._findUntilLimit[Cb]() passes findBy* call', (done) => {
    mockedExtendModel.methods._findUntilLimitCb((error, result) => {
      chai.expect(error).to.be.null;
      chai.expect(result).to.deep.equal({
        ScannedCount: 9,
        Count: 7,
        Items: [ 'a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1' ],
      });

      done();
    }, new queryMock, 7);
  });

  test('Check method._findUntilLimit[Cb]() passes findBy*Paginated call', (done) => {
    let query = new queryMock;
    let segmentKeys = query.segmentKeys();

    mockedExtendModel.methods._findUntilLimitCb(
      (error, result) => {
        console.log('result', JSON.stringify(result));//@todo remove

        chai.expect(error).to.be.null;
        chai.expect(result).to.deep.equal({
          ScannedCount: 6,
          Count: 6,
          Items: [ 'c1', 'c2', 'c3', 'd1', 'd2', 'd3' ],
        });

        done();
      }, query, 999, 0, [], segmentKeys[segmentKeys.length - 3]
    );
  });

  test('Check method.findAll() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAll(spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findAllPaginated() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findAllPaginated('startKey', 'limit', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findOneById() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findOneById('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findOneBy() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findOneBy('fieldName', 'value', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  // test('Check method.findBy() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findBy('fieldName', 'value', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findAllBy() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllBy('fieldName', 'value', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.findAllByPaginated() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllByPaginated('fieldName', 'value', 'startKey', 'limit', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findMatching() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findMatching({}, spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  // test('Check method.findOneMatching() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findOneMatching({}, spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findAllMatching() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllMatching({}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.findAllMatchingPaginated() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllMatchingPaginated({}, 'startKey', 'limit', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.deleteById() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.deleteById('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.deleteByIdConditional() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.deleteByIdConditional('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.createItem() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.createItem('data', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.updateItem() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.updateItem('id', {key: 'test value'}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.updateItemConditional() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.updateItemConditional('id', {key: 'test value'}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.createUniqueOnFields() for already existed item', () => {
    let spyCallback = sinon.spy();

    modelMock.setMode(ModelMock.DATA_WITH_COUNT_MODE, ['exec']);

    mockedExtendModel.methods.createUniqueOnFields('fields', {Count: false}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWith();

    chai.expect(spyCallback.args[0][0]).to.contains('already exists');
  });

  test('Check method.createUniqueOnFields() for new fields', () => {
    let spyCallback = sinon.spy();

    modelMock.setMode(ModelMock.DATA_MODE, ['exec']);

    mockedExtendModel.methods.createUniqueOnFields('fields', {Count: false}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  //@todo - to be updated
  //test('Check "Exception" exception can be called', () => {
  //  let extendModelMock = new ExtendModelMock();
  //  let error = null;
  //  let msg = 'Test message';
  //
  //  try {
  //    extendModelMock.throwException(msg);
  //  } catch (e) {
  //    error = e;
  //  }
  //
  //  chai.assert.instanceOf(error, Exception, 'error is an instance of Exception');
  //});
  //
  //test('Check "UndefinedMethodException" exception can be called', () => {
  //  let error = null;
  //  let method = 'test';
  //  let predefinedMethods = ['firstMethod', 'secondMethod'];
  //  let extendModelMock = new ExtendModelMock();
  //
  //  try {
  //    extendModelMock.throwUndefinedMethodException(method, predefinedMethods);
  //  } catch (e) {
  //    error = e;
  //  }
  //
  //  chai.assert.instanceOf(
  //    error, UndefinedMethodException, 'error is an instance of UndefinedMethodException'
  //  );
  //});
});
<commit_msg>Fix packages tests<commit_after>'use strict';

import chai from 'chai';
import sinon from 'sinon';
import sinonChai from 'sinon-chai';
import {ExtendModel} from '../../lib/Vogels/ExtendModel';
import {Exception} from '../../lib/Vogels/Exceptions/Exception';
import {UndefinedMethodException} from '../../lib/Vogels/Exceptions/UndefinedMethodException';
import {ModelMock} from '../../test/Mock/ModelMock';
import {ExtendModelMock} from '../../test/Mock/ExtendModelMock';
import resultSegments from './scan.segments';

chai.use(sinonChai);

suite('Vogels/ExtendModel', () => {
  let model = {
    Name: {
      Name: 'string',
      Id: 'timeUUID',
    },
  };
  let extendModel = new ExtendModel(model);

  let modelMock = new ModelMock();
  modelMock.setMode(ModelMock.NO_RESULT_MODE);
  let mockedExtendModel = new ExtendModel(modelMock);

  test('Class ExtendModel exists in Vogels/ExtendModel', () => {
    chai.expect(ExtendModel).to.be.an('function');
  });

  test('Check constructor sets _model', () => {
    chai.expect(extendModel.model).to.be.equal(model);
  });

  test('Check DEFAULT_LIMIT static getter returns value more than 0', () => {
    chai.expect(ExtendModel.DEFAULT_LIMIT).to.be.above(0);
  });

  test('Check DEFAULT_SEGMENTS_NUMBER static getter returns value more than 0', () => {
    chai.expect(ExtendModel.DEFAULT_SEGMENTS_NUMBER).to.be.above(0);
  });

  test('Check buildScanParameters static getter returns value more than 0', () => {
    let expectedResult = {
      filterExpression: '#firstKey = :firstKey AND #secondKey = :secondKey',
      filterExpressionNames: {
        '#firstKey': 'firstKey',
        '#secondKey': 'secondKey',
      },
      filterExpressionValues: {
        ':firstKey': 'Value0',
        ':secondKey': 'Value0',
      },
    };
    let acttualResult = ExtendModel.buildScanParameters({firstKey: 'Value0', secondKey: 'Value0',})
    chai.expect(acttualResult).to.be.eql(expectedResult);
  });

  test('Check inject() method with methods=null', () => {
    chai.expect(extendModel.inject()).to.be.eql(model);
  });

  test('Check methods() getter', () => {
    let actualResult = extendModel.methods;
    let methods = Object.keys(actualResult);

    let expectedMethodNames = ['findAll', 'findAllPaginated', 'findOneById', 'findOneBy',
      'findBy', 'findAllBy', 'findAllByPaginated', 'findMatching', 'findOneMatching',
      'findAllMatching', 'findAllMatchingPaginated', 'deleteById',
      'deleteByIdConditional', 'createItem', 'createUniqueOnFields',
      'updateItem', 'updateItemConditional', 'findItems'];

    //check all items is fucntions
    for (let methodName of expectedMethodNames) {
      chai.expect(methods).to.be.contains(methodName);
      chai.expect(typeof actualResult[methodName]).to.be.equal('function');
    }
  });

  // @todo move to a separate file
  const queryMock = (function() {
    let segmentKeys = Object.keys(resultSegments);
    let startKey = segmentKeys[0];

    return {
      segmentKeys() {
        return segmentKeys;
      },
      limit() {
        return this;
      },
      startKey(key) {
        startKey = key || startKey;
        return this;
      },
      exec(cb) {
        const result = resultSegments[startKey];

        cb(null, result);
      },
    };
  });

  test('Check method._findUntilLimit[Cb]() passes findOne* call', (done) => {
    mockedExtendModel.methods._findUntilLimitCb((error, result) => {
      chai.expect(error).to.be.null;
      chai.expect(result).to.deep.equal({
        ScannedCount: 3,
        Count: 1,
        Items: [ 'a1' ],
      });

      done();
    }, new queryMock, 1);
  });

  test('Check method._findUntilLimit[Cb]() passes findBy* call', (done) => {
    mockedExtendModel.methods._findUntilLimitCb((error, result) => {
      chai.expect(error).to.be.null;
      chai.expect(result).to.deep.equal({
        ScannedCount: 9,
        Count: 7,
        Items: [ 'a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1' ],
      });

      done();
    }, new queryMock, 7);
  });

  test('Check method._findUntilLimit[Cb]() passes findBy*Paginated call', (done) => {
    let query = new queryMock;
    let segmentKeys = query.segmentKeys();

    mockedExtendModel.methods._findUntilLimitCb(
      (error, result) => {
        console.log('result', JSON.stringify(result));//@todo remove

        chai.expect(error).to.be.null;
        chai.expect(result).to.deep.equal({
          ScannedCount: 6,
          Count: 6,
          Items: [ 'c1', 'c2', 'c3', 'd1', 'd2', 'd3' ],
        });

        done();
      }, query, 999, 0, [], segmentKeys[segmentKeys.length - 2]
    );
  });

  test('Check method.findAll() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAll(spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findAllPaginated() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findAllPaginated('startKey', 'limit', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findOneById() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findOneById('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findOneBy() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findOneBy('fieldName', 'value', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  // test('Check method.findBy() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findBy('fieldName', 'value', spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findAllBy() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllBy('fieldName', 'value', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.findAllByPaginated() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllByPaginated('fieldName', 'value', 'startKey', 'limit', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  // test('Check method.findMatching() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findMatching({}, spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  // test('Check method.findOneMatching() exist and can be called', () => {
  //   let spyCallback = sinon.spy();
  //
  //   mockedExtendModel.methods.findOneMatching({}, spyCallback);
  //
  //   chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  // });

  test('Check method.findAllMatching() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllMatching({}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.findAllMatchingPaginated() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.findAllMatchingPaginated({}, 'startKey', 'limit', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.deleteById() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.deleteById('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.deleteByIdConditional() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.deleteByIdConditional('id', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.createItem() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.createItem('data', spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.updateItem() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.updateItem('id', {key: 'test value'}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.updateItemConditional() exist and can be called', () => {
    let spyCallback = sinon.spy();

    mockedExtendModel.methods.updateItemConditional('id', {key: 'test value'}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  test('Check method.createUniqueOnFields() for already existed item', () => {
    let spyCallback = sinon.spy();

    modelMock.setMode(ModelMock.DATA_WITH_COUNT_MODE, ['exec']);

    mockedExtendModel.methods.createUniqueOnFields('fields', {Count: false}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWith();

    chai.expect(spyCallback.args[0][0]).to.contains('already exists');
  });

  test('Check method.createUniqueOnFields() for new fields', () => {
    let spyCallback = sinon.spy();

    modelMock.setMode(ModelMock.DATA_MODE, ['exec']);

    mockedExtendModel.methods.createUniqueOnFields('fields', {Count: false}, spyCallback);

    chai.expect(spyCallback).to.have.been.calledWithExactly(null, null);
  });

  //@todo - to be updated
  //test('Check "Exception" exception can be called', () => {
  //  let extendModelMock = new ExtendModelMock();
  //  let error = null;
  //  let msg = 'Test message';
  //
  //  try {
  //    extendModelMock.throwException(msg);
  //  } catch (e) {
  //    error = e;
  //  }
  //
  //  chai.assert.instanceOf(error, Exception, 'error is an instance of Exception');
  //});
  //
  //test('Check "UndefinedMethodException" exception can be called', () => {
  //  let error = null;
  //  let method = 'test';
  //  let predefinedMethods = ['firstMethod', 'secondMethod'];
  //  let extendModelMock = new ExtendModelMock();
  //
  //  try {
  //    extendModelMock.throwUndefinedMethodException(method, predefinedMethods);
  //  } catch (e) {
  //    error = e;
  //  }
  //
  //  chai.assert.instanceOf(
  //    error, UndefinedMethodException, 'error is an instance of UndefinedMethodException'
  //  );
  //});
});
<|endoftext|>


<commit_before>/**
 * Static utilities for PSV
 */
var PSVUtils = {};

/**
 * Check if some Three.js components are loaded
 * @param components (String...)
 * @returns (boolean)
 */
PSVUtils.checkTHREE = function(/* components */) {
  for (var i = 0, l = arguments.length; i < l; i++) {
    if (!(arguments[i] in THREE)) {
      return false;
    }
  }

  return true;
};

/**
 * Detects whether canvas is supported
 * @return (boolean) true if canvas is supported, false otherwise
 */
PSVUtils.isCanvasSupported = function() {
  var canvas = document.createElement('canvas');
  return !!(canvas.getContext && canvas.getContext('2d'));
};

/**
 * Detects whether WebGL is supported
 * @return (boolean) true if WebGL is supported, false otherwise
 */
PSVUtils.isWebGLSupported = function() {
  var canvas = document.createElement('canvas');
  return !!(window.WebGLRenderingContext && canvas.getContext('webgl'));
};

/**
 * Get max texture width in WebGL context
 * @return (int)
 */
PSVUtils.getMaxTextureWidth = function() {
  var canvas = document.createElement('canvas');
  var ctx = canvas.getContext('webgl');
  return ctx.getParameter(ctx.MAX_TEXTURE_SIZE);
};

/**
 * Search if an element has a particular, at any level including itself
 * @param el (HTMLElement)
 * @param parent (HTMLElement)
 * @return (Boolean)
 */
PSVUtils.hasParent = function(el, parent) {
  do {
    if (el === parent) {
      return true;
    }
  } while (!!(el = el.parentNode));

  return false;
};

/**
 * Get closest parent (can by itself)
 * @param el (HTMLElement)
 * @param selector (String)
 * @return (HTMLElement)
 */
PSVUtils.getClosest = function(el, selector) {
  var matches = el.matches || el.msMatchesSelector;

  do {
    if (matches.bind(el)(selector)) {
      return el;
    }
  } while (!!(el = el.parentElement));

  return null;
};

/**
 * Get the event name for mouse wheel
 * @return (string)
 */
PSVUtils.mouseWheelEvent = function() {
  return 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
    document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
};

/**
 * Get the event name for fullscreen event
 * @return (string)
 */
PSVUtils.fullscreenEvent = function() {
  var map = {
    'exitFullscreen': 'fullscreenchange',
    'webkitExitFullscreen': 'webkitfullscreenchange',
    'mozCancelFullScreen': 'mozfullscreenchange',
    'msExitFullscreen': 'msFullscreenEnabled'
  };

  for (var exit in map) {
    if (exit in document) return map[exit];
  }

  return 'fullscreenchange';
};

/**
 * Ensures that a number is in a given interval
 * @param x (number) The number to check
 * @param min (number) First endpoint
 * @param max (number) Second endpoint
 * @return (number) The checked number
 */
PSVUtils.stayBetween = function(x, min, max) {
  return Math.max(min, Math.min(max, x));
};

/**
 * Returns the value of a given attribute in the panorama metadata
 * @param data (string) The panorama metadata
 * @param attr (string) The wanted attribute
 * @return (string) The value of the attribute
 */
PSVUtils.getXMPValue = function(data, attr) {
  var a, b;
  // XMP data are stored in children
  if ((a = data.indexOf('<GPano:' + attr + '>')) !== -1 && (b = data.indexOf('</GPano:' + attr + '>')) !== -1) {
    return data.substring(a, b).replace('<GPano:' + attr + '>', '');
  }
  // XMP data are stored in attributes
  else if ((a = data.indexOf('GPano:' + attr)) !== -1 && (b = data.indexOf('"', a + attr.length + 8)) !== -1) {
    return data.substring(a + attr.length + 8, b);
  }
  else {
    return null;
  }
};

/**
 * Detects whether fullscreen is enabled or not
 * @return (boolean) true if fullscreen is enabled, false otherwise
 */
PSVUtils.isFullscreenEnabled = function() {
  return (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
};

/**
 * Enters fullscreen mode
 * @param elt (HTMLElement)
 */
PSVUtils.requestFullscreen = function(elt) {
  (elt.requestFullscreen || elt.mozRequestFullScreen || elt.webkitRequestFullscreen || elt.msRequestFullscreen).call(elt);
};

/**
 * Exits fullscreen mode
 * @param elt (HTMLElement)
 */
PSVUtils.exitFullscreen = function(elt) {
  (document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen || document.msExitFullscreen).call(document);
};

/**
 * Gets an element style
 * @param elt (HTMLElement)
 * @param prop (string)
 * @return mixed
 */
PSVUtils.getStyle = function(elt, prop) {
  return window.getComputedStyle(elt, null)[prop];
};

/**
 * Translate CSS values like "top center" or "10% 50%" as top and left positions
 * @param value (String)
 * @return Object
 */
PSVUtils.parsePosition = function(value) {
  if (!value) {
    return { top: 0.5, left: 0.5 };
  }

  if (typeof value === 'object') {
    return value;
  }

  var e = document.createElement('div');
  document.body.appendChild(e);
  e.style.backgroundPosition = value;
  var parsed = PSVUtils.getStyle(e, 'background-position').match(/^([0-9.]+)% ([0-9.]+)%$/);
  document.body.removeChild(e);

  return {
    left: parsed[1] / 100,
    top: parsed[2] / 100
  };
};

/**
 * Utility for animations
 * @param options (Object)
 *    - properties ({name: {end: number, start: number}})
 *    - duration (int)
 *    - delay (int, optional)
 *    - easing (string|function, optional)
 *    - onTick (function(properties))
 *    - onCancel (function)
 * @returns (D.promise) with an additional "cancel" method
 */
PSVUtils.animation = function(options) {
  var defer = D();
  var start = null;

  if (!options.easing || typeof options.easing == 'string') {
    options.easing = PSVUtils.animation.easings[options.easing || 'linear'];
  }

  function run(timestamp) {
    // the animation has been cancelled
    if (defer.promise.getStatus() === -1) {
      return;
    }

    // first iteration
    if (start === null) {
      start = timestamp;
    }

    // compute progress
    var progress = (timestamp - start) / options.duration;
    var current = {};
    var name;

    if (progress < 1.0) {
      // interpolate properties
      for (name in options.properties) {
        current[name] = options.properties[name].start + (options.properties[name].end - options.properties[name].start) * options.easing(progress);
      }

      options.onTick(current, progress);

      window.requestAnimationFrame(run);
    }
    else {
      // call onTick one last time with final values
      for (name in options.properties) {
        current[name] = options.properties[name].end;
      }

      options.onTick(current, 1.0);

      defer.resolve();
    }
  }

  if (options.delay !== undefined) {
    window.setTimeout(function() {
      window.requestAnimationFrame(run);
    }, options.delay);
  }
  else {
    window.requestAnimationFrame(run);
  }

  // add a "cancel" to the promise
  var promise = defer.promise;
  promise.cancel = function() {
    if (options.onCancel) {
      options.onCancel();
      defer.reject(defer);
    }
  };
  return promise;
};

/**
 * Collection of easing functions
 * https://gist.github.com/frederickk/6165768
 */
// @formatter:off
// jscs:disable
/* jshint ignore:start */
PSVUtils.animation.easings = {
  // no easing, no acceleration
  linear: function(t) { return t; },

  // accelerating from zero velocity
  inQuad: function(t) { return t*t; },
  // decelerating to zero velocity
  outQuad: function(t) { return t*(2-t); },
  // acceleration until halfway, then deceleration
  inOutQuad: function(t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; },

  // accelerating from zero velocity
  inCubic: function(t) { return t*t*t; },
  // decelerating to zero velocity
  outCubic: function(t) { return (--t)*t*t+1; },
  // acceleration until halfway, then deceleration
  inOutCubic: function(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; },

  // accelerating from zero velocity
  inQuart: function(t) { return t*t*t*t; },
  // decelerating to zero velocity
  outQuart: function(t) { return 1-(--t)*t*t*t; },
  // acceleration until halfway, then deceleration
  inOutQuart: function(t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; },

  // accelerating from zero velocity
  inQuint: function(t) { return t*t*t*t*t; },
  // decelerating to zero velocity
  outQuint: function(t) { return 1+(--t)*t*t*t*t; },
  // acceleration until halfway, then deceleration
  inOutQuint: function(t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; },

  // accelerating from zero velocity
  inSine: function(t) { return 1-Math.cos(t*(Math.PI/2)); },
  // decelerating to zero velocity
  outSine: function(t) { return Math.sin(t*(Math.PI/2)); },
  // accelerating until halfway, then decelerating
  inOutSine: function(t) { return .5-.5*Math.cos(Math.PI*t); },

  // accelerating from zero velocity
  inExpo: function(t) { return Math.pow(2, 10*(t-1)); },
  // decelerating to zero velocity
  outExpo: function(t) { return 1-Math.pow(2, -10*t); },
  // accelerating until halfway, then decelerating
  inOutExpo: function(t) { t=t*2-1; return t<0 ? .5*Math.pow(2, 10*t) : 1-.5*Math.pow(2, -10*t); },

  // accelerating from zero velocity
  inCirc: function(t) { return 1-Math.sqrt(1-t*t); },
  // decelerating to zero velocity
  outCirc: function(t) { t--; return Math.sqrt(1-t*t); },
  // acceleration until halfway, then deceleration
  inOutCirc: function(t) { t*=2; return t<1 ? .5-.5*Math.sqrt(1-t*t) : .5+.5*Math.sqrt(1-(t-=2)*t); }
};
// jscs:enable
/* jshint ignore:end */
// @formatter:off

/**
 * Merge the enumerable attributes of two objects.
 * Modified to replace arrays instead of merge.
 * @copyright Nicholas Fisher <nfisher110@gmail.com>"
 * @license MIT
 * @param object
 * @param object
 * @return object
 */
PSVUtils.deepmerge = function(target, src) {
  var array = Array.isArray(src);
  var dst = array && [] || {};

  if (array) {
    src.forEach(function(e, i) {
      if (typeof dst[i] === 'undefined') {
        dst[i] = e;
      }
      else {
        dst[i] = PSVUtils.deepmerge(null, e);
      }
    });
  }
  else {
    if (target && Array.isArray(target)) {
      target = undefined;
    }
    if (target && typeof target === 'object') {
      Object.keys(target).forEach(function(key) {
        dst[key] = target[key];
      });
    }
    Object.keys(src).forEach(function(key) {
      if (typeof src[key] !== 'object' || !src[key]) {
        dst[key] = src[key];
      }
      else {
        if (!target[key]) {
          dst[key] = src[key];
        }
        else {
          dst[key] = PSVUtils.deepmerge(target[key], src[key]);
        }
      }
    });
  }

  return dst;
};

/**
 * Clone an object
 * @param object
 * @return object
 */
PSVUtils.clone = function(src) {
  return PSVUtils.deepmerge(Array.isArray(src) ? [] : {}, src);
};
<commit_msg>Update PSVUtils.js<commit_after>/**
 * Static utilities for PSV
 */
var PSVUtils = {};

/**
 * Check if some Three.js components are loaded
 * @param components (String...)
 * @returns (boolean)
 */
PSVUtils.checkTHREE = function(/* components */) {
  for (var i = 0, l = arguments.length; i < l; i++) {
    if (!(arguments[i] in THREE)) {
      return false;
    }
  }

  return true;
};

/**
 * Detects whether canvas is supported
 * @return (boolean) true if canvas is supported, false otherwise
 */
PSVUtils.isCanvasSupported = function() {
  var canvas = document.createElement('canvas');
  return !!(canvas.getContext && canvas.getContext('2d'));
};

/**
 * Tries to return a canvas webgl context
 * @return (ctx) if canvas is supported, undefined otherwise
 */
PSVUtils.getWebGLCtx = function() {
  var canvas = document.createElement('canvas');
  var names = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'];
  var context = null;

  if (!canvas.getContext) {
    return null;
  }

  if (names.some(function(name) {
    try {
      context = canvas.getContext(name);
      return (context && typeof context.getParameter == 'function');
    } catch (e) {
      return false;
    }
  })) {
    return context;
  }
  else {
    return null;
  }
};

/**
 * Detects whether WebGL is supported
 * @return (boolean) true if WebGL is supported, false otherwise
 */
PSVUtils.isWebGLSupported = function() {
  return !!window.WebGLRenderingContext && PSVUtils.getWebGLCtx() !== null;
};

/**
 * Get max texture width in WebGL context
 * @return (int)
 */
PSVUtils.getMaxTextureWidth = function() {
  var ctx = PSVUtils.getWebGLCtx();
  return ctx.getParameter(ctx.MAX_TEXTURE_SIZE);
};

/**
 * Search if an element has a particular, at any level including itself
 * @param el (HTMLElement)
 * @param parent (HTMLElement)
 * @return (Boolean)
 */
PSVUtils.hasParent = function(el, parent) {
  do {
    if (el === parent) {
      return true;
    }
  } while (!!(el = el.parentNode));

  return false;
};

/**
 * Get closest parent (can by itself)
 * @param el (HTMLElement)
 * @param selector (String)
 * @return (HTMLElement)
 */
PSVUtils.getClosest = function(el, selector) {
  var matches = el.matches || el.msMatchesSelector;

  do {
    if (matches.bind(el)(selector)) {
      return el;
    }
  } while (!!(el = el.parentElement));

  return null;
};

/**
 * Get the event name for mouse wheel
 * @return (string)
 */
PSVUtils.mouseWheelEvent = function() {
  return 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
    document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
};

/**
 * Get the event name for fullscreen event
 * @return (string)
 */
PSVUtils.fullscreenEvent = function() {
  var map = {
    'exitFullscreen': 'fullscreenchange',
    'webkitExitFullscreen': 'webkitfullscreenchange',
    'mozCancelFullScreen': 'mozfullscreenchange',
    'msExitFullscreen': 'msFullscreenEnabled'
  };

  for (var exit in map) {
    if (exit in document) return map[exit];
  }

  return 'fullscreenchange';
};

/**
 * Ensures that a number is in a given interval
 * @param x (number) The number to check
 * @param min (number) First endpoint
 * @param max (number) Second endpoint
 * @return (number) The checked number
 */
PSVUtils.stayBetween = function(x, min, max) {
  return Math.max(min, Math.min(max, x));
};

/**
 * Returns the value of a given attribute in the panorama metadata
 * @param data (string) The panorama metadata
 * @param attr (string) The wanted attribute
 * @return (string) The value of the attribute
 */
PSVUtils.getXMPValue = function(data, attr) {
  var a, b;
  // XMP data are stored in children
  if ((a = data.indexOf('<GPano:' + attr + '>')) !== -1 && (b = data.indexOf('</GPano:' + attr + '>')) !== -1) {
    return data.substring(a, b).replace('<GPano:' + attr + '>', '');
  }
  // XMP data are stored in attributes
  else if ((a = data.indexOf('GPano:' + attr)) !== -1 && (b = data.indexOf('"', a + attr.length + 8)) !== -1) {
    return data.substring(a + attr.length + 8, b);
  }
  else {
    return null;
  }
};

/**
 * Detects whether fullscreen is enabled or not
 * @return (boolean) true if fullscreen is enabled, false otherwise
 */
PSVUtils.isFullscreenEnabled = function() {
  return (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement);
};

/**
 * Enters fullscreen mode
 * @param elt (HTMLElement)
 */
PSVUtils.requestFullscreen = function(elt) {
  (elt.requestFullscreen || elt.mozRequestFullScreen || elt.webkitRequestFullscreen || elt.msRequestFullscreen).call(elt);
};

/**
 * Exits fullscreen mode
 * @param elt (HTMLElement)
 */
PSVUtils.exitFullscreen = function(elt) {
  (document.exitFullscreen || document.mozCancelFullScreen || document.webkitExitFullscreen || document.msExitFullscreen).call(document);
};

/**
 * Gets an element style
 * @param elt (HTMLElement)
 * @param prop (string)
 * @return mixed
 */
PSVUtils.getStyle = function(elt, prop) {
  return window.getComputedStyle(elt, null)[prop];
};

/**
 * Translate CSS values like "top center" or "10% 50%" as top and left positions
 * @param value (String)
 * @return Object
 */
PSVUtils.parsePosition = function(value) {
  if (!value) {
    return { top: 0.5, left: 0.5 };
  }

  if (typeof value === 'object') {
    return value;
  }

  var e = document.createElement('div');
  document.body.appendChild(e);
  e.style.backgroundPosition = value;
  var parsed = PSVUtils.getStyle(e, 'background-position').match(/^([0-9.]+)% ([0-9.]+)%$/);
  document.body.removeChild(e);

  return {
    left: parsed[1] / 100,
    top: parsed[2] / 100
  };
};

/**
 * Utility for animations
 * @param options (Object)
 *    - properties ({name: {end: number, start: number}})
 *    - duration (int)
 *    - delay (int, optional)
 *    - easing (string|function, optional)
 *    - onTick (function(properties))
 *    - onCancel (function)
 * @returns (D.promise) with an additional "cancel" method
 */
PSVUtils.animation = function(options) {
  var defer = D();
  var start = null;

  if (!options.easing || typeof options.easing == 'string') {
    options.easing = PSVUtils.animation.easings[options.easing || 'linear'];
  }

  function run(timestamp) {
    // the animation has been cancelled
    if (defer.promise.getStatus() === -1) {
      return;
    }

    // first iteration
    if (start === null) {
      start = timestamp;
    }

    // compute progress
    var progress = (timestamp - start) / options.duration;
    var current = {};
    var name;

    if (progress < 1.0) {
      // interpolate properties
      for (name in options.properties) {
        current[name] = options.properties[name].start + (options.properties[name].end - options.properties[name].start) * options.easing(progress);
      }

      options.onTick(current, progress);

      window.requestAnimationFrame(run);
    }
    else {
      // call onTick one last time with final values
      for (name in options.properties) {
        current[name] = options.properties[name].end;
      }

      options.onTick(current, 1.0);

      defer.resolve();
    }
  }

  if (options.delay !== undefined) {
    window.setTimeout(function() {
      window.requestAnimationFrame(run);
    }, options.delay);
  }
  else {
    window.requestAnimationFrame(run);
  }

  // add a "cancel" to the promise
  var promise = defer.promise;
  promise.cancel = function() {
    if (options.onCancel) {
      options.onCancel();
      defer.reject(defer);
    }
  };
  return promise;
};

/**
 * Collection of easing functions
 * https://gist.github.com/frederickk/6165768
 */
// @formatter:off
// jscs:disable
/* jshint ignore:start */
PSVUtils.animation.easings = {
  // no easing, no acceleration
  linear: function(t) { return t; },

  // accelerating from zero velocity
  inQuad: function(t) { return t*t; },
  // decelerating to zero velocity
  outQuad: function(t) { return t*(2-t); },
  // acceleration until halfway, then deceleration
  inOutQuad: function(t) { return t<.5 ? 2*t*t : -1+(4-2*t)*t; },

  // accelerating from zero velocity
  inCubic: function(t) { return t*t*t; },
  // decelerating to zero velocity
  outCubic: function(t) { return (--t)*t*t+1; },
  // acceleration until halfway, then deceleration
  inOutCubic: function(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1; },

  // accelerating from zero velocity
  inQuart: function(t) { return t*t*t*t; },
  // decelerating to zero velocity
  outQuart: function(t) { return 1-(--t)*t*t*t; },
  // acceleration until halfway, then deceleration
  inOutQuart: function(t) { return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t; },

  // accelerating from zero velocity
  inQuint: function(t) { return t*t*t*t*t; },
  // decelerating to zero velocity
  outQuint: function(t) { return 1+(--t)*t*t*t*t; },
  // acceleration until halfway, then deceleration
  inOutQuint: function(t) { return t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t; },

  // accelerating from zero velocity
  inSine: function(t) { return 1-Math.cos(t*(Math.PI/2)); },
  // decelerating to zero velocity
  outSine: function(t) { return Math.sin(t*(Math.PI/2)); },
  // accelerating until halfway, then decelerating
  inOutSine: function(t) { return .5-.5*Math.cos(Math.PI*t); },

  // accelerating from zero velocity
  inExpo: function(t) { return Math.pow(2, 10*(t-1)); },
  // decelerating to zero velocity
  outExpo: function(t) { return 1-Math.pow(2, -10*t); },
  // accelerating until halfway, then decelerating
  inOutExpo: function(t) { t=t*2-1; return t<0 ? .5*Math.pow(2, 10*t) : 1-.5*Math.pow(2, -10*t); },

  // accelerating from zero velocity
  inCirc: function(t) { return 1-Math.sqrt(1-t*t); },
  // decelerating to zero velocity
  outCirc: function(t) { t--; return Math.sqrt(1-t*t); },
  // acceleration until halfway, then deceleration
  inOutCirc: function(t) { t*=2; return t<1 ? .5-.5*Math.sqrt(1-t*t) : .5+.5*Math.sqrt(1-(t-=2)*t); }
};
// jscs:enable
/* jshint ignore:end */
// @formatter:off

/**
 * Merge the enumerable attributes of two objects.
 * Modified to replace arrays instead of merge.
 * @copyright Nicholas Fisher <nfisher110@gmail.com>"
 * @license MIT
 * @param object
 * @param object
 * @return object
 */
PSVUtils.deepmerge = function(target, src) {
  var array = Array.isArray(src);
  var dst = array && [] || {};

  if (array) {
    src.forEach(function(e, i) {
      if (typeof dst[i] === 'undefined') {
        dst[i] = e;
      }
      else {
        dst[i] = PSVUtils.deepmerge(null, e);
      }
    });
  }
  else {
    if (target && Array.isArray(target)) {
      target = undefined;
    }
    if (target && typeof target === 'object') {
      Object.keys(target).forEach(function(key) {
        dst[key] = target[key];
      });
    }
    Object.keys(src).forEach(function(key) {
      if (typeof src[key] !== 'object' || !src[key]) {
        dst[key] = src[key];
      }
      else {
        if (!target[key]) {
          dst[key] = src[key];
        }
        else {
          dst[key] = PSVUtils.deepmerge(target[key], src[key]);
        }
      }
    });
  }

  return dst;
};

/**
 * Clone an object
 * @param object
 * @return object
 */
PSVUtils.clone = function(src) {
  return PSVUtils.deepmerge(Array.isArray(src) ? [] : {}, src);
};
<|endoftext|>


<commit_before>/**
 * Created by mgoria on 11/6/15.
 */

'use strict';

import AWS from 'aws-sdk';
import CognitoSyncManager from 'amazon-cognito-js';
import {CreateCognitoDatasetException} from './Exception/CreateCognitoDatasetException';
import {PutCognitoRecordException} from './Exception/PutCognitoRecordException';
import {SynchronizeCognitoDatasetException} from './Exception/SynchronizeCognitoDatasetException';

export class CredentialsManager {
  /**
   * @returns {String}
   */
  static get DATASET_NAME() {
    return 'deep_session';
  }

  /**
   * @returns {String}
   */
  static get RECORD_NAME() {
    return 'session_creds';
  }

  /**
   * @param {String} identityPoolId
   * @param {Object|null} cognitoSyncClient
   */
  constructor(identityPoolId, cognitoSyncClient = null) {
    this._identityPoolId = identityPoolId;
    this._cognitoSyncClient = cognitoSyncClient;
  }

  /**
   * @returns {Object}
   */
  get cognitoSyncClient() {
    if (!this._cognitoSyncClient) {
      this._cognitoSyncClient = new AWS.CognitoSyncManager();
    }

    return this._cognitoSyncClient;
  }

  /**
   * @param {Object} credentials
   * @param {Function} callback
   */
  saveCredentials(credentials, callback) {
    this._createOrGetDataset((error, dataset) => {
      if (error) {
        callback(error, null);
        return;
      }

      dataset.put(CredentialsManager.RECORD_NAME, this._encodeCredentials(credentials), (error, record) => {
        if (error) {
          callback(new PutCognitoRecordException(
            CredentialsManager.DATASET_NAME, CredentialsManager.RECORD_NAME, error
          ), null);
          return;
        }

        this._synchronizeDataset(dataset, (error, savedRecords) => {
          if (error) {
            callback(new SynchronizeCognitoDatasetException(dataset, error), null);
            return;
          }

          callback(null, savedRecords);
        });
      });
    });
  }

  /**
   * @param {String} identityId
   * @param {Function} callback
   */
  loadCredentials(identityId, callback) {
    let cognitosync = new AWS.CognitoSync();

    let params = {
      DatasetName: CredentialsManager.DATASET_NAME,
      IdentityId: identityId,
      IdentityPoolId: this._identityPoolId,
    };

    cognitosync.listRecords(params, (error, data) => {
      if (error) {
        callback(error, null);
        return;
      }

      let creds = null;
      data.Records.forEach((record) => {
        if (record.Key === CredentialsManager.RECORD_NAME) {
          creds = this._decodeCredentials(record.Value);
          return creds;
        }
      });

      callback(null, creds);
    });
  }

  /**
   * @param {Function} callback
   * @private
   */
  _createOrGetDataset(callback) {
    this.cognitoSyncClient.openOrCreateDataset(CredentialsManager.DATASET_NAME, (error, dataset) => {
      if (error) {
        callback(new CreateCognitoDatasetException(CredentialsManager.DATASET_NAME, error), null);
        return;
      }

      callback(null, dataset);
    });
  }

  /**
   * @param {Object} dataset
   * @param {Function} callback
   * @private
   */
  _synchronizeDataset(dataset, callback) {
    dataset.synchronize({
      onSuccess: (dataset, newRecords) => {
        callback(null, newRecords);
      },
      onFailure: (error) => {
        callback(error, null);
      },
      onConflict: (dataset, conflicts) => {
        let resolved = [];

        for (let i = 0; i < conflicts.length; i++) {
          // take local version. @todo: implement custom merge logic to take latest changes
          resolved.push(conflicts[i].resolveWithLocalRecord());
        }

        dataset.resolve(resolved, () => {
          return callback(true);
        });
      },
      onDatasetDeleted: (dataset, datasetName, cb) => {
        return callback(true);
      },
      onDatasetMerged: (dataset, datasetNames, cb) => {
        return callback(true);
      }
    });
  }

  /**
   * @todo: implement an encoding method
   *
   * @param {Object} credentials
   * @returns {String}
   */
  _encodeCredentials(credentials) {
    // set secretAccessKey property enumerable:true to allow storing it into Cognito datastore
    credentials = Object.defineProperty(credentials, 'secretAccessKey', {
      enumerable: true,
      writable: true,
      configurable: true
    });

    return JSON.stringify(credentials);
  }

  /**
   * @todo: implement an encoding method
   *
   * @param {String} credentials
   * @returns {Object}
   */
  _decodeCredentials(credentials) {
    return JSON.parse(credentials);
  }
}
<commit_msg>Fix return for renamed cb<commit_after>/**
 * Created by mgoria on 11/6/15.
 */

'use strict';

import AWS from 'aws-sdk';
import CognitoSyncManager from 'amazon-cognito-js';
import {CreateCognitoDatasetException} from './Exception/CreateCognitoDatasetException';
import {PutCognitoRecordException} from './Exception/PutCognitoRecordException';
import {SynchronizeCognitoDatasetException} from './Exception/SynchronizeCognitoDatasetException';

export class CredentialsManager {
  /**
   * @returns {String}
   */
  static get DATASET_NAME() {
    return 'deep_session';
  }

  /**
   * @returns {String}
   */
  static get RECORD_NAME() {
    return 'session_creds';
  }

  /**
   * @param {String} identityPoolId
   * @param {Object|null} cognitoSyncClient
   */
  constructor(identityPoolId, cognitoSyncClient = null) {
    this._identityPoolId = identityPoolId;
    this._cognitoSyncClient = cognitoSyncClient;
  }

  /**
   * @returns {Object}
   */
  get cognitoSyncClient() {
    if (!this._cognitoSyncClient) {
      this._cognitoSyncClient = new AWS.CognitoSyncManager();
    }

    return this._cognitoSyncClient;
  }

  /**
   * @param {Object} credentials
   * @param {Function} callback
   */
  saveCredentials(credentials, callback) {
    this._createOrGetDataset((error, dataset) => {
      if (error) {
        callback(error, null);
        return;
      }

      dataset.put(CredentialsManager.RECORD_NAME, this._encodeCredentials(credentials), (error, record) => {
        if (error) {
          callback(new PutCognitoRecordException(
            CredentialsManager.DATASET_NAME, CredentialsManager.RECORD_NAME, error
          ), null);
          return;
        }

        this._synchronizeDataset(dataset, (error, savedRecords) => {
          if (error) {
            callback(new SynchronizeCognitoDatasetException(dataset, error), null);
            return;
          }

          callback(null, savedRecords);
        });
      });
    });
  }

  /**
   * @param {String} identityId
   * @param {Function} callback
   */
  loadCredentials(identityId, callback) {
    let cognitosync = new AWS.CognitoSync();

    let params = {
      DatasetName: CredentialsManager.DATASET_NAME,
      IdentityId: identityId,
      IdentityPoolId: this._identityPoolId,
    };

    cognitosync.listRecords(params, (error, data) => {
      if (error) {
        callback(error, null);
        return;
      }

      let creds = null;
      data.Records.forEach((record) => {
        if (record.Key === CredentialsManager.RECORD_NAME) {
          creds = this._decodeCredentials(record.Value);
          return creds;
        }
      });

      callback(null, creds);
    });
  }

  /**
   * @param {Function} callback
   * @private
   */
  _createOrGetDataset(callback) {
    this.cognitoSyncClient.openOrCreateDataset(CredentialsManager.DATASET_NAME, (error, dataset) => {
      if (error) {
        callback(new CreateCognitoDatasetException(CredentialsManager.DATASET_NAME, error), null);
        return;
      }

      callback(null, dataset);
    });
  }

  /**
   * @param {Object} dataset
   * @param {Function} callback
   * @private
   */
  _synchronizeDataset(dataset, callback) {
    dataset.synchronize({
      onSuccess: (dataset, newRecords) => {
        callback(null, newRecords);
      },
      onFailure: (error) => {
        callback(error, null);
      },
      onConflict: (dataset, conflicts) => {
        let resolved = [];

        for (let i = 0; i < conflicts.length; i++) {
          // take local version. @todo: implement custom merge logic to take latest changes
          resolved.push(conflicts[i].resolveWithLocalRecord());
        }

        dataset.resolve(resolved, () => {
          return callback(true);
        });
      },
      onDatasetDeleted: (dataset, datasetName, cb) => {
        return cb(true);
      },
      onDatasetMerged: (dataset, datasetNames, cb) => {
        return cb(true);
      }
    });
  }

  /**
   * @todo: implement an encoding method
   *
   * @param {Object} credentials
   * @returns {String}
   */
  _encodeCredentials(credentials) {
    // set secretAccessKey property enumerable:true to allow storing it into Cognito datastore
    credentials = Object.defineProperty(credentials, 'secretAccessKey', {
      enumerable: true,
      writable: true,
      configurable: true
    });

    return JSON.stringify(credentials);
  }

  /**
   * @todo: implement an encoding method
   *
   * @param {String} credentials
   * @returns {Object}
   */
  _decodeCredentials(credentials) {
    return JSON.parse(credentials);
  }
}
<|endoftext|>


<commit_before>/* Highlight all code blocks */
$('pre').each(function(i, block) {
	'use strict';

  /* globals hljs:false */
  hljs.highlightBlock(block);
});
<commit_msg>Fixes #13<commit_after><|endoftext|>


<commit_before>var calcMain = {
    calcObj : {
        srcNum: '0',
        destNum: '0',
        resultNum: '0',
        enterNum: '',
        btnFuncName: ''
    }
};
calcMain.fn = {};

calcMain.init = function(){
    var btnNums = document.getElementsByName('btn_num');

    for (var i = btnNums.length; i--;){
        btnNums[i].onclick = function(){
            calcMain.fn.clickBtnNum(this);
        }
    }

    document.getElementById('btn_func_plus').onclick = function() {
        calcMain.fn.plus();
    };

    document.getElementById('btn_func_clear').onclick = function(){
        calcMain.fn.clear();
    };

    document.getElementById('btn_func_equal').onclick = function(){
        calcMain.fn.equal();
    };
};

calcMain.fn.clickBtnNum = function(btnNumElement){
    var calcDisplay = document.getElementById('calcMain_display_div'),
        enterNum = calcMain.calcObj.enterNum;

    enterNum += btnNumElement.value;
    calcDisplay.innerHTML = enterNum;

    // set object
    calcMain.calcObj.enterNum = enterNum;
};

calcMain.fn.plus = function(){
    var srcNum = calcMain.calcObj.srcNum,
        destNum = calcMain.calcObj.destNum,
        enterNum = calcMain.calcObj.enterNum,
        resultNum = calcMain.calcObj.resultNum;

    calcMain.calcObj.btnFuncName = calcMain.fn.plus;

    if (enterNum == ''){
        resultNum = Number(srcNum) + Number(destNum);
        document.getElementById('calcMain_display_div').innerHTML = '' + resultNum;

    } else {
        destNum = enterNum;
        resultNum = Number(srcNum) + Number(destNum);

        calcMain.calcObj.srcNum = resultNum;
        calcMain.calcObj.destNum = '0';
        calcMain.calcObj.enterNum = '';
        calcMain.calcObj.resultNum = resultNum;
        document.getElementById('calcMain_display_div').innerHTML = '' + resultNum;
    }

    calcMain.fn.reloadSrcNum();
};

calcMain.fn.reloadSrcNum = function(){
    var calcDisplay = document.getElementById('calcMain_display_div'),
        calcDisplayValue = calcDisplay.innerHTML;

    calcDisplay.innerHTML = ' ';
    setTimeout(function () {
        calcDisplay.innerHTML = calcDisplayValue;
    }, 100);
};

calcMain.fn.clear = function(){
    calcMain.calcObj.srcNum = '0';
    calcMain.calcObj.resultNum = '0';
    calcMain.calcObj.destNum = '0';
    calcMain.calcObj.enterNum = '';
    calcMain.calcObj.btnFuncName = '';

    document.getElementById('calcMain_display_div').innerHTML = calcMain.calcObj.resultNum;
};

calcMain.fn.equal = function(){
    calcMain.calcObj.btnFuncName();
};
<commit_msg>refactor(calc): calcObj 객체 constructor 구현<commit_after>var calcMain = {
    calcObj : ''
};
calcMain.fn = {};

var calcObj = function(){
    this.srcNum = '0';
    this.destNum = '0';
    this.resultNum = '0';
    this.enterNum = '';
    this.btnFuncName = '';
};

calcMain.init = function(){
    calcMain.calcObj = new calcObj();

    var btnNums = document.getElementsByName('btn_num');

    for (var i = btnNums.length; i--;){
        btnNums[i].onclick = function(){
            calcMain.fn.clickBtnNum(this);
        }
    }

    document.getElementById('btn_func_plus').onclick = function() {
        calcMain.fn.plus();
    };

    document.getElementById('btn_func_clear').onclick = function(){
        calcMain.fn.clear();
    };

    document.getElementById('btn_func_equal').onclick = function(){
        calcMain.fn.equal();
    };
};

calcMain.fn.clickBtnNum = function(btnNumElement){
    var calcDisplay = document.getElementById('calcMain_display_div'),
        enterNum = calcMain.calcObj.enterNum;

    enterNum += btnNumElement.value;
    calcDisplay.innerHTML = enterNum;

    // set object
    calcMain.calcObj.enterNum = enterNum;
};

calcMain.fn.plus = function(){
    var srcNum = calcMain.calcObj.srcNum,
        destNum = calcMain.calcObj.destNum,
        enterNum = calcMain.calcObj.enterNum,
        resultNum = calcMain.calcObj.resultNum;

    calcMain.calcObj.btnFuncName = calcMain.fn.plus;

    if (enterNum == ''){
        resultNum = Number(srcNum) + Number(destNum);
        document.getElementById('calcMain_display_div').innerHTML = '' + resultNum;

    } else {
        destNum = enterNum;
        resultNum = Number(srcNum) + Number(destNum);

        calcMain.calcObj.srcNum = resultNum;
        calcMain.calcObj.destNum = '0';
        calcMain.calcObj.enterNum = '';
        calcMain.calcObj.resultNum = resultNum;
        document.getElementById('calcMain_display_div').innerHTML = '' + resultNum;
    }

    calcMain.fn.reloadSrcNum();
};

calcMain.fn.reloadSrcNum = function(){
    var calcDisplay = document.getElementById('calcMain_display_div'),
        calcDisplayValue = calcDisplay.innerHTML;

    calcDisplay.innerHTML = ' ';
    setTimeout(function () {
        calcDisplay.innerHTML = calcDisplayValue;
    }, 100);
};

calcMain.fn.clear = function(){
    calcMain.calcObj = new calcObj();
    document.getElementById('calcMain_display_div').innerHTML = calcMain.calcObj.resultNum;
};

calcMain.fn.equal = function(){
    calcMain.calcObj.btnFuncName();
};
<|endoftext|>


<commit_before>// Ajax
$.ajax = function (options) {
    var defaults = {
        method: 'GET',
        data: false,
        async: true,
        cache: true,
        user: '',
        password: '',
        headers: {},
        xhrFields: {},
        statusCode: {},
        processData: true,
        dataType: 'text',
        contentType: 'application/x-www-form-urlencoded'
    };

    //For jQuery guys
    if (options.type) options.type = options.method;

    // Merge options and defaults
    for (var prop in defaults) {
        if (!(prop in options)) options[prop] = defaults[prop];
    }

    // Default URL
    if (!options.url) {
        options.url = window.location.toString();
    }

    // Data to modify GET URL
    if ((options.method === 'GET' || options.method === 'HEAD') && options.data) {
        var stringData;
        if (typeof options.data === 'string') {
            // Should be key=value string
            if (options.data.indexOf('?') >= 0) stringData = options.data.split('?')[1];
            else stringData = options.data;
        }
        else {
            // Should be key=value object
            stringData = $.serializeObject(options.data);
        }
        if (options.url.indexOf('?') >= 0) options.url += '&' + stringData;
        else options.url += '?' + stringData;
    }
    // JSONP
    if (options.dataType === 'json' && options.url.indexOf('callback=') >= 0) {

        var callbackName = 'f7jsonp_' + Date.now();
        var requestURL;
        var callbackSplit = options.url.split('callback=');
        if (callbackSplit[1].indexOf('&') >= 0) {
            var addVars = callbackSplit[1].split('&').filter(function (el) { return el.indexOf('=') > 0; }).join('&');
            requestURL = callbackSplit[0] + 'callback=' + callbackName + (addVars.length > 0 ? '&' + addVars : '');
        }
        else {
            requestURL = callbackSplit[0] + 'callback=' + callbackName;
        }

        // Create script
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = requestURL;

        // Handler
        window[callbackName] = function (data) {
            if (options.success) options.success(data);
            script.parentNode.removeChild(script);
            script = null;
            delete window[callbackName];
        };
        document.querySelector('head').appendChild(script);

        return;
    }

    // Cache for GET/HEAD requests
    if (options.method === 'GET' || options.method === 'HEAD') {
        if (options.cache === false) options.url += ('_nocache=' + Date.now());
    }

    // Create XHR
    var xhr = new XMLHttpRequest();

    // Open XHR
    xhr.open(options.method, options.url, options.async, options.user, options.password);

    // Create POST Data
    var postData = null;

    if ((options.method === 'POST' || options.method === 'PUT') && options.data) {
        if (options.processData) {
            var postDataInstances = [ArrayBuffer, Blob, Document, FormData];
            // Post Data
            if (postDataInstances.indexOf(options.data.constructor) >= 0) {
                postData = options.data;
            }
            else {
                // POST Headers
                var boundary = '---------------------------' + Date.now().toString(16);

                if (options.contentType === 'multipart\/form-data') {
                    xhr.setRequestHeader('Content-Type', 'multipart\/form-data; boundary=' + boundary);
                }
                else {
                    xhr.setRequestHeader('Content-Type', options.contentType);
                }
                postData = '';
                var _data = $.serializeObject(options.data);
                if (options.contentType === 'multipart\/form-data') {
                    boundary = '---------------------------' + Date.now().toString(16);
                    _data = _data.split('&');
                    var _newData = [];
                    for (var i = 0; i < _data.length; i++) {
                        _newData.push('Content-Disposition: form-data; name="' + _data[i].split('=')[0] + '"\r\n\r\n' + _data[i].split('=')[1] + '\r\n');
                    }
                    postData = '--' + boundary + '\r\n' + _newData.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
                }
                else {
                    postData = options.contentType === 'application/x-www-form-urlencoded' ? _data : _data.replace(/&/g, '\r\n');
                }
            }
        }
        else {
            postData = options.data;
        }

    }

    // Additional headers
    if (options.headers) {
        for (var header in options.headers) {
            xhr.setRequestHeader(header, options.headers[header]);
        }
    }

    // Check for crossDomain
    if (typeof options.crossDomain === 'undefined') {
        options.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(options.url) && RegExp.$2 !== window.location.host;
    }

    if (!options.crossDomain) {
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    }

    if (options.xhrFields) {
        for (var field in options.xhrFields) {
            xhr[field] = options.xhrFields[field];
        }
    }

    // Handle XHR
    xhr.onload = function (e) {
        if (xhr.status === 200 || xhr.status === 0) {
            $(document).trigger('ajaxSuccess', {xhr: xhr});
            if (options.success) {
                var responseData = xhr.responseText;

                if (options.dataType === 'json') responseData = JSON.parse(responseData);
                options.success(responseData, xhr.status, xhr);
            }
        }
        if (options.statusCode) {
            if (options.statusCode[xhr.status]) options.statusCode[xhr.status](xhr);
        }
        if (options.complete) {
            options.complete(xhr);
        }
        $(document).trigger('ajaxComplete', {xhr: xhr});
    };
    if (options.error) {

    }
    xhr.onerror = function (e) {
        $(document).trigger('ajaxError', {xhr: xhr});
        if (options.error) options.error(xhr);
    };

    // Ajax start callback
    if (options.start) options.start(xhr);

    // Send XHR
    $(document).trigger('ajaxStart', {xhr: xhr});
    xhr.send(postData);

    // Return XHR object
    return xhr;
};
// Shrotcuts
(function () {
    var methods = ('get post getJSON').split(' ');
    function createMethod(method) {
        $[method] = function (url, data, success) {
            return $.ajax({
                url: url,
                method: method === 'post' ? 'POST' : 'GET',
                data: typeof data === 'function' ? undefined : data,
                success: typeof data === 'function' ? data : success,
                dataType: method === 'getJSON' ? 'json' : undefined
            });
        };
    }
    for (var i = 0; i < methods.length; i++) {
        createMethod(methods[i]);
    }
})();
<commit_msg>Fix multiple jsonp requests<commit_after>// Ajax
var _jsonpRequests = 0;
$.ajax = function (options) {
    var defaults = {
        method: 'GET',
        data: false,
        async: true,
        cache: true,
        user: '',
        password: '',
        headers: {},
        xhrFields: {},
        statusCode: {},
        processData: true,
        dataType: 'text',
        contentType: 'application/x-www-form-urlencoded'
    };

    //For jQuery guys
    if (options.type) options.type = options.method;

    // Merge options and defaults
    for (var prop in defaults) {
        if (!(prop in options)) options[prop] = defaults[prop];
    }

    // Default URL
    if (!options.url) {
        options.url = window.location.toString();
    }

    // Data to modify GET URL
    if ((options.method === 'GET' || options.method === 'HEAD') && options.data) {
        var stringData;
        if (typeof options.data === 'string') {
            // Should be key=value string
            if (options.data.indexOf('?') >= 0) stringData = options.data.split('?')[1];
            else stringData = options.data;
        }
        else {
            // Should be key=value object
            stringData = $.serializeObject(options.data);
        }
        if (options.url.indexOf('?') >= 0) options.url += '&' + stringData;
        else options.url += '?' + stringData;
    }
    // JSONP
    if (options.dataType === 'json' && options.url.indexOf('callback=') >= 0) {

        var callbackName = 'f7jsonp_' + Date.now() + (_jsonpRequests++);
        var requestURL;
        var callbackSplit = options.url.split('callback=');
        if (callbackSplit[1].indexOf('&') >= 0) {
            var addVars = callbackSplit[1].split('&').filter(function (el) { return el.indexOf('=') > 0; }).join('&');
            requestURL = callbackSplit[0] + 'callback=' + callbackName + (addVars.length > 0 ? '&' + addVars : '');
        }
        else {
            requestURL = callbackSplit[0] + 'callback=' + callbackName;
        }

        // Create script
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = requestURL;

        // Handler
        window[callbackName] = function (data) {
            if (options.success) options.success(data);
            script.parentNode.removeChild(script);
            script = null;
            delete window[callbackName];
        };
        document.querySelector('head').appendChild(script);

        return;
    }

    // Cache for GET/HEAD requests
    if (options.method === 'GET' || options.method === 'HEAD') {
        if (options.cache === false) options.url += ('_nocache=' + Date.now());
    }

    // Create XHR
    var xhr = new XMLHttpRequest();

    // Open XHR
    xhr.open(options.method, options.url, options.async, options.user, options.password);

    // Create POST Data
    var postData = null;

    if ((options.method === 'POST' || options.method === 'PUT') && options.data) {
        if (options.processData) {
            var postDataInstances = [ArrayBuffer, Blob, Document, FormData];
            // Post Data
            if (postDataInstances.indexOf(options.data.constructor) >= 0) {
                postData = options.data;
            }
            else {
                // POST Headers
                var boundary = '---------------------------' + Date.now().toString(16);

                if (options.contentType === 'multipart\/form-data') {
                    xhr.setRequestHeader('Content-Type', 'multipart\/form-data; boundary=' + boundary);
                }
                else {
                    xhr.setRequestHeader('Content-Type', options.contentType);
                }
                postData = '';
                var _data = $.serializeObject(options.data);
                if (options.contentType === 'multipart\/form-data') {
                    boundary = '---------------------------' + Date.now().toString(16);
                    _data = _data.split('&');
                    var _newData = [];
                    for (var i = 0; i < _data.length; i++) {
                        _newData.push('Content-Disposition: form-data; name="' + _data[i].split('=')[0] + '"\r\n\r\n' + _data[i].split('=')[1] + '\r\n');
                    }
                    postData = '--' + boundary + '\r\n' + _newData.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
                }
                else {
                    postData = options.contentType === 'application/x-www-form-urlencoded' ? _data : _data.replace(/&/g, '\r\n');
                }
            }
        }
        else {
            postData = options.data;
        }

    }

    // Additional headers
    if (options.headers) {
        for (var header in options.headers) {
            xhr.setRequestHeader(header, options.headers[header]);
        }
    }

    // Check for crossDomain
    if (typeof options.crossDomain === 'undefined') {
        options.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(options.url) && RegExp.$2 !== window.location.host;
    }

    if (!options.crossDomain) {
        xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
    }

    if (options.xhrFields) {
        for (var field in options.xhrFields) {
            xhr[field] = options.xhrFields[field];
        }
    }

    // Handle XHR
    xhr.onload = function (e) {
        if (xhr.status === 200 || xhr.status === 0) {
            $(document).trigger('ajaxSuccess', {xhr: xhr});
            if (options.success) {
                var responseData = xhr.responseText;

                if (options.dataType === 'json') responseData = JSON.parse(responseData);
                options.success(responseData, xhr.status, xhr);
            }
        }
        if (options.statusCode) {
            if (options.statusCode[xhr.status]) options.statusCode[xhr.status](xhr);
        }
        if (options.complete) {
            options.complete(xhr);
        }
        $(document).trigger('ajaxComplete', {xhr: xhr});
    };
    if (options.error) {

    }
    xhr.onerror = function (e) {
        $(document).trigger('ajaxError', {xhr: xhr});
        if (options.error) options.error(xhr);
    };

    // Ajax start callback
    if (options.start) options.start(xhr);

    // Send XHR
    $(document).trigger('ajaxStart', {xhr: xhr});
    xhr.send(postData);

    // Return XHR object
    return xhr;
};
// Shrotcuts
(function () {
    var methods = ('get post getJSON').split(' ');
    function createMethod(method) {
        $[method] = function (url, data, success) {
            return $.ajax({
                url: url,
                method: method === 'post' ? 'POST' : 'GET',
                data: typeof data === 'function' ? undefined : data,
                success: typeof data === 'function' ? data : success,
                dataType: method === 'getJSON' ? 'json' : undefined
            });
        };
    }
    for (var i = 0; i < methods.length; i++) {
        createMethod(methods[i]);
    }
})();
<|endoftext|>


<commit_before>/*!
 * Chameleon
 *
 * Copyright 2014 ghostwords.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

/*
 * Injected via inject.js. Not a content script, no chrome.* API access.
 */

(function () {

	Error.stackTraceLimit = Infinity; // collect all frames

	var event_id = document.currentScript.getAttribute('data-event-id');

	// from underscore-1.6.0.js
	function debounce(func, wait, immediate) {
		var timeout, args, context, timestamp, result;

		var later = function () {
			var last = Date.now() - timestamp;
			if (last < wait) {
				timeout = setTimeout(later, wait - last);
			} else {
				timeout = null;
				if (!immediate) {
					result = func.apply(context, args);
					context = args = null;
				}
			}
		};

		return function () {
			context = this;
			args = arguments;
			timestamp = Date.now();
			var callNow = immediate && !timeout;
			if (!timeout) {
				timeout = setTimeout(later, wait);
			}
			if (callNow) {
				result = func.apply(context, args);
				context = args = null;
			}

			return result;
		};
	}

	// messages the injected script
	var send = (function () {
		var messages = [];

		// debounce sending queued messages
		var _send = debounce(function () {
			document.dispatchEvent(new CustomEvent(event_id, {
				detail: messages
			}));

			// clear the queue
			messages = [];
		}, 100);

		return function (msg) {
			// queue the message
			messages.push(msg);

			_send();
		};
	}());

	// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
	function getStackTrace(structured) {
		var err = {}, // TODO should this be new Error() instead?
			origFormatter,
			stack;

		if (structured) {
			origFormatter = Error.prepareStackTrace;
			Error.prepareStackTrace = function (err, structuredStackTrace) {
				return structuredStackTrace;
			};
		}

		Error.captureStackTrace(err, getStackTrace);
		stack = err.stack;

		if (structured) {
			Error.prepareStackTrace = origFormatter;
		}

		return stack;
	}

	/* TODO doesn't work when the stack trace contains <anonymous> fileNames
	for example: http://blogs.wsj.com/digits/2014/07/16/newest-hit-game-maker-machine-zone-nears-3-billion-valuation/
		at Navigator.Object.defineProperty.get [as userAgent] (chrome-extension://.../js/builds/injected.min.js:2:1027)
		at Object.self.doTag (<anonymous>:33:1230)
		at bk_doSendData (<anonymous>:33:2259)
		at Object.blueKai.blueKai.sendBlueKai (<anonymous>:55:3)
		at Object.blueKai.blueKai.getAdsData (<anonymous>:147:8)
		at <anonymous>:1:17
	seems related to setTimeout use */
	function getOriginatingScriptUrl() {
		// this script is at 0 and 1
		var callSite = getStackTrace(true)[2];

		if (callSite.isEval()) {
			// argh, getEvalOrigin returns a string ...
			return callSite.getEvalOrigin().match(/\((http.*)\)$/)[1];
		} else {
			return callSite.getFileName() + ':' + callSite.getLineNumber() + ':' + callSite.getColumnNumber();
		}
	}

	function stripLineAndColumnNumbers(script_url) {
		return script_url.replace(/:\d+:\d+$/, '');
	}

	function getObjectName(o) {
		return o.toString().replace(/^\[object ([^\]]+)\]/, '$1');
	}

	function trap(obj, prop, override) {
		var desc = Object.getOwnPropertyDescriptor(obj, prop);

		if (desc && !desc.configurable) {
			console.log("%s.%s is not configurable", obj, prop);
			return;
		}

		var orig_val = obj[prop];

		//if (orig_val == console || orig_val == console.log) {
		//	return;
		//}

		//console.log("trapping %s.%s ...", obj, prop);

		Object.defineProperty(obj, prop, {
			get: function () {
				var script_url = getOriginatingScriptUrl();

				console.log("%s.%s prop access: %s", obj, prop, script_url);

				send({
					obj: getObjectName(obj),
					prop: prop.toString(),
					scriptUrl: stripLineAndColumnNumbers(script_url)
				});

				if (override !== undefined) {
					return override;
				}

				return orig_val;
			}
		});
	}

	// define nonexistent-in-Chrome properties (to match Tor Browser)
	// TODO merge into trap()
	window.navigator.buildID = "20000101000000";
	window.navigator.oscpu = "Windows NT 6.1";

	// JS objects to trap along with properties to override
	[
		{
			obj: window.navigator,
			overrides: {
				appCodeName: "Mozilla",
				appName: "Netscape",
				appVersion: "5.0 (Windows)",
				doNotTrack: "unspecified",
				// TODO not overridable?
				//javaEnabled: function () {
				//	return false;
				//},
				language: "en-US",
				mimeTypes: {
					length: 0
				},
				platform: "Win32",
				plugins: {
					length: 0,
					refresh: function () {}
				},
				userAgent: "Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0",
				vendor: ""
			}
		},
		{
			obj: window.screen,
			overrides: {
				availWidth: 1000,
				availHeight: 700,
				width: 1000,
				height: 700,
				colorDepth: 24
			}
		}
	].forEach(function (item) {
		Object.keys(item.obj).forEach(function (prop) {
			trap(item.obj, prop, item.overrides[prop]);
		});
	});
	trap(window, 'innerWidth', 1000);
	trap(window, 'innerHeight', 700);

	// override instance methods
	// override Date
	// TODO merge into trap()
	window.Date.prototype.getTimezoneOffset = function () {
		var script_url = getOriginatingScriptUrl();

		console.log("Date.prototype.getTimezoneOffset prop access: %s", script_url);

		send({
			obj: 'Date.prototype',
			prop: 'getTimezoneOffset',
			scriptUrl: stripLineAndColumnNumbers(script_url)
		});

		return 0;
	};
	// TODO Tor also changes the time to match timezone 0 (getHours(), etc.)

	// handle canvas-based fingerprinting
	HTMLCanvasElement.prototype.toDataURL = (function (orig) {
		// TODO merge into trap()
		return function () {
			var script_url = getOriginatingScriptUrl();

			console.log("HTMLCanvasElement.prototype.toDataURL prop access: %s", script_url);

			send({
				obj: 'HTMLCanvasElement.prototype',
				prop: 'toDataURL',
				scriptUrl: stripLineAndColumnNumbers(script_url)
			});

			// TODO detection only for now ... to protect, need to generate an
			// TODO empty canvas with matching dimensions, but Chrome and
			// TODO Firefox produce different PNGs from same inputs somehow
			//c.setAttribute('width', this.width);
			//c.setAttribute('height', this.height);

			return orig.apply(this, arguments);
		};
	}(HTMLCanvasElement.prototype.toDataURL));

	// detect font enumeration
	var observer = new MutationObserver(function (mutations) {
		for (var i = 0; i < mutations.length; i++) {
			var mutation = mutations[i];

			if (!mutation.oldValue || mutation.oldValue.indexOf('font-family: ') == -1) {
				continue;
			}

			var target = mutation.target,
				old_font = mutation.oldValue.match(/font-family: ([^;]+);/)[1],
				fonts = [];

			// TODO switch to WeakMaps
			// TODO https://github.com/Benvie/WeakMap
			// TODO https://gist.github.com/Gozala/1269991
			if (!(event_id in target.dataset)) {
				target.dataset[event_id] = '';
			} else {
				fonts = target.dataset[event_id].split(';');
			}

			if (fonts.indexOf(old_font) == -1) {
				fonts.push(old_font);
			}

			console.log(fonts); // TODO

			if (fonts.length > 2) {
				console.log(mutation); // TODO

				// TODO since MutationObserver is async, a stack trace now
				// TODO won't get us the script that originated the scanning
				send({
					obj: getObjectName(target),
					prop: 'style.fontFamily'
				});

				// no need to keep listening
				observer.disconnect();

				break;
			}

			target.dataset[event_id] = fonts.join(';');
		}
	});
	observer.observe(document, {
		attribute: true,
		// TODO more precise filtering?
		attributeFilter: ['style'],
		attributeOldValue: true,
		childList: false,
		subtree: true
	});

}());
<commit_msg>Note another getOriginatingScriptUrl bug.<commit_after>/*!
 * Chameleon
 *
 * Copyright 2014 ghostwords.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

/*
 * Injected via inject.js. Not a content script, no chrome.* API access.
 */

(function () {

	Error.stackTraceLimit = Infinity; // collect all frames

	var event_id = document.currentScript.getAttribute('data-event-id');

	// from underscore-1.6.0.js
	function debounce(func, wait, immediate) {
		var timeout, args, context, timestamp, result;

		var later = function () {
			var last = Date.now() - timestamp;
			if (last < wait) {
				timeout = setTimeout(later, wait - last);
			} else {
				timeout = null;
				if (!immediate) {
					result = func.apply(context, args);
					context = args = null;
				}
			}
		};

		return function () {
			context = this;
			args = arguments;
			timestamp = Date.now();
			var callNow = immediate && !timeout;
			if (!timeout) {
				timeout = setTimeout(later, wait);
			}
			if (callNow) {
				result = func.apply(context, args);
				context = args = null;
			}

			return result;
		};
	}

	// messages the injected script
	var send = (function () {
		var messages = [];

		// debounce sending queued messages
		var _send = debounce(function () {
			document.dispatchEvent(new CustomEvent(event_id, {
				detail: messages
			}));

			// clear the queue
			messages = [];
		}, 100);

		return function (msg) {
			// queue the message
			messages.push(msg);

			_send();
		};
	}());

	// http://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
	function getStackTrace(structured) {
		var err = {}, // TODO should this be new Error() instead?
			origFormatter,
			stack;

		if (structured) {
			origFormatter = Error.prepareStackTrace;
			Error.prepareStackTrace = function (err, structuredStackTrace) {
				return structuredStackTrace;
			};
		}

		Error.captureStackTrace(err, getStackTrace);
		stack = err.stack;

		if (structured) {
			Error.prepareStackTrace = origFormatter;
		}

		return stack;
	}

	/*
	TODO Doesn't work when the stack trace contains <anonymous> fileNames.
	For example: http://blogs.wsj.com/digits/2014/07/16/newest-hit-game-maker-machine-zone-nears-3-billion-valuation/
		at Navigator.Object.defineProperty.get [as userAgent] (chrome-extension://.../js/builds/injected.min.js:2:1027)
		at Object.self.doTag (<anonymous>:33:1230)
		at bk_doSendData (<anonymous>:33:2259)
		at Object.blueKai.blueKai.sendBlueKai (<anonymous>:55:3)
		at Object.blueKai.blueKai.getAdsData (<anonymous>:147:8)
		at <anonymous>:1:17
	Seems related to setTimeout use.

	TODO Doesn't work when the script gets loaded via eval.
	For example, see globalEval in http://code.jquery.com/jquery-1.6.4.js,
	used on http://fingerprint.pet-portal.eu/, apparently here:
		$.get("?controller=fingerprint&t="+(new Date().getTime()), function(data) {
			$('body').append(data);
		});
	The stack trace:
		at Navigator.Object.defineProperty.get [as language] (chrome-extension://.../js/builds/injected.min.js:2:1020)
		at start_test (eval at <anonymous> (eval at <anonymous> (http://fingerprint.pet-portal.eu/javascript/jquery.min.js:2:12388)), <anonymous>:1:1079)
	Appears to be double eval'd: once by jQuery and again by Dean Edwards' Packer.
	Another eval'd script example here: http://lomavistarecordings.com/
	*/
	function getOriginatingScriptUrl() {
		// this script is at 0 and 1
		var callSite = getStackTrace(true)[2];

		if (callSite.isEval()) {
			// argh, getEvalOrigin returns a string ...
			return callSite.getEvalOrigin().match(/\((http.*)\)$/)[1];
		} else {
			return callSite.getFileName() + ':' + callSite.getLineNumber() + ':' + callSite.getColumnNumber();
		}
	}

	function stripLineAndColumnNumbers(script_url) {
		return script_url.replace(/:\d+:\d+$/, '');
	}

	function getObjectName(o) {
		return o.toString().replace(/^\[object ([^\]]+)\]/, '$1');
	}

	function trap(obj, prop, override) {
		var desc = Object.getOwnPropertyDescriptor(obj, prop);

		if (desc && !desc.configurable) {
			console.log("%s.%s is not configurable", obj, prop);
			return;
		}

		var orig_val = obj[prop];

		//if (orig_val == console || orig_val == console.log) {
		//	return;
		//}

		//console.log("trapping %s.%s ...", obj, prop);

		Object.defineProperty(obj, prop, {
			get: function () {
				var script_url = getOriginatingScriptUrl();

				console.log("%s.%s prop access: %s", obj, prop, script_url);

				send({
					obj: getObjectName(obj),
					prop: prop.toString(),
					scriptUrl: stripLineAndColumnNumbers(script_url)
				});

				if (override !== undefined) {
					return override;
				}

				return orig_val;
			}
		});
	}

	// define nonexistent-in-Chrome properties (to match Tor Browser)
	// TODO merge into trap()
	window.navigator.buildID = "20000101000000";
	window.navigator.oscpu = "Windows NT 6.1";

	// JS objects to trap along with properties to override
	[
		{
			obj: window.navigator,
			overrides: {
				appCodeName: "Mozilla",
				appName: "Netscape",
				appVersion: "5.0 (Windows)",
				doNotTrack: "unspecified",
				// TODO not overridable?
				//javaEnabled: function () {
				//	return false;
				//},
				language: "en-US",
				mimeTypes: {
					length: 0
				},
				platform: "Win32",
				plugins: {
					length: 0,
					refresh: function () {}
				},
				userAgent: "Mozilla/5.0 (Windows NT 6.1; rv:24.0) Gecko/20100101 Firefox/24.0",
				vendor: ""
			}
		},
		{
			obj: window.screen,
			overrides: {
				availWidth: 1000,
				availHeight: 700,
				width: 1000,
				height: 700,
				colorDepth: 24
			}
		}
	].forEach(function (item) {
		Object.keys(item.obj).forEach(function (prop) {
			trap(item.obj, prop, item.overrides[prop]);
		});
	});
	trap(window, 'innerWidth', 1000);
	trap(window, 'innerHeight', 700);

	// override instance methods
	// override Date
	// TODO merge into trap()
	window.Date.prototype.getTimezoneOffset = function () {
		var script_url = getOriginatingScriptUrl();

		console.log("Date.prototype.getTimezoneOffset prop access: %s", script_url);

		send({
			obj: 'Date.prototype',
			prop: 'getTimezoneOffset',
			scriptUrl: stripLineAndColumnNumbers(script_url)
		});

		return 0;
	};
	// TODO Tor also changes the time to match timezone 0 (getHours(), etc.)

	// handle canvas-based fingerprinting
	HTMLCanvasElement.prototype.toDataURL = (function (orig) {
		// TODO merge into trap()
		return function () {
			var script_url = getOriginatingScriptUrl();

			console.log("HTMLCanvasElement.prototype.toDataURL prop access: %s", script_url);

			send({
				obj: 'HTMLCanvasElement.prototype',
				prop: 'toDataURL',
				scriptUrl: stripLineAndColumnNumbers(script_url)
			});

			// TODO detection only for now ... to protect, need to generate an
			// TODO empty canvas with matching dimensions, but Chrome and
			// TODO Firefox produce different PNGs from same inputs somehow
			//c.setAttribute('width', this.width);
			//c.setAttribute('height', this.height);

			return orig.apply(this, arguments);
		};
	}(HTMLCanvasElement.prototype.toDataURL));

	// detect font enumeration
	var observer = new MutationObserver(function (mutations) {
		for (var i = 0; i < mutations.length; i++) {
			var mutation = mutations[i];

			if (!mutation.oldValue || mutation.oldValue.indexOf('font-family: ') == -1) {
				continue;
			}

			var target = mutation.target,
				old_font = mutation.oldValue.match(/font-family: ([^;]+);/)[1],
				fonts = [];

			// TODO switch to WeakMaps
			// TODO https://github.com/Benvie/WeakMap
			// TODO https://gist.github.com/Gozala/1269991
			if (!(event_id in target.dataset)) {
				target.dataset[event_id] = '';
			} else {
				fonts = target.dataset[event_id].split(';');
			}

			if (fonts.indexOf(old_font) == -1) {
				fonts.push(old_font);
			}

			console.log(fonts); // TODO

			if (fonts.length > 2) {
				console.log(mutation); // TODO

				// TODO since MutationObserver is async, a stack trace now
				// TODO won't get us the script that originated the scanning
				send({
					obj: getObjectName(target),
					prop: 'style.fontFamily'
				});

				// no need to keep listening
				observer.disconnect();

				break;
			}

			target.dataset[event_id] = fonts.join(';');
		}
	});
	observer.observe(document, {
		attribute: true,
		// TODO more precise filtering?
		attributeFilter: ['style'],
		attributeOldValue: true,
		childList: false,
		subtree: true
	});

}());
<|endoftext|>


<commit_before>/*=========================
  Keyboard Control
  ===========================*/
function handleKeyboard(e) {
    if (e.originalEvent) e = e.originalEvent; //jquery fix
    var kc = e.keyCode || e.charCode;
    if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {
        return;
    }
    if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) {
        return;
    }
    if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
        var inView = false;
        //Check that swiper should be inside of visible area of window
        if (s.container.parents('.swiper-slide').length > 0 && s.container.parents('.swiper-slide-active').length === 0) {
            return;
        }
        var windowScroll = {
            left: window.pageXOffset,
            top: window.pageYOffset
        };
        var windowWidth = window.innerWidth;
        var windowHeight = window.innerHeight;
        var swiperOffset = s.container.offset();

        var swiperCoord = [
            [swiperOffset.left, swiperOffset.top],
            [swiperOffset.left + s.width, swiperOffset.top],
            [swiperOffset.left, swiperOffset.top + s.height],
            [swiperOffset.left + s.width, swiperOffset.top + s.height]
        ];
        for (var i = 0; i < swiperCoord.length; i++) {
            var point = swiperCoord[i];
            if (
                point[0] >= windowScroll.left && point[0] <= windowScroll.left + windowWidth &&
                point[1] >= windowScroll.top && point[1] <= windowScroll.top + windowHeight
            ) {
                inView = true;
            }

        }
        if (!inView) return;
    }
    if (isH()) {
        if (kc === 37 || kc === 39) {
            if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
        }
        if (kc === 39) s.slideNext();
        if (kc === 37) s.slidePrev();
    }
    else {
        if (kc === 38 || kc === 40) {
            if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
        }
        if (kc === 40) s.slideNext();
        if (kc === 38) s.slidePrev();
    }
}
s.disableKeyboardControl = function () {
    $(document).off('keydown', handleKeyboard);
};
s.enableKeyboardControl = function () {
    $(document).on('keydown', handleKeyboard);
};
<commit_msg>Return false in handleKeyboard if keycode matches locked direction<commit_after>/*=========================
  Keyboard Control
  ===========================*/
function handleKeyboard(e) {
    if (e.originalEvent) e = e.originalEvent; //jquery fix
    var kc = e.keyCode || e.charCode;
    // Directions locks
    if (!s.params.allowSwipeToNext && (isH() && kc === 39 || !isH() && kc === 40)) {
        return false;
    }
    if (!s.params.allowSwipeToPrev && (isH() && kc === 37 || !isH() && kc === 38)) {
        return false;
    }
    if (e.shiftKey || e.altKey || e.ctrlKey || e.metaKey) {
        return;
    }
    if (document.activeElement && document.activeElement.nodeName && (document.activeElement.nodeName.toLowerCase() === 'input' || document.activeElement.nodeName.toLowerCase() === 'textarea')) {
        return;
    }
    if (kc === 37 || kc === 39 || kc === 38 || kc === 40) {
        var inView = false;
        //Check that swiper should be inside of visible area of window
        if (s.container.parents('.swiper-slide').length > 0 && s.container.parents('.swiper-slide-active').length === 0) {
            return;
        }
        var windowScroll = {
            left: window.pageXOffset,
            top: window.pageYOffset
        };
        var windowWidth = window.innerWidth;
        var windowHeight = window.innerHeight;
        var swiperOffset = s.container.offset();

        var swiperCoord = [
            [swiperOffset.left, swiperOffset.top],
            [swiperOffset.left + s.width, swiperOffset.top],
            [swiperOffset.left, swiperOffset.top + s.height],
            [swiperOffset.left + s.width, swiperOffset.top + s.height]
        ];
        for (var i = 0; i < swiperCoord.length; i++) {
            var point = swiperCoord[i];
            if (
                point[0] >= windowScroll.left && point[0] <= windowScroll.left + windowWidth &&
                point[1] >= windowScroll.top && point[1] <= windowScroll.top + windowHeight
            ) {
                inView = true;
            }

        }
        if (!inView) return;
    }
    if (isH()) {
        if (kc === 37 || kc === 39) {
            if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
        }
        if (kc === 39) s.slideNext();
        if (kc === 37) s.slidePrev();
    }
    else {
        if (kc === 38 || kc === 40) {
            if (e.preventDefault) e.preventDefault();
            else e.returnValue = false;
        }
        if (kc === 40) s.slideNext();
        if (kc === 38) s.slidePrev();
    }
}
s.disableKeyboardControl = function () {
    $(document).off('keydown', handleKeyboard);
};
s.enableKeyboardControl = function () {
    $(document).on('keydown', handleKeyboard);
};
<|endoftext|>