<commit_before>'use strict';

angular.module('scegratooApp')
  .service('X3domUtils', function X3domutils($window, $routeParams, $templateCache, Constants) {
    // AngularJS will instantiate a singleton by calling "new" on this function
    var vecOffset = {
    	x: 0,
    	y: 0,
    	z: 0,
    }
    var options = {
		  useHitPnt: false,
      snapToGrid: false,
		  x: '',
		  y: '',
		  z: '',
    }
    var inlines
    var crosshairs
    var translationGizmoX
    var translationGizmoY

    var start = function(event) {
      // event.hitPnt is in global space so for this to work one would have to
      // add it to the scene and translate it inside the move function.
      // runtime.getCenter(hitObject) seems to return sth in local space
      // which works
      var runtime = document.querySelector('X3D').runtime
      var translationString = ''
      var inline = event.hitObject
      var next = event.hitObject

      // find top most inline
      while (next.nodeName.toLowerCase() !== 'scene') {
        next = next.parentNode

        if (next.nodeName.toLowerCase() === 'inline') {
          inline = next;
        }
      }

      if (options.useHitPnt) {
        vecOffset = new $window.x3dom.fields.SFVec3f(event.hitPnt[0], event.hitPnt[1], event.hitPnt[2])
      } else {
        vecOffset = runtime.getCenter(inline)
      }

      inline.parentNode.appendChild(crosshairs)
      translationString = vecOffset.x + ' ' + vecOffset.y + ' ' + vecOffset.z
      crosshairs.setAttribute('translation', translationString)
    }

    var move = function(event) {
    }

    var stop = function() {
      if (crosshairs.parentNode) {
        crosshairs.parentNode.removeChild(crosshairs)
      }
    }

    var processTranslationGizmoEventX = function(event) {
        var sensorToWorldMatrix, translationValue;

        if (event.fieldName === 'translation_changed') {
          //convert the sensor's output from sensor coordinates to world coordinates (i.e., include its 'axisRotation')
          sensorToWorldMatrix = $window.x3dom.fields.SFMatrix4f.parseRotation(event.target.getAttribute('axisRotation'));

          translationValue = sensorToWorldMatrix.multMatrixVec(event.value);

          if (options.snapToGrid) {
            translationValue.x = Math.floor(translationValue.x)
          }

          angular.forEach(inlines, function(inline){
            var oldTranslationValue = inline.parentNode.getFieldValue('translation')
            oldTranslationValue.x = translationValue.x
            inline.parentNode.setFieldValue('translation', oldTranslationValue)
          });
        }
    }

    var processTranslationGizmoEventY = function(event) {
        var sensorToWorldMatrix, translationValue;

        if (event.fieldName === 'translation_changed') {
          //convert the sensor's output from sensor coordinates to world coordinates (i.e., include its 'axisRotation')
          sensorToWorldMatrix = $window.x3dom.fields.SFMatrix4f.parseRotation(event.target.getAttribute('axisRotation'));

          translationValue = sensorToWorldMatrix.multMatrixVec(event.value);

          if (options.snapToGrid) {
            translationValue.y = Math.floor(translationValue.y)
          }

          angular.forEach(inlines, function(inline){
            var oldTranslationValue = inline.parentNode.getFieldValue('translation')
            oldTranslationValue.y = translationValue.y
            inline.parentNode.setFieldValue('translation', oldTranslationValue)
          });
        }
    }

    var setUp = function(x3dElement) {
      var loadCount = 0
      console.debug('Set up scene.')

      // fix x3dom swallowing exceptions in callback
      $window.x3dom.debug.logException = function(e) {
        console.error(e.stack)
      }

      crosshairs         = angular.element($templateCache.get('templates/crosshair.html')).get(0);
      translationGizmoX  = angular.element($templateCache.get('templates/planeSensor-X.html')).get(0);
      translationGizmoY  = angular.element($templateCache.get('templates/planeSensor-Y.html')).get(0);

      inlines   = x3dElement.find('inline')

      angular.forEach(inlines, function(inline){
        var url = inline.getAttribute('url')
        inline.setAttribute('url', Constants.apiRoot +
          '/' + 'projects' +
          '/' + $routeParams.project +
          '/' + $routeParams.file.replace(/\/[^\/]*$/, '') +
          '/' + url)
      });

      $window.x3dom.reload()

      angular.forEach(x3dElement.find('scene'), function(scene){
        scene.appendChild(translationGizmoX)
        scene.appendChild(translationGizmoY)
      })

      angular.forEach(inlines, function(inline) {
        inline.addEventListener('mousedown', start)
        inline.addEventListener('mouseup', stop)
        inline.addEventListener('load', function () {
          loadCount += 1
          if (loadCount === inlines.length && x3dElement.children().get(0) && x3dElement.children().get(0).runtime) {
            window.x3dNode = x3dElement.children().get(0)
            x3dElement.children().get(0).runtime.showAll()
          }
        })
        new $window.x3dom.Moveable(x3dElement.children().get(0),
          inline.parentElement, move, 0, 'all')
      });

      translationGizmoX.children[0].addEventListener('onoutputchange', processTranslationGizmoEventX)
      translationGizmoY.children[0].addEventListener('onoutputchange', processTranslationGizmoEventY)

      return options
    }

    return {
      setUp: setUp
    }
  });
<commit_msg>change color of objects while selected<commit_after>'use strict';

angular.module('scegratooApp')
  .service('X3domUtils', function X3domutils($window, $routeParams, $templateCache, Constants, x3dQuery) {
    // AngularJS will instantiate a singleton by calling "new" on this function
    var vecOffset = {
    	x: 0,
    	y: 0,
    	z: 0,
    }
    var options = {
		  useHitPnt: false,
      snapToGrid: false,
		  x: '',
		  y: '',
		  z: '',
    }
    var inlines
    var crosshairs
    var translationGizmoX
    var translationGizmoY
    var colorCache

    var start = function(event) {
      // event.hitPnt is in global space so for this to work one would have to
      // add it to the scene and translate it inside the move function.
      // runtime.getCenter(hitObject) seems to return sth in local space
      // which works
      var translationString = ''
      var inline = x3dQuery(event.hitObject).lastParent('inline')

      if (options.useHitPnt) {
        vecOffset = new $window.x3dom.fields.SFVec3f(event.hitPnt[0], event.hitPnt[1], event.hitPnt[2])
      } else {
        // `runtime.getCenter` does not work with inlines, only with X3DShapeNode and X3DGeometryNode
        // and even for a shape it returns always the same coordinates, so what does it actually return?
        // TODO: test this w/o inlines.
        // vecOffset = runtime.getCenter(inline)
        console.debug(document.getElementsByTagName('shape')[1]._x3domNode.getCenter())

        // on the other hand this is always null
        vecOffset = inline.get()._x3domNode.getVolume().center
      }

      inline.get().parentNode.appendChild(crosshairs)
      translationString = vecOffset.x + ' ' + vecOffset.y + ' ' + vecOffset.z
      crosshairs.setAttribute('translation', translationString)

      colorCache = inline.color()
      inline.color('yellow')
    }

    var move = function(event) {
    }

    var stop = function(event) {
      var inline = x3dQuery(event.hitObject)

      // remove the crosshair
      if (crosshairs.parentNode) {
        crosshairs.parentNode.removeChild(crosshairs)
      }

      inline.color(colorCache)
    }

    var processTranslationGizmoEventX = function(event) {
        var sensorToWorldMatrix, translationValue;

        if (event.fieldName === 'translation_changed') {
          //convert the sensor's output from sensor coordinates to world coordinates (i.e., include its 'axisRotation')
          sensorToWorldMatrix = $window.x3dom.fields.SFMatrix4f.parseRotation(event.target.getAttribute('axisRotation'));

          translationValue = sensorToWorldMatrix.multMatrixVec(event.value);

          if (options.snapToGrid) {
            translationValue.x = Math.floor(translationValue.x)
          }

          angular.forEach(inlines, function(inline){
            var oldTranslationValue = inline.parentNode.getFieldValue('translation')
            oldTranslationValue.x = translationValue.x
            inline.parentNode.setFieldValue('translation', oldTranslationValue)
          });
        }
    }

    var processTranslationGizmoEventY = function(event) {
        var sensorToWorldMatrix, translationValue;

        if (event.fieldName === 'translation_changed') {
          //convert the sensor's output from sensor coordinates to world coordinates (i.e., include its 'axisRotation')
          sensorToWorldMatrix = $window.x3dom.fields.SFMatrix4f.parseRotation(event.target.getAttribute('axisRotation'));

          translationValue = sensorToWorldMatrix.multMatrixVec(event.value);

          if (options.snapToGrid) {
            translationValue.y = Math.floor(translationValue.y)
          }

          angular.forEach(inlines, function(inline){
            var oldTranslationValue = inline.parentNode.getFieldValue('translation')
            oldTranslationValue.y = translationValue.y
            inline.parentNode.setFieldValue('translation', oldTranslationValue)
          });
        }
    }

    var setUp = function(x3dElement) {
      var loadCount = 0
      console.debug('Set up scene.')

      // fix x3dom swallowing exceptions in callback
      $window.x3dom.debug.logException = function(e) {
        console.error(e.stack)
      }

      crosshairs         = angular.element($templateCache.get('templates/crosshair.html')).get(0);
      translationGizmoX  = angular.element($templateCache.get('templates/planeSensor-X.html')).get(0);
      translationGizmoY  = angular.element($templateCache.get('templates/planeSensor-Y.html')).get(0);

      inlines   = x3dElement.find('inline')

      angular.forEach(inlines, function(inline){
        var url = inline.getAttribute('url')
        inline.setAttribute('url', Constants.apiRoot +
          '/' + 'projects' +
          '/' + $routeParams.project +
          '/' + $routeParams.file.replace(/\/[^\/]*$/, '') +
          '/' + url)
      });

      $window.x3dom.reload()

      angular.forEach(x3dElement.find('scene'), function(scene){
        scene.appendChild(translationGizmoX)
        scene.appendChild(translationGizmoY)
      })

      angular.forEach(inlines, function(inline) {
        inline.addEventListener('mousedown', start)
        inline.addEventListener('mouseup', stop)
        inline.addEventListener('load', function () {
          loadCount += 1
          if (loadCount === inlines.length && x3dElement.children().get(0) && x3dElement.children().get(0).runtime) {
            window.x3dNode = x3dElement.children().get(0)
            x3dElement.children().get(0).runtime.showAll()
          }
        })
        new $window.x3dom.Moveable(x3dElement.children().get(0),
          inline.parentElement, move, 0, 'all')
      });

      translationGizmoX.children[0].addEventListener('onoutputchange', processTranslationGizmoEventX)
      translationGizmoY.children[0].addEventListener('onoutputchange', processTranslationGizmoEventY)

      return options
    }

    return {
      setUp: setUp
    }
  });
<|endoftext|>


<commit_before>describe('pascal triangle test', function() {
  it('depth = 5, result length test', function() {
    expect(pascal(5).length).toBe(5);
  });

  it('depth = 100, result length test', function() {
    expect(pascal(100).length).toBe(100);
  });

  it('0', function() {
    expect(pascal(0)).toEqual([]);
  });

  it('1', function() {
    expect(pascal(1)).toEqual([
      [1]
    ]);
  });

  it('2', function() {
    expect(pascal(2)).toEqual([
      [1],
      [1, 1]
    ]);
  });

  it('depth = 5', function() {
    expect(pascal(5)).toEqual([
      [1],
      [1, 1],
      [1, 2, 1],
      [1, 3, 3, 1],
      [1, 4, 6, 4, 1]
    ]);
  });

  it('depth = 6', function() {
    expect(pascal(6)).toEqual([
      [1],
      [1, 1],
      [1, 2, 1],
      [1, 3, 3, 1],
      [1, 4, 6, 4, 1],
      [1, 5, 10, 10, 5, 1]
    ]);
  });

  it('depth = 5', function() {
    expect(pascal(5).toString()).toBe('1,1,1,1,2,1,1,3,3,1,1,4,6,4,1');
  });
});
<commit_msg>pascal tests updated<commit_after>describe('pascal triangle test', function() {
  it('depth = 5, result length test', function() {
    expect(pascal(5).length).toBe(5);
  });

  it('depth = 100, result length test', function() {
    expect(pascal(100).length).toBe(100);
  });

  it('level 100 items count', function() {
    expect(pascal(100)[99].length).toBe(100);
  });

  it('level 3 items count', function() {
    expect(pascal(10)[2].length).toBe(3);
  });

  it('0', function() {
    expect(pascal(0)).toEqual([]);
  });

  it('1', function() {
    expect(pascal(1)).toEqual([
      [1]
    ]);
  });

  it('2', function() {
    expect(pascal(2)).toEqual([
      [1],
      [1, 1]
    ]);
  });

  it('depth = 5', function() {
    expect(pascal(5)).toEqual([
      [1],
      [1, 1],
      [1, 2, 1],
      [1, 3, 3, 1],
      [1, 4, 6, 4, 1]
    ]);
  });

  it('depth = 6', function() {
    expect(pascal(6)).toEqual([
      [1],
      [1, 1],
      [1, 2, 1],
      [1, 3, 3, 1],
      [1, 4, 6, 4, 1],
      [1, 5, 10, 10, 5, 1]
    ]);
  });

  it('depth = 5', function() {
    expect(pascal(5).toString()).toBe('1,1,1,1,2,1,1,3,3,1,1,4,6,4,1');
  });
});
<|endoftext|>


<commit_before>export default class FoodRecallService {

  static get $inject() { return ['openFdaService']; }

  constructor(openFdaService) {
    this.openFdaService = openFdaService;
  }

  // startDate and endDate should be moment objects
  getRecallsByState(startDate, endDate) {

    // prepare the search criteria dates
    let start = startDate.format('YYYYMMDD');
    let end = endDate.format('YYYYMMDD');

    // get the data from the service and process it and return the results
    return this.openFdaService
      .query({
        search: 'report_date:[' + start + ' TO ' + end + ']',
        limit: 100
      })
      .then((results) => this.processRecallsByState(results));
  }

  processRecallsByState(data) {

    // Create a map by state
    let results = this.createResultsMap();

    let states = this.createStateList();

    // Loop over all the recalls passed in
    data.results.forEach((recall) => {
      // For each state
      states.forEach((state) => {
        if (this.appliesToState(state, recall)) {
          results[state.abbr].count++;
        }
      });
    });

    return results;
  }

  // Basic function to check if a recall applies to a state. This will be
  // updated to apply more sophisticated matching.
  appliesToState(state, recall) {

    if (recall.distribution_pattern) {

      // Check the state name
      let nameExpression = new RegExp(`\\b${state.name.replace(' ', '\\s')}\\b`, 'gi');
      // Do a special check for Virginia since west virginia also includes virginia
      if (state.abbr === 'VA') {
        nameExpression = new RegExp(`^(West)\\b${state.name.replace(' ', '\\s')}\\b`, 'gi');
      }
      if (recall.distribution_pattern.match(nameExpression) !== null) {
        return true;
      }

      // Check for the state abbreviation
      let abbrExpression = new RegExp(`\\b${state.abbr}\\b`, 'gi');
      if (recall.distribution_pattern.match(abbrExpression) !== null) {
        return true;
      }

      // Check for the string nationwide (for all states)
      let nationwideExpression = new RegExp(`\\bnationwide\\b`, 'gi');
      if (recall.distribution_pattern.match(nationwideExpression) !== null) {
        return true;
      }
    }

    // Assume it doesn't match
    return false;
  }

  createResultsMap() {

    let map = {};

    this.createStateList().forEach((state) => {
      map[state.abbr] = { state: state, count: 0 };
    });

    return map;
  }

  createStateList() {
    return [
      { name: 'Alabama', abbr: 'AL' },
      { name: 'Alaska', abbr: 'AK' },
      { name: 'Arizona', abbr: 'AZ' },
      { name: 'Arkansas', abbr: 'AR' },
      { name: 'Colorado', abbr: 'CO' },
      { name: 'California', abbr: 'CA' },
      { name: 'Connecticut', abbr: 'CT' },
      { name: 'Delaware', abbr: 'DE' },
      { name: 'District of Columbia', abbr: 'DC' },
      { name: 'Florida', abbr: 'FL' },
      { name: 'Georgia', abbr: 'GA' },
      { name: 'Hawaii', abbr: 'HI' },
      { name: 'Idaho', abbr: 'ID' },
      { name: 'Illinois', abbr: 'IL' },
      { name: 'Indiana', abbr: 'IN' },
      { name: 'Iowa', abbr: 'IA' },
      { name: 'Kansas', abbr: 'KS' },
      { name: 'Kentucky', abbr: 'KY' },
      { name: 'Louisiana', abbr: 'LA' },
      { name: 'Maine', abbr: 'ME' },
      { name: 'Maryland', abbr: 'MD' },
      { name: 'Massachusetts', abbr: 'MA' },
      { name: 'Michigan', abbr: 'MI' },
      { name: 'Minnesota', abbr: 'MN' },
      { name: 'Mississippi', abbr: 'MS' },
      { name: 'Missouri', abbr: 'MO' },
      { name: 'Montana', abbr: 'MT' },
      { name: 'Nebraska', abbr: 'NE' },
      { name: 'Nevada', abbr: 'NV' },
      { name: 'New Hampshire', abbr: 'NH' },
      { name: 'New Jersey', abbr: 'NJ' },
      { name: 'New Mexico', abbr: 'NM' },
      { name: 'New York', abbr: 'NY' },
      { name: 'North Carolina', abbr: 'NC' },
      { name: 'North Dakota', abbr: 'ND' },
      { name: 'Ohio', abbr: 'OH' },
      { name: 'Oklahoma', abbr: 'OK' },
      { name: 'Oregon', abbr: 'OR' },
      { name: 'Pennsylvania', abbr: 'PA' },
      { name: 'Rhode Island', abbr: 'RI' },
      { name: 'South Carolina', abbr: 'SC' },
      { name: 'South Dakota', abbr: 'SD' },
      { name: 'Tennessee', abbr: 'TN' },
      { name: 'Texas', abbr: 'TX' },
      { name: 'Utah', abbr: 'UT' },
      { name: 'Vermont', abbr: 'VT' },
      { name: 'Virginia', abbr: 'VA' },
      { name: 'Washington', abbr: 'WA' },
      { name: 'West Virginia', abbr: 'WV' },
      { name: 'Wisconsin', abbr: 'WI' },
      { name: 'Wyoming', abbr: 'WY' }
    ];

  }
}
<commit_msg>Updated the FoodRecallService to contain an unmatched entry. Also stored references to the recalls associated with the state.<commit_after>export default class FoodRecallService {

  static get $inject() { return ['openFdaService']; }

  constructor(openFdaService) {
    this.openFdaService = openFdaService;

    // The key and state name/abbr for unmatched recalls
    this.UNMATCHED = 'Unmatched';
  }

  // startDate and endDate should be moment objects
  getRecallsByState(startDate, endDate) {

    // prepare the search criteria dates
    let start = startDate.format('YYYYMMDD');
    let end = endDate.format('YYYYMMDD');

    // get the data from the service and process it and return the results
    return this.openFdaService
      .query({
        search: 'report_date:[' + start + ' TO ' + end + ']',
        limit: 100
      })
      .then((results) => this.processRecallsByState(results));
  }

  processRecallsByState(data) {

    // create a map by state
    let results = this.createResultsMap();

    // loop over all the recalls passed in
    data.results.forEach((recall) => {

      let isMatched = false;

      // for each state, see if it matches
      this.createStateList().forEach((state) => {
        if (this.appliesToState(state, recall)) {
          isMatched = true;
          results[state.abbr].count++;
          results[state.abbr].recalls.push(recall);
        }
      });

      // if we didn't match a state, add it to unmatched item
      if (!isMatched) {
        results[this.UNMATCHED].count++;
        results[this.UNMATCHED].recalls.push(recall);
      }

    });

    return results;
  }

  // Basic function to check if a recall applies to a state. This will be
  // updated to apply more sophisticated matching.
  appliesToState(state, recall) {

    if (recall.distribution_pattern) {

      // Check the state name
      let nameExpression = new RegExp(`\\b${state.name.replace(' ', '\\s')}\\b`, 'gi');
      // Do a special check for Virginia since west virginia also includes virginia
      if (state.abbr === 'VA') {
        nameExpression = new RegExp(`^(West)\\b${state.name.replace(' ', '\\s')}\\b`, 'gi');
      }
      if (recall.distribution_pattern.match(nameExpression) !== null) {
        return true;
      }

      // Check for the state abbreviation
      let abbrExpression = new RegExp(`\\b${state.abbr}\\b`, 'gi');
      if (recall.distribution_pattern.match(abbrExpression) !== null) {
        return true;
      }

      // Check for the string nationwide (for all states)
      let nationwideExpression = new RegExp(`\\bnationwide\\b`, 'gi');
      if (recall.distribution_pattern.match(nationwideExpression) !== null) {
        return true;
      }
    }

    // Assume it doesn't match
    return false;
  }

  createResultsMap() {

    let map = { };

    // add a map entry for unmatched entries
    map[this.UNMATCHED] = {
      state: {
        name: this.UNMATCHED,
        abbr: this.UNMATCHED
      },
      count: 0,
      recalls: []
    };

    // Add a map entry for each state
    this.createStateList().forEach((state) => {
      map[state.abbr] = {
        state: state,
        count: 0,
        recalls: []
      };
    });

    return map;
  }

  createStateList() {
    return [
      { name: 'Alabama', abbr: 'AL' },
      { name: 'Alaska', abbr: 'AK' },
      { name: 'Arizona', abbr: 'AZ' },
      { name: 'Arkansas', abbr: 'AR' },
      { name: 'Colorado', abbr: 'CO' },
      { name: 'California', abbr: 'CA' },
      { name: 'Connecticut', abbr: 'CT' },
      { name: 'Delaware', abbr: 'DE' },
      { name: 'District of Columbia', abbr: 'DC' },
      { name: 'Florida', abbr: 'FL' },
      { name: 'Georgia', abbr: 'GA' },
      { name: 'Hawaii', abbr: 'HI' },
      { name: 'Idaho', abbr: 'ID' },
      { name: 'Illinois', abbr: 'IL' },
      { name: 'Indiana', abbr: 'IN' },
      { name: 'Iowa', abbr: 'IA' },
      { name: 'Kansas', abbr: 'KS' },
      { name: 'Kentucky', abbr: 'KY' },
      { name: 'Louisiana', abbr: 'LA' },
      { name: 'Maine', abbr: 'ME' },
      { name: 'Maryland', abbr: 'MD' },
      { name: 'Massachusetts', abbr: 'MA' },
      { name: 'Michigan', abbr: 'MI' },
      { name: 'Minnesota', abbr: 'MN' },
      { name: 'Mississippi', abbr: 'MS' },
      { name: 'Missouri', abbr: 'MO' },
      { name: 'Montana', abbr: 'MT' },
      { name: 'Nebraska', abbr: 'NE' },
      { name: 'Nevada', abbr: 'NV' },
      { name: 'New Hampshire', abbr: 'NH' },
      { name: 'New Jersey', abbr: 'NJ' },
      { name: 'New Mexico', abbr: 'NM' },
      { name: 'New York', abbr: 'NY' },
      { name: 'North Carolina', abbr: 'NC' },
      { name: 'North Dakota', abbr: 'ND' },
      { name: 'Ohio', abbr: 'OH' },
      { name: 'Oklahoma', abbr: 'OK' },
      { name: 'Oregon', abbr: 'OR' },
      { name: 'Pennsylvania', abbr: 'PA' },
      { name: 'Rhode Island', abbr: 'RI' },
      { name: 'South Carolina', abbr: 'SC' },
      { name: 'South Dakota', abbr: 'SD' },
      { name: 'Tennessee', abbr: 'TN' },
      { name: 'Texas', abbr: 'TX' },
      { name: 'Utah', abbr: 'UT' },
      { name: 'Vermont', abbr: 'VT' },
      { name: 'Virginia', abbr: 'VA' },
      { name: 'Washington', abbr: 'WA' },
      { name: 'West Virginia', abbr: 'WV' },
      { name: 'Wisconsin', abbr: 'WI' },
      { name: 'Wyoming', abbr: 'WY' }
    ];

  }
}
<|endoftext|>


<commit_before>"use strict";

var vertexShader = `#version 300 es
#line 5
// Create a static triangle strip covering the entire viewport
const vec4 SCREEN_QUAD[4] = vec4[4](
  vec4(-1, -1, 0.5, 1),
  vec4( 1, -1, 0.5, 1),
  vec4(-1,  1, 0.5, 1),
  vec4( 1,  1, 0.5, 1));
// interpolate the corner positions
const vec2 SCREEN_COORD[4] = vec2[4](
  vec2(-1, -1),
  vec2( 1, -1),
  vec2(-1,  1),
  vec2( 1,  1));

uniform float zoom; // half-screens per radian

out vec2 screen_xy;

void main() {
  gl_Position = SCREEN_QUAD[gl_VertexID];
  // scale the corner locations to apply the current zoom level, in half-screens per radian
  screen_xy = SCREEN_COORD[gl_VertexID] / zoom;
}
`;

var fragmentShader = `#version 300 es
#line 31
precision highp float;

// keep these projection indices in sync with javascript declarations, below...
const int EQUIRECTANGULAR = 1;
const int ORTHOGRAPHIC = 2;

uniform sampler2D world_texture;
uniform int projection;
uniform mat3 rotation;

in vec2 screen_xy;

out vec4 out_color;

const float PI = 3.14159265359;

// Convert points on the unit sphere to longituded and latitude angles, in radians
vec2 longlatFromXyz(in vec3 xyz) {
  float r = length(xyz.xz);
  return vec2(atan(xyz.x, xyz.z),
              atan(xyz.y, r));
}

// Convert from input equirectangular image, to unit sphere surface xyz
vec2 texCoordFromXyz(in vec3 xyz) {
  vec2 longlat = longlatFromXyz(xyz);
  vec2 uv = vec2(
    0.5 + 0.5 * longlat.x / PI,
    0.5 + -longlat.y / PI);
  return uv;
}

// Deproject equirectangular
vec3 sphereFromEquirectangular(in vec2 screenXy) {
  float lat = screenXy.y;
  if (abs(lat) > 0.5 * PI) discard;
  float y = sin(lat);
  float lon = screenXy.x;
  float s = cos(lat);
  float x = s * sin(lon);
  float z = s * cos(lon);
  return vec3(x, y, z);
}

// Deproject orthographic
vec3 sphereFromOrthographic(in vec2 screenXy) {
  float y = screenXy.y;
  float x = screenXy.x;
  float z = 1.0 - x*x - y*y;
  if (z < 0.0) discard;
  z = sqrt(z);
  return vec3(x, y, z);
}

void main() {
  // Choose the map projection
  vec3 xyz;
  if (projection == EQUIRECTANGULAR)
    xyz = sphereFromEquirectangular(screen_xy);
  else
    xyz = sphereFromOrthographic(screen_xy);

  // Center on the current geographic location
  xyz = rotation * xyz;

  // Fetch the color from the world image
  vec2 uv = texCoordFromXyz(xyz);
  out_color =
      texture(world_texture, uv);
}
`;

var EQUIRECTANGULAR = 1;
var ORTHOGRAPHIC = 2;

var gl = null;
var vao = null;
var program = null;
var world_texture = null;
var zoom_loc = -1;
var zoom = 1.0; // half-screens per radian
var projection_loc = -1;
var projection = ORTHOGRAPHIC;
var rotation_loc = -1;
var rotation = [1.0, 0.0, 0.0,
                0.0, 1.0, 0.0,
                0.0, 0.0, 1.0];

// verify whether the canvas size matches the current browser window size
function resize(canvas) {
  // Lookup the size the browser is displaying the canvas.
  var displayWidth  = ~~(0.9 * canvas.clientWidth);
  var displayHeight = ~~(0.9 * canvas.clientHeight);

  // Check if the canvas is not the same size.
  if (canvas.width  != displayWidth ||
      canvas.height != displayHeight) {

    // Make the canvas the same size
    canvas.width  = displayWidth;
    canvas.height = displayHeight;
  }
}

// first time setup of opengl state
function initGL(canvas) {
  gl = canvas.getContext("webgl2");
  if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
    return;
  }
  gl.clearColor(0.2, 0.2, 0.2, 1.0);
  gl.disable(gl.DEPTH_TEST);
  vao = gl.createVertexArray(); // webgl2 only
  gl.bindVertexArray(vao);
  var vs = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vs, vertexShader);
  gl.compileShader(vs);
  // Check if it compiled
  var success = gl.getShaderParameter(vs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(vs);
  }
  var fs = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fs, fragmentShader);
  gl.compileShader(fs);
  // Check if it compiled
  success = gl.getShaderParameter(fs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(fs);
  }
  program = gl.createProgram();
  gl.attachShader(program, vs);
  gl.attachShader(program, fs);
  gl.linkProgram(program);
  success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!success) {
      // something went wrong with the link
      throw ("program filed to link:" + gl.getProgramInfoLog (program));
  }
  var world_texture_loc = gl.getUniformLocation(program, 'world_texture');

  zoom_loc = gl.getUniformLocation(program, 'zoom');
  projection_loc = gl.getUniformLocation(program, 'projection');
  rotation_loc = gl.getUniformLocation(program, 'rotation');

  gl.useProgram(program);
  gl.uniform1i(world_texture_loc, 0);
  gl.uniform1f(zoom_loc, zoom);
  world_texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
}

// draw the earth
function drawScene() {
  resize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.bindVertexArray(vao);
  gl.useProgram(program);

  gl.uniform1f(zoom_loc, zoom);
  gl.uniform1i(projection_loc, projection)
  gl.uniformMatrix3fv(rotation_loc, false, rotation);

  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(drawScene);
}

// change the current map projection
function projectionChanged(selectObject) {
  if (selectObject.value == 'equirectangular') {
    projection = EQUIRECTANGULAR;
  }
  else {
    projection = ORTHOGRAPHIC;
  }
}

// begin drawing the earth for the first time
function globeviewStart() {
  var canvas = document.getElementById("globeview_canvas");
  initGL(canvas);
  // Load the satellite picture of the earth
  var image = new Image();
  image.src = 'world.topo.bathy.200411.3x5400x2700.jpg';
  image.onload = function() {
    gl.texImage2D(gl.TEXTURE_2D,
      0, // mipLevel
      gl.RGB, // internalFormat,
      gl.RGB, // source format,
      gl.UNSIGNED_BYTE,
      image);
    gl.generateMipmap(gl.TEXTURE_2D);
    requestAnimationFrame(drawScene);
  }

  // use mouse scroll wheel to zoom in and out
  function scrollZoom(event) {
    event.preventDefault();
    var e = window.event || event;
    var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
    if (delta > 0) {
      zoom *= 1.1;
    }
    else {
      zoom *= 1.0/1.1;
    }
    return false;
  }
  canvas.addEventListener('mousewheel', scrollZoom, false);
  canvas.addEventListener('DOMMouseScroll', scrollZoom, false);

  // drag mouse to shift center location
  var dragX = 0;
  var dragY = 0;
  canvas.addEventListener('dragstart', function(event) {
    dragX = event.screenX;
    dragY = event.screenY;
    // event.preventDefault();
  }, false);
  canvas.addEventListener('drag', function(event) {
    var dx = event.screenX - dragX;
    var dy = event.screenY - dragY;
    if ((dx == 0) && (dy == 0)) return; // no change
    dragX = event.screenX;
    dragY = event.screenY;
    if (Math.abs(dx) > 30) return; // too much
    if (Math.abs(dy) > 30) return; // too much
    // console.log('%d, %d', dx, dy)
    // todo:
    event.preventDefault();
  }, false);
}
<commit_msg>Replace var with const<commit_after>"use strict";

// Define GLSL shader programs as strings
const vertexShader = `#version 300 es
#line 6
// Create a static triangle strip covering the entire viewport
const vec4 SCREEN_QUAD[4] = vec4[4](
  vec4(-1, -1, 0.5, 1),
  vec4( 1, -1, 0.5, 1),
  vec4(-1,  1, 0.5, 1),
  vec4( 1,  1, 0.5, 1));
// interpolate the corner positions
const vec2 SCREEN_COORD[4] = vec2[4](
  vec2(-1, -1),
  vec2( 1, -1),
  vec2(-1,  1),
  vec2( 1,  1));

uniform float zoom; // half-screens per radian

out vec2 screen_xy;

void main() {
  gl_Position = SCREEN_QUAD[gl_VertexID];
  // scale the corner locations to apply the current zoom level, in half-screens per radian
  screen_xy = SCREEN_COORD[gl_VertexID] / zoom;
}
`;

const fragmentShader = `#version 300 es
#line 32
precision highp float;

// keep these projection indices in sync with javascript declarations, below...
const int EQUIRECTANGULAR = 1;
const int ORTHOGRAPHIC = 2;

uniform sampler2D world_texture;
uniform int projection;
uniform mat3 rotation;

in vec2 screen_xy;

out vec4 out_color;

const float PI = 3.14159265359;

// Convert points on the unit sphere to longituded and latitude angles, in radians
vec2 longlatFromXyz(in vec3 xyz) {
  float r = length(xyz.xz);
  return vec2(atan(xyz.x, xyz.z),
              atan(xyz.y, r));
}

// Convert from input equirectangular image, to unit sphere surface xyz
vec2 texCoordFromXyz(in vec3 xyz) {
  vec2 longlat = longlatFromXyz(xyz);
  vec2 uv = vec2(
    0.5 + 0.5 * longlat.x / PI,
    0.5 + -longlat.y / PI);
  return uv;
}

// Deproject equirectangular
vec3 sphereFromEquirectangular(in vec2 screenXy) {
  float lat = screenXy.y;
  if (abs(lat) > 0.5 * PI) discard;
  float y = sin(lat);
  float lon = screenXy.x;
  float s = cos(lat);
  float x = s * sin(lon);
  float z = s * cos(lon);
  return vec3(x, y, z);
}

// Deproject orthographic
vec3 sphereFromOrthographic(in vec2 screenXy) {
  float y = screenXy.y;
  float x = screenXy.x;
  float z = 1.0 - x*x - y*y;
  if (z < 0.0) discard;
  z = sqrt(z);
  return vec3(x, y, z);
}

void main() {
  // Choose the map projection
  vec3 xyz;
  if (projection == EQUIRECTANGULAR)
    xyz = sphereFromEquirectangular(screen_xy);
  else
    xyz = sphereFromOrthographic(screen_xy);

  // Center on the current geographic location
  xyz = rotation * xyz;

  // Fetch the color from the world image
  vec2 uv = texCoordFromXyz(xyz);
  out_color =
      texture(world_texture, uv);
}
`;

// assign a unique index to each projection, for communicating between javascript and GLSL
const EQUIRECTANGULAR = 1;
const ORTHOGRAPHIC = 2;

var gl = null; // OpenGL context
var vao = null; // OpenGL vertex array object
var program = null; // GLSL shader program handle
var world_texture = null; // Satellite image
// GLSL uniform parameters below
var zoom_loc = -1;
var zoom = 1.0; // half-screens per radian
var projection_loc = -1;
var projection = ORTHOGRAPHIC;
var rotation_loc = -1;
var rotation = [1.0, 0.0, 0.0,
                0.0, 1.0, 0.0,
                0.0, 0.0, 1.0];

// verify whether the canvas size matches the current browser window size
function resize(canvas) {
  // Lookup the size the browser is displaying the canvas.
  const displayWidth  = ~~(0.9 * canvas.clientWidth);
  const displayHeight = ~~(0.9 * canvas.clientHeight);

  // Check if the canvas is not the same size.
  if (canvas.width  != displayWidth ||
      canvas.height != displayHeight) {

    // Make the canvas the same size
    canvas.width  = displayWidth;
    canvas.height = displayHeight;
  }
}

// first time setup of opengl state
function initGL(canvas) {
  gl = canvas.getContext("webgl2");
  if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
    return;
  }
  gl.clearColor(0.2, 0.2, 0.2, 1.0);
  gl.disable(gl.DEPTH_TEST);
  vao = gl.createVertexArray(); // webgl2 only
  gl.bindVertexArray(vao);
  const vs = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vs, vertexShader);
  gl.compileShader(vs);
  // Check if it compiled
  var success = gl.getShaderParameter(vs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(vs);
  }
  const fs = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fs, fragmentShader);
  gl.compileShader(fs);
  // Check if it compiled
  success = gl.getShaderParameter(fs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(fs);
  }
  program = gl.createProgram();
  gl.attachShader(program, vs);
  gl.attachShader(program, fs);
  gl.linkProgram(program);
  success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!success) {
      // something went wrong with the link
      throw ("program filed to link:" + gl.getProgramInfoLog (program));
  }
  const world_texture_loc = gl.getUniformLocation(program, 'world_texture');

  zoom_loc = gl.getUniformLocation(program, 'zoom');
  projection_loc = gl.getUniformLocation(program, 'projection');
  rotation_loc = gl.getUniformLocation(program, 'rotation');

  gl.useProgram(program);
  gl.uniform1i(world_texture_loc, 0);
  gl.uniform1f(zoom_loc, zoom);
  world_texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
}

// draw the earth
function drawScene() {
  resize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.bindVertexArray(vao);
  gl.useProgram(program);

  gl.uniform1f(zoom_loc, zoom);
  gl.uniform1i(projection_loc, projection)
  gl.uniformMatrix3fv(rotation_loc, false, rotation);

  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(drawScene);
}

// change the current map projection
function projectionChanged(selectObject) {
  if (selectObject.value == 'equirectangular') {
    projection = EQUIRECTANGULAR;
  }
  else {
    projection = ORTHOGRAPHIC;
  }
}

// begin drawing the earth for the first time
function globeviewStart() {
  const canvas = document.getElementById("globeview_canvas");
  initGL(canvas);
  // Load the satellite picture of the earth
  const image = new Image();
  image.src = 'world.topo.bathy.200411.3x5400x2700.jpg';
  image.onload = function() {
    gl.texImage2D(gl.TEXTURE_2D,
      0, // mipLevel
      gl.RGB, // internalFormat,
      gl.RGB, // source format,
      gl.UNSIGNED_BYTE,
      image);
    gl.generateMipmap(gl.TEXTURE_2D);
    requestAnimationFrame(drawScene);
  }

  // use mouse scroll wheel to zoom in and out
  function scrollZoom(event) {
    event.preventDefault();
    const e = window.event || event;
    const delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
    if (delta > 0) {
      zoom *= 1.1;
    }
    else {
      zoom *= 1.0/1.1;
    }
    return false;
  }
  canvas.addEventListener('mousewheel', scrollZoom, false);
  canvas.addEventListener('DOMMouseScroll', scrollZoom, false);

  // drag mouse to shift center location
  var dragX = 0;
  var dragY = 0;
  canvas.addEventListener('dragstart', function(event) {
    dragX = event.screenX;
    dragY = event.screenY;
    // event.preventDefault();
  }, false);
  canvas.addEventListener('drag', function(event) {
    const dx = event.screenX - dragX;
    const dy = event.screenY - dragY;
    if ((dx == 0) && (dy == 0)) return; // no change
    dragX = event.screenX;
    dragY = event.screenY;
    if (Math.abs(dx) > 30) return; // too much
    if (Math.abs(dy) > 30) return; // too much
    // console.log('%d, %d', dx, dy)
    // todo:
    event.preventDefault();
  }, false);
}
<|endoftext|>


<commit_before>import Ember from "ember-metal/core"; // FEATURES
import { set } from "ember-metal/property_set";

import EmberLocation from "ember-routing/location/api";
import HistoryLocation from "ember-routing/location/history_location";
import HashLocation from "ember-routing/location/hash_location";
import NoneLocation from "ember-routing/location/none_location";

import environment from "ember-metal/environment";
import { supportsHashChange, supportsHistory } from "ember-routing/location/feature_detect";

/**
@module ember
@submodule ember-routing
*/

/**
  Ember.AutoLocation will select the best location option based off browser
  support with the priority order: history, hash, none.

  Clean pushState paths accessed by hashchange-only browsers will be redirected
  to the hash-equivalent and vice versa so future transitions are consistent.

  Keep in mind that since some of your users will use `HistoryLocation`, your
  server must serve the Ember app at all the routes you define.

  @class AutoLocation
  @namespace Ember
  @static
*/
export default {

  /**
    @private

    This property is used by router:main to know whether to cancel the routing
    setup process, which is needed while we redirect the browser.

    @since 1.5.1
    @property cancelRouterSetup
    @default false
  */
  cancelRouterSetup: false,

  /**
    @private

    Will be pre-pended to path upon state change.

    @since 1.5.1
    @property rootURL
    @default '/'
  */
  rootURL: '/',

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _HistoryLocation
    @default Ember.HistoryLocation
  */
  _HistoryLocation: HistoryLocation,

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _HashLocation
    @default Ember.HashLocation
  */
  _HashLocation: HashLocation,

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _NoneLocation
    @default Ember.NoneLocation
  */
  _NoneLocation: NoneLocation,

  /**
    @private

    Returns location.origin or builds it if device doesn't support it.

    @method _getOrigin
  */
  _getOrigin: function () {
    var location = this._location;
    var origin = location.origin;

    // Older browsers, especially IE, don't have origin
    if (!origin) {
      origin = location.protocol + '//' + location.hostname;

      if (location.port) {
        origin += ':' + location.port;
      }
    }

    return origin;
  },

  _userAgent: environment.userAgent,

  /**
    @private

    @method _getSupportsHistory
  */
  _getSupportsHistory: function () {
    return supportsHistory(environment.userAgent, environment.history);
  },

  /**
    @private

    @method _getSupportsHashChange
  */
  _getSupportsHashChange: function () {
    return supportsHashChange(document.documentMode, window);
  },

  /**
    @private

    Redirects the browser using location.replace, prepending the locatin.origin
    to prevent phishing attempts

    @method _replacePath
  */
  _replacePath: function (path) {
    this._location.replace(this._getOrigin() + path);
  },

  /**
    @since 1.5.1
    @private
    @method _getRootURL
  */
  _getRootURL: function () {
    return this.rootURL;
  },

  /**
    @private

    Returns the current `location.pathname`, normalized for IE inconsistencies.

    @method _getPath
  */
  _getPath: function () {
    var pathname = this._location.pathname;
    // Various versions of IE/Opera don't always return a leading slash
    if (pathname.charAt(0) !== '/') {
      pathname = '/' + pathname;
    }

    return pathname;
  },

  /**
    @private

    Returns normalized location.hash as an alias to Ember.Location._getHash

    @since 1.5.1
    @method _getHash
  */
  _getHash: EmberLocation._getHash,

  /**
    @private

    Returns location.search

    @since 1.5.1
    @method _getQuery
  */
  _getQuery: function () {
    return this._location.search;
  },

  /**
    @private

    Returns the full pathname including query and hash

    @method _getFullPath
  */
  _getFullPath: function () {
    return this._getPath() + this._getQuery() + this._getHash();
  },

  /**
    @private

    Returns the current path as it should appear for HistoryLocation supported
    browsers. This may very well differ from the real current path (e.g. if it
    starts off as a hashed URL)

    @method _getHistoryPath
  */
  _getHistoryPath: function () {
    var rootURL = this._getRootURL();
    var path = this._getPath();
    var hash = this._getHash();
    var query = this._getQuery();
    var rootURLIndex = path.indexOf(rootURL);
    var routeHash, hashParts;

    Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0);

    // By convention, Ember.js routes using HashLocation are required to start
    // with `#/`. Anything else should NOT be considered a route and should
    // be passed straight through, without transformation.
    if (hash.substr(0, 2) === '#/') {
      // There could be extra hash segments after the route
      hashParts = hash.substr(1).split('#');
      // The first one is always the route url
      routeHash = hashParts.shift();

      // If the path already has a trailing slash, remove the one
      // from the hashed route so we don't double up.
      if (path.slice(-1) === '/') {
          routeHash = routeHash.substr(1);
      }

      // This is the "expected" final order
      path += routeHash;
      path += query;

      if (hashParts.length) {
        path += '#' + hashParts.join('#');
      }
    } else {
      path += query;
      path += hash;
    }

    return path;
  },

  /**
    @private

    Returns the current path as it should appear for HashLocation supported
    browsers. This may very well differ from the real current path.

    @method _getHashPath
  */
  _getHashPath: function () {
    var rootURL = this._getRootURL();
    var path = rootURL;
    var historyPath = this._getHistoryPath();
    var routePath = historyPath.substr(rootURL.length);

    if (routePath !== '') {
      if (routePath.charAt(0) !== '/') {
        routePath = '/' + routePath;
      }

      path += '#' + routePath;
    }

    return path;
  },

  /**
    Selects the best location option based off browser support and returns an
    instance of that Location class.

    @see Ember.AutoLocation
    @method create
  */
  create: function (options) {
    if (options && options.rootURL) {
      Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"',
                   options.rootURL.charAt(options.rootURL.length-1) === '/');
      this.rootURL = options.rootURL;
    }

    var historyPath, hashPath;
    var cancelRouterSetup = false;
    var implementationClass = this._NoneLocation;
    var currentPath = this._getFullPath();

    if (this._getSupportsHistory()) {
      historyPath = this._getHistoryPath();

      // Since we support history paths, let's be sure we're using them else
      // switch the location over to it.
      if (currentPath === historyPath) {
        implementationClass = this._HistoryLocation;
      } else {
        if (Ember.FEATURES.isEnabled("ember-routing-auto-location-uses-replace-state-for-history")) {
          if (currentPath.substr(0, 2) === '/#') {
            this._history.replaceState({ path: historyPath }, null, historyPath);
            implementationClass = this._HistoryLocation;
          } else {
            cancelRouterSetup = true;
            this._replacePath(historyPath);
          }
        } else {
          cancelRouterSetup = true;
          this._replacePath(historyPath);
        }
      }

    } else if (this._getSupportsHashChange()) {
      hashPath = this._getHashPath();

      // Be sure we're using a hashed path, otherwise let's switch over it to so
      // we start off clean and consistent. We'll count an index path with no
      // hash as "good enough" as well.
      if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) {
        implementationClass = this._HashLocation;
      } else {
        // Our URL isn't in the expected hash-supported format, so we want to
        // cancel the router setup and replace the URL to start off clean
        cancelRouterSetup = true;
        this._replacePath(hashPath);
      }
    }

    var implementation = implementationClass.create.apply(implementationClass, arguments);

    if (cancelRouterSetup) {
      set(implementation, 'cancelRouterSetup', true);
    }

    return implementation;
  }
};
<commit_msg>Ember-on-node refactor removed location from AutoLocation.<commit_after>import Ember from "ember-metal/core"; // FEATURES
import { set } from "ember-metal/property_set";

import EmberLocation from "ember-routing/location/api";
import HistoryLocation from "ember-routing/location/history_location";
import HashLocation from "ember-routing/location/hash_location";
import NoneLocation from "ember-routing/location/none_location";

import environment from "ember-metal/environment";
import { supportsHashChange, supportsHistory } from "ember-routing/location/feature_detect";

/**
@module ember
@submodule ember-routing
*/

/**
  Ember.AutoLocation will select the best location option based off browser
  support with the priority order: history, hash, none.

  Clean pushState paths accessed by hashchange-only browsers will be redirected
  to the hash-equivalent and vice versa so future transitions are consistent.

  Keep in mind that since some of your users will use `HistoryLocation`, your
  server must serve the Ember app at all the routes you define.

  @class AutoLocation
  @namespace Ember
  @static
*/
export default {
  /**
    @private

    Attached for mocking in tests

    @property location
    @default environment.location
  */
  _location: environment.location,

  /**
    @private

    This property is used by router:main to know whether to cancel the routing
    setup process, which is needed while we redirect the browser.

    @since 1.5.1
    @property cancelRouterSetup
    @default false
  */
  cancelRouterSetup: false,

  /**
    @private

    Will be pre-pended to path upon state change.

    @since 1.5.1
    @property rootURL
    @default '/'
  */
  rootURL: '/',

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _HistoryLocation
    @default Ember.HistoryLocation
  */
  _HistoryLocation: HistoryLocation,

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _HashLocation
    @default Ember.HashLocation
  */
  _HashLocation: HashLocation,

  /**
    @private

    Attached for mocking in tests

    @since 1.5.1
    @property _NoneLocation
    @default Ember.NoneLocation
  */
  _NoneLocation: NoneLocation,

  /**
    @private

    Returns location.origin or builds it if device doesn't support it.

    @method _getOrigin
  */
  _getOrigin: function () {
    var location = this._location;
    var origin = location.origin;

    // Older browsers, especially IE, don't have origin
    if (!origin) {
      origin = location.protocol + '//' + location.hostname;

      if (location.port) {
        origin += ':' + location.port;
      }
    }

    return origin;
  },

  _userAgent: environment.userAgent,

  /**
    @private

    @method _getSupportsHistory
  */
  _getSupportsHistory: function () {
    return supportsHistory(environment.userAgent, environment.history);
  },

  /**
    @private

    @method _getSupportsHashChange
  */
  _getSupportsHashChange: function () {
    return supportsHashChange(document.documentMode, window);
  },

  /**
    @private

    Redirects the browser using location.replace, prepending the locatin.origin
    to prevent phishing attempts

    @method _replacePath
  */
  _replacePath: function (path) {
    this._location.replace(this._getOrigin() + path);
  },

  /**
    @since 1.5.1
    @private
    @method _getRootURL
  */
  _getRootURL: function () {
    return this.rootURL;
  },

  /**
    @private

    Returns the current `location.pathname`, normalized for IE inconsistencies.

    @method _getPath
  */
  _getPath: function () {
    var pathname = this._location.pathname;
    // Various versions of IE/Opera don't always return a leading slash
    if (pathname.charAt(0) !== '/') {
      pathname = '/' + pathname;
    }

    return pathname;
  },

  /**
    @private

    Returns normalized location.hash as an alias to Ember.Location._getHash

    @since 1.5.1
    @method _getHash
  */
  _getHash: EmberLocation._getHash,

  /**
    @private

    Returns location.search

    @since 1.5.1
    @method _getQuery
  */
  _getQuery: function () {
    return this._location.search;
  },

  /**
    @private

    Returns the full pathname including query and hash

    @method _getFullPath
  */
  _getFullPath: function () {
    return this._getPath() + this._getQuery() + this._getHash();
  },

  /**
    @private

    Returns the current path as it should appear for HistoryLocation supported
    browsers. This may very well differ from the real current path (e.g. if it
    starts off as a hashed URL)

    @method _getHistoryPath
  */
  _getHistoryPath: function () {
    var rootURL = this._getRootURL();
    var path = this._getPath();
    var hash = this._getHash();
    var query = this._getQuery();
    var rootURLIndex = path.indexOf(rootURL);
    var routeHash, hashParts;

    Ember.assert('Path ' + path + ' does not start with the provided rootURL ' + rootURL, rootURLIndex === 0);

    // By convention, Ember.js routes using HashLocation are required to start
    // with `#/`. Anything else should NOT be considered a route and should
    // be passed straight through, without transformation.
    if (hash.substr(0, 2) === '#/') {
      // There could be extra hash segments after the route
      hashParts = hash.substr(1).split('#');
      // The first one is always the route url
      routeHash = hashParts.shift();

      // If the path already has a trailing slash, remove the one
      // from the hashed route so we don't double up.
      if (path.slice(-1) === '/') {
          routeHash = routeHash.substr(1);
      }

      // This is the "expected" final order
      path += routeHash;
      path += query;

      if (hashParts.length) {
        path += '#' + hashParts.join('#');
      }
    } else {
      path += query;
      path += hash;
    }

    return path;
  },

  /**
    @private

    Returns the current path as it should appear for HashLocation supported
    browsers. This may very well differ from the real current path.

    @method _getHashPath
  */
  _getHashPath: function () {
    var rootURL = this._getRootURL();
    var path = rootURL;
    var historyPath = this._getHistoryPath();
    var routePath = historyPath.substr(rootURL.length);

    if (routePath !== '') {
      if (routePath.charAt(0) !== '/') {
        routePath = '/' + routePath;
      }

      path += '#' + routePath;
    }

    return path;
  },

  /**
    Selects the best location option based off browser support and returns an
    instance of that Location class.

    @see Ember.AutoLocation
    @method create
  */
  create: function (options) {
    if (options && options.rootURL) {
      Ember.assert('rootURL must end with a trailing forward slash e.g. "/app/"',
                   options.rootURL.charAt(options.rootURL.length-1) === '/');
      this.rootURL = options.rootURL;
    }

    var historyPath, hashPath;
    var cancelRouterSetup = false;
    var implementationClass = this._NoneLocation;
    var currentPath = this._getFullPath();

    if (this._getSupportsHistory()) {
      historyPath = this._getHistoryPath();

      // Since we support history paths, let's be sure we're using them else
      // switch the location over to it.
      if (currentPath === historyPath) {
        implementationClass = this._HistoryLocation;
      } else {
        if (Ember.FEATURES.isEnabled("ember-routing-auto-location-uses-replace-state-for-history")) {
          if (currentPath.substr(0, 2) === '/#') {
            this._history.replaceState({ path: historyPath }, null, historyPath);
            implementationClass = this._HistoryLocation;
          } else {
            cancelRouterSetup = true;
            this._replacePath(historyPath);
          }
        } else {
          cancelRouterSetup = true;
          this._replacePath(historyPath);
        }
      }

    } else if (this._getSupportsHashChange()) {
      hashPath = this._getHashPath();

      // Be sure we're using a hashed path, otherwise let's switch over it to so
      // we start off clean and consistent. We'll count an index path with no
      // hash as "good enough" as well.
      if (currentPath === hashPath || (currentPath === '/' && hashPath === '/#/')) {
        implementationClass = this._HashLocation;
      } else {
        // Our URL isn't in the expected hash-supported format, so we want to
        // cancel the router setup and replace the URL to start off clean
        cancelRouterSetup = true;
        this._replacePath(hashPath);
      }
    }

    var implementation = implementationClass.create.apply(implementationClass, arguments);

    if (cancelRouterSetup) {
      set(implementation, 'cancelRouterSetup', true);
    }

    return implementation;
  }
};
<|endoftext|>


<commit_before>const shell = require("shelljs");
const { paths } = require("common");
const pino = require("pino")({ prettyPrint: { forceColor: true } });
const yargs = require("yargs");

const coverage = function({ nameSpaceId }) {
  const argv = yargs.options({
    w: { alias: "watch", type: "boolean" },
    r: { alias: "reporter", type: "string", default: "html" }
  }).argv;
  const endOfOptions = argv._.join(" ");

  let reportDir = paths.project(`coverage/${nameSpaceId}`);

  shell.rm("-r", reportDir);

  let command = `npx nyc report`;
  command += ` --reporter ${argv.reporter}`;
  command += ` --report-dir ${reportDir}`;
  command += ` --temp-directory ${paths.tmp(`.nyc_output_${nameSpaceId}`)}`;
  command += ` ${endOfOptions}`;

  pino.info(command);
  shell.exec(command);
};

module.exports = coverage;
<commit_msg>[FEATURE] Coverage script: Change nyc temp-directory back to temp-dir<commit_after>const shell = require("shelljs");
const { paths } = require("common");
const pino = require("pino")({ prettyPrint: { forceColor: true } });
const yargs = require("yargs");

const coverage = function({ nameSpaceId }) {
  const argv = yargs.options({
    w: { alias: "watch", type: "boolean" },
    r: { alias: "reporter", type: "string", default: "html" }
  }).argv;
  const endOfOptions = argv._.join(" ");

  let reportDir = paths.project(`coverage/${nameSpaceId}`);

  shell.rm("-r", reportDir);

  let command = `npx nyc report`;
  command += ` --reporter ${argv.reporter}`;
  command += ` --report-dir ${reportDir}`;
  command += ` --temp-dir ${paths.tmp(`.nyc_output_${nameSpaceId}`)}`;
  command += ` ${endOfOptions}`;

  pino.info(command);
  shell.exec(command);
};

module.exports = coverage;
<|endoftext|>


<commit_before>const fs   = require('fs-extra');
const path = require('path');

const createDoodle = (_name, _cwd) => {

  const name = _name;
  const cwd = path.resolve(_cwd, _name);

  if (!name) throw new Error('Invalid doodle name');

  const templates = {
    'index.js': '',
    'index.styl': '',
    'index.mustache': "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  "
     + "<meta charset=\"utf-8\">\r\n  <title>{{title}}<\/title>\r\n  "
     + "<meta name=\"viewport\" content=\"width=device-width,"
     + "height=device-height,initial-scale=1.0,minimal-ui\">\r\n  "
     + "<base href=\".\/\">\r\n  {{#compiler.isProduction}}"
     + "<link rel=\"stylesheet\" href=\"bundle-{{compiler.hash}}.css\">"
     + "{{\/compiler.isProduction}}\r\n<\/head>\r\n<body>\r\n  "
     + "<main id=\"page\"><\/main>\r\n  "
     + "<script src=\"bundle-{{compiler.hash}}.js\"><\/script>\r\n"
     + "<\/body>\r\n<\/html>\r\n",
    'pages.config.js': "const options = {\r\n  'cwd': __dirname\r\n};"
      + "\r\nconst pages = {\r\n  'index.html': {\r\n    "
      + "template: 'index.mustache',\r\n    data: {\r\n      "
      + "title: '" + name + "',\r\n    }\r\n  }\r\n};\r\n"
      + "module.exports = { options, pages };"
  }

  const exists = () => {
    return new Promise((resolve, reject) => {
      fs.access(cwd, fs.F_OK, err => (!err) ? resolve() : reject(err));
    });
  };

  const remove = () => {
    return new Promise((resolve, reject) => {
      fs.remove(cwd, err => (!err) ? resolve() : reject(err))
    });
  };

  const makeDirs = () => {
    const promises = [];
    promises.push(new Promise((resolve, reject) => {
      fs.mkdirs(path.join(cwd, 'src'),
        err => (!err) ? resolve() : reject(err));
    }));
    promises.push(new Promise((resolve, reject) => {
      fs.mkdirs(path.join(cwd, 'build'),
        err => (!err) ? resolve() : reject(err));
    }));
    return Promise.all(promises);
  };

  const makeFiles = () => {
    const promises = [];
    for (k in templates) {
      const fileName = k;
      const file = templates[fileName];
      const promise = new Promise((resolve, reject) => {
        fs.writeFile(path.join(cwd, 'src', fileName), file,
          err => (!err) ? resolve(fileName) : reject(err));
      });
      promises.push(promise);
    }
    return Promise.all(promises);
  };

  return { exists, remove, makeDirs, makeFiles, name, cwd };

}

module.exports = createDoodle;<commit_msg>Fix for non-string doodle name<commit_after>const fs   = require('fs-extra');
const path = require('path');

const createDoodle = (_name, _cwd) => {

  if (!_name) throw new Error('Invalid doodle name');

  const name = _name.toString();
  const cwd = path.resolve(_cwd, name);

  const templates = {
    'index.js': '',
    'index.styl': '',
    'index.mustache': "<!DOCTYPE html>\r\n<html>\r\n<head>\r\n  "
     + "<meta charset=\"utf-8\">\r\n  <title>{{title}}<\/title>\r\n  "
     + "<meta name=\"viewport\" content=\"width=device-width,"
     + "height=device-height,initial-scale=1.0,minimal-ui\">\r\n  "
     + "<base href=\".\/\">\r\n  {{#compiler.isProduction}}"
     + "<link rel=\"stylesheet\" href=\"bundle-{{compiler.hash}}.css\">"
     + "{{\/compiler.isProduction}}\r\n<\/head>\r\n<body>\r\n  "
     + "<main id=\"page\"><\/main>\r\n  "
     + "<script src=\"bundle-{{compiler.hash}}.js\"><\/script>\r\n"
     + "<\/body>\r\n<\/html>\r\n",
    'pages.config.js': "const options = {\r\n  'cwd': __dirname\r\n};"
      + "\r\nconst pages = {\r\n  'index.html': {\r\n    "
      + "template: 'index.mustache',\r\n    data: {\r\n      "
      + "title: '" + name + "',\r\n    }\r\n  }\r\n};\r\n"
      + "module.exports = { options, pages };"
  }

  const exists = () => {
    return new Promise((resolve, reject) => {
      fs.access(cwd, fs.F_OK, err => (!err) ? resolve() : reject(err));
    });
  };

  const remove = () => {
    return new Promise((resolve, reject) => {
      fs.remove(cwd, err => (!err) ? resolve() : reject(err))
    });
  };

  const makeDirs = () => {
    const promises = [];
    promises.push(new Promise((resolve, reject) => {
      fs.mkdirs(path.join(cwd, 'src'),
        err => (!err) ? resolve() : reject(err));
    }));
    promises.push(new Promise((resolve, reject) => {
      fs.mkdirs(path.join(cwd, 'build'),
        err => (!err) ? resolve() : reject(err));
    }));
    return Promise.all(promises);
  };

  const makeFiles = () => {
    const promises = [];
    for (k in templates) {
      const fileName = k;
      const file = templates[fileName];
      const promise = new Promise((resolve, reject) => {
        fs.writeFile(path.join(cwd, 'src', fileName), file,
          err => (!err) ? resolve(fileName) : reject(err));
      });
      promises.push(promise);
    }
    return Promise.all(promises);
  };

  return { exists, remove, makeDirs, makeFiles, name, cwd };

}

module.exports = createDoodle;<|endoftext|>


<commit_before>'use strict'

var native = require('./native')
var now = require('./now')
var performance = require('./performance')

// Weird native implementation doesn't work if context is defined.
var nativeRequest = native.request
var nativeCancel = native.cancel

/**
 * Animation frame constructor.
 *
 * Options:
 *   - `useNative` use the native animation frame if possible, defaults to true
 *   - `frameRate` pass a custom frame rate
 *
 * @param {Object|Number} options
 */
function AnimationFrame(options) {
    if (!(this instanceof AnimationFrame)) return new AnimationFrame(options)
    options || (options = {})

    // Its a frame rate.
    if (typeof options == 'number') options = {frameRate: options}
    options.useNative != null || (options.useNative = true)
    this.options = options
    this.frameRate = options.frameRate || AnimationFrame.FRAME_RATE
    this._frameLength = 1000 / this.frameRate
    this._isCustomFrameRate = this.frameRate !== AnimationFrame.FRAME_RATE
    this._timeoutId = null
    this._callbacks = {}
    this._lastTickTime = 0
    this._tickCounter = 0
}

module.exports = AnimationFrame

/**
 * Default frame rate used for shim implementation. Native implementation
 * will use the screen frame rate, but js have no way to detect it.
 *
 * If you know your target device, define it manually.
 *
 * @type {Number}
 * @api public
 */
AnimationFrame.FRAME_RATE = 60

/**
 * Replace the globally defined implementation or define it globally.
 *
 * @param {Object|Number} [options]
 * @api public
 */
AnimationFrame.shim = function(options) {
    var animationFrame = new AnimationFrame(options)

    window.requestAnimationFrame = function(callback) {
        return animationFrame.request(callback)
    }
    window.cancelAnimationFrame = function(id) {
        return animationFrame.cancel(id)
    }

    return animationFrame
}

/**
 * Request animation frame.
 * We will use the native RAF as soon as we know it does works.
 *
 * @param {Function} callback
 * @return {Number} timeout id or requested animation frame id
 * @api public
 */
AnimationFrame.prototype.request = function(callback) {
    var self = this

    // Alawys inc counter to ensure it never has a conflict with the native counter.
    // After the feature test phase we don't know exactly which implementation has been used.
    // Therefore on #cancel we do it for both.
    ++this._tickCounter

    if (native.supported && this.options.useNative && !this._isCustomFrameRate) {
        return nativeRequest(callback)
    }

    if (!callback) throw new TypeError('Not enough arguments')

    if (this._timeoutId == null) {
        // Much faster than Math.max
        // http://jsperf.com/math-max-vs-comparison/3
        // http://jsperf.com/date-now-vs-date-gettime/11
        var delay = this._frameLength + this._lastTickTime - now()
        if (delay < 0) delay = 0

        this._timeoutId = setTimeout(function() {
            self._lastTickTime = now()
            self._timeoutId = null
            ++self._tickCounter
            var callbacks = self._callbacks
            self._callbacks = {}
            for (var id in callbacks) {
                if (callbacks[id]) {
                    if (native.supported && self.options.useNative) {
                        nativeRequest(callbacks[id])
                    } else {
                        callbacks[id](performance.now())
                    }
                }
            }
        }, delay)
    }

    this._callbacks[this._tickCounter] = callback

    return this._tickCounter
}

/**
 * Cancel animation frame.
 *
 * @param {Number} timeout id or requested animation frame id
 *
 * @api public
 */
AnimationFrame.prototype.cancel = function(id) {
    if (native.supported && this.options.useNative) nativeCancel(id)
    delete this._callbacks[id]
}
<commit_msg>Renamed native to nativeImpl<commit_after>'use strict'

var nativeImpl = require('./native')
var now = require('./now')
var performance = require('./performance')

// Weird native implementation doesn't work if context is defined.
var nativeRequest = nativeImpl.request
var nativeCancel = nativeImpl.cancel

/**
 * Animation frame constructor.
 *
 * Options:
 *   - `useNative` use the native animation frame if possible, defaults to true
 *   - `frameRate` pass a custom frame rate
 *
 * @param {Object|Number} options
 */
function AnimationFrame(options) {
    if (!(this instanceof AnimationFrame)) return new AnimationFrame(options)
    options || (options = {})

    // Its a frame rate.
    if (typeof options == 'number') options = {frameRate: options}
    options.useNative != null || (options.useNative = true)
    this.options = options
    this.frameRate = options.frameRate || AnimationFrame.FRAME_RATE
    this._frameLength = 1000 / this.frameRate
    this._isCustomFrameRate = this.frameRate !== AnimationFrame.FRAME_RATE
    this._timeoutId = null
    this._callbacks = {}
    this._lastTickTime = 0
    this._tickCounter = 0
}

module.exports = AnimationFrame

/**
 * Default frame rate used for shim implementation. Native implementation
 * will use the screen frame rate, but js have no way to detect it.
 *
 * If you know your target device, define it manually.
 *
 * @type {Number}
 * @api public
 */
AnimationFrame.FRAME_RATE = 60

/**
 * Replace the globally defined implementation or define it globally.
 *
 * @param {Object|Number} [options]
 * @api public
 */
AnimationFrame.shim = function(options) {
    var animationFrame = new AnimationFrame(options)

    window.requestAnimationFrame = function(callback) {
        return animationFrame.request(callback)
    }
    window.cancelAnimationFrame = function(id) {
        return animationFrame.cancel(id)
    }

    return animationFrame
}

/**
 * Request animation frame.
 * We will use the native RAF as soon as we know it does works.
 *
 * @param {Function} callback
 * @return {Number} timeout id or requested animation frame id
 * @api public
 */
AnimationFrame.prototype.request = function(callback) {
    var self = this

    // Alawys inc counter to ensure it never has a conflict with the native counter.
    // After the feature test phase we don't know exactly which implementation has been used.
    // Therefore on #cancel we do it for both.
    ++this._tickCounter

    if (nativeImpl.supported && this.options.useNative && !this._isCustomFrameRate) {
        return nativeRequest(callback)
    }

    if (!callback) throw new TypeError('Not enough arguments')

    if (this._timeoutId == null) {
        // Much faster than Math.max
        // http://jsperf.com/math-max-vs-comparison/3
        // http://jsperf.com/date-now-vs-date-gettime/11
        var delay = this._frameLength + this._lastTickTime - now()
        if (delay < 0) delay = 0

        this._timeoutId = setTimeout(function() {
            self._lastTickTime = now()
            self._timeoutId = null
            ++self._tickCounter
            var callbacks = self._callbacks
            self._callbacks = {}
            for (var id in callbacks) {
                if (callbacks[id]) {
                    if (nativeImpl.supported && self.options.useNative) {
                        nativeRequest(callbacks[id])
                    } else {
                        callbacks[id](performance.now())
                    }
                }
            }
        }, delay)
    }

    this._callbacks[this._tickCounter] = callback

    return this._tickCounter
}

/**
 * Cancel animation frame.
 *
 * @param {Number} timeout id or requested animation frame id
 *
 * @api public
 */
AnimationFrame.prototype.cancel = function(id) {
    if (nativeImpl.supported && this.options.useNative) nativeCancel(id)
    delete this._callbacks[id]
}
<|endoftext|>


<commit_before>describe('controllers', function () {
  var scope, controller, $httpBackend

  beforeEach(module('juiceShop'))
  beforeEach(inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend')
    $httpBackend.whenGET(/\/i18n\/.*\.json/).respond(200, {})
  }))

  afterEach(function () {
    $httpBackend.verifyNoOutstandingExpectation()
    $httpBackend.verifyNoOutstandingRequest()
  })

  describe('ContactController', function () {
    beforeEach(inject(function ($rootScope, $controller) {
      scope = $rootScope.$new()
      controller = $controller('ContactController', {
        '$scope': scope
      })
    }))

    it('should be defined', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.flush()

      expect(controller).toBeDefined()
      expect(scope.save).toBeDefined()
    }))

    it('should hold the user id of the currently logged in user', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {id: 42}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.flush()

      expect(scope.feedback.UserId).toBe(42)
    }))

    it('should hold no user id if current user is not logged in', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.flush()

      expect(scope.feedback.UserId).toBeUndefined()
    }))

    it('should miss feedback object if retrieving currently logged in user fails', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(500)
      $httpBackend.whenGET('/rest/captcha/').respond(500, {})
      $httpBackend.flush()

      expect(scope.feedback).toBeUndefined()
    }))

    it('should hold the user email of the currently logged in user', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {email: 'x@x.xx'}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.flush()

      expect(scope.userEmail).toBe('x@x.xx')
    }))

    it('should hold anonymous placeholder for email if current user is not logged in', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.flush()

      expect(scope.userEmail).toBe('anonymous')
    }))

    it('should display thank-you message and reset feedback form on saving feedback', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.whenPOST('/api/Feedbacks/').respond(200, {data: {comment: 'Test', rating: 4}})
      scope.feedback = {comment: 'Test', rating: 4}
      scope.form = {$setPristine: function () {}}

      scope.save()
      $httpBackend.flush()

      expect(scope.feedback).toEqual({})
      expect(scope.confirmation).toBe('Thank you for your feedback.')
    }))

    it('should display 5-star thank-you message and reset feedback form on saving 5-star feedback', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
      $httpBackend.whenPOST('/api/Feedbacks/').respond(200, {data: {comment: 'Praise', rating: 5}})
      scope.feedback = {comment: 'Praise', rating: 5}
      scope.form = {$setPristine: function () {}}

      scope.save()
      $httpBackend.flush()

      expect(scope.feedback).toEqual({})
      expect(scope.confirmation).toBe('Thank you for your feedback and your 5-star rating!')
    }))
  })
})
<commit_msg>Reduce HTTP mock duplication for captcha retrieval<commit_after>describe('controllers', function () {
  var scope, controller, $httpBackend

  beforeEach(module('juiceShop'))
  beforeEach(inject(function ($injector) {
    $httpBackend = $injector.get('$httpBackend')
    $httpBackend.whenGET(/\/i18n\/.*\.json/).respond(200, {})
    $httpBackend.whenGET('/rest/captcha/').respond(200, {'captchaId': 1, 'captcha': '5-1-1', 'answer': '3'})
  }))

  afterEach(function () {
    $httpBackend.verifyNoOutstandingExpectation()
    $httpBackend.verifyNoOutstandingRequest()
  })

  describe('ContactController', function () {
    beforeEach(inject(function ($rootScope, $controller) {
      scope = $rootScope.$new()
      controller = $controller('ContactController', {
        '$scope': scope
      })
    }))

    it('should be defined', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.flush()

      expect(controller).toBeDefined()
      expect(scope.save).toBeDefined()
    }))

    it('should hold the user id of the currently logged in user', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {id: 42}})
      $httpBackend.flush()

      expect(scope.feedback.UserId).toBe(42)
    }))

    it('should hold no user id if current user is not logged in', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.flush()

      expect(scope.feedback.UserId).toBeUndefined()
    }))

    it('should miss feedback object if retrieving currently logged in user fails', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(500)
      $httpBackend.flush()

      expect(scope.feedback).toBeUndefined()
    }))

    it('should hold the user email of the currently logged in user', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {email: 'x@x.xx'}})
      $httpBackend.flush()

      expect(scope.userEmail).toBe('x@x.xx')
    }))

    it('should hold anonymous placeholder for email if current user is not logged in', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.flush()

      expect(scope.userEmail).toBe('anonymous')
    }))

    it('should display thank-you message and reset feedback form on saving feedback', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenPOST('/api/Feedbacks/').respond(200, {data: {comment: 'Test', rating: 4}})
      scope.feedback = {comment: 'Test', rating: 4}
      scope.form = {$setPristine: function () {}}

      scope.save()
      $httpBackend.flush()

      expect(scope.feedback).toEqual({})
      expect(scope.confirmation).toBe('Thank you for your feedback.')
    }))

    it('should display 5-star thank-you message and reset feedback form on saving 5-star feedback', inject(function () {
      $httpBackend.whenGET('/rest/user/whoami').respond(200, {user: {}})
      $httpBackend.whenPOST('/api/Feedbacks/').respond(200, {data: {comment: 'Praise', rating: 5}})
      scope.feedback = {comment: 'Praise', rating: 5}
      scope.form = {$setPristine: function () {}}

      scope.save()
      $httpBackend.flush()

      expect(scope.feedback).toEqual({})
      expect(scope.confirmation).toBe('Thank you for your feedback and your 5-star rating!')
    }))
  })
})
<|endoftext|>


<commit_before>var assemble = require('assemble');
var path = require('path');
var lazy = require('lazy-cache')(require);
lazy('mixin-object', 'mixin');

var engine = require('engine-assemble');
var layouts = require('handlebars-layouts');

assemble.engine('hbs', engine);
engine.Handlebars.registerHelper(layouts(engine.Handlebars));
//assemble.helpers(layouts(engine.Handlebars));

assemble.helper('raw', require('../handlebars/helpers/raw'));
assemble.helper('doc', require('../handlebars/helpers/doc'));
assemble.helper('test', require('../handlebars/helpers/test'));

assemble.option('renameKey', function(filepath, options) {
    return path.relative(process.cwd() + '/src/tmpl/', filepath).replace('partials/', '').replace(path.extname(filepath), '');
});

assemble.option('mergeContext', function (view, ctx, locals) {
    var context = {};
    if(view.cwd) {
        var key = path.relative(view.cwd + '/src/tmpl', view.path).replace(path.extname(view.path), '');
        if(this.cache.data[key]) {
            lazy.mixin(context, this.cache.data[key]);
        }
    }
//    console.log(view.orig.match(/{{partial\s"([\w\/]+).*}}/g));
//    console.log('------------------');
    if (this.enabled('preferLocals')) {
        lazy.mixin(context, view.options);
        lazy.mixin(context, view.data);
        lazy.mixin(context, view.locals);
    } else {
        lazy.mixin(context, view.locals);
        lazy.mixin(context, view.data);
        lazy.mixin(context, view.options);
    }

    lazy.mixin(context, this.mergePartials(ctx));
    lazy.mixin(context, this.cache._context.partials);
    return context;
});

assemble.data('**/*.{json,yml}', {
    namespace: function(filename, options) {
        return path.relative(options.cwd, filename).replace(path.extname(filename), '');
    },
    cwd: process.cwd() + '/src/data/'
});

module.exports = assemble;<commit_msg>compatible mode (win/osx) embedded into renameKey function<commit_after>var assemble = require('assemble');
var path = require('path');
var lazy = require('lazy-cache')(require);
lazy('mixin-object', 'mixin');

var engine = require('engine-assemble');
var layouts = require('handlebars-layouts');

assemble.engine('hbs', engine);
engine.Handlebars.registerHelper(layouts(engine.Handlebars));
//assemble.helpers(layouts(engine.Handlebars));

assemble.helper('raw', require('../handlebars/helpers/raw'));
assemble.helper('doc', require('../handlebars/helpers/doc'));
assemble.helper('test', require('../handlebars/helpers/test'));

assemble.option('renameKey', function(filepath, options) {
    return path.relative(process.cwd() + '/src/tmpl/', filepath).replace('partials/', '').replace(path.extname(filepath), '').replace(/\\/g, '/').replace('partials/', '');
});

assemble.option('mergeContext', function (view, ctx, locals) {
    var context = {};
    if(view.cwd) {
        var key = path.relative(view.cwd + '/src/tmpl', view.path).replace(path.extname(view.path), '');
        if(this.cache.data[key]) {
            lazy.mixin(context, this.cache.data[key]);
        }
    }
//    console.log(view.orig.match(/{{partial\s"([\w\/]+).*}}/g));
//    console.log('------------------');
    if (this.enabled('preferLocals')) {
        lazy.mixin(context, view.options);
        lazy.mixin(context, view.data);
        lazy.mixin(context, view.locals);
    } else {
        lazy.mixin(context, view.locals);
        lazy.mixin(context, view.data);
        lazy.mixin(context, view.options);
    }

    lazy.mixin(context, this.mergePartials(ctx));
    lazy.mixin(context, this.cache._context.partials);
    return context;
});

assemble.data('**/*.{json,yml}', {
    namespace: function(filename, options) {
        return path.relative(options.cwd, filename).replace(path.extname(filename), '');
    },
    cwd: process.cwd() + '/src/data/'
});

module.exports = assemble;<|endoftext|>


<commit_before>const Boom = require('boom');
const Controller = require('../controller');
// const {Issuer} = require('openid-client');
const User = require('./user');
const {hash_verify, jwt_sign} = require('../helpers/security');
const Sharp = require('../../vendor/sharp/index');
const {upload} = require('../../vendor/minio');

class AuthController extends Controller {

    constructor(auth_options) {
        super({
            prefix: '/api/auth',
            routes: {
                profile_post: {
                    auth: {mode: 'required'},
                    payload: {
                        maxBytes: 1048576 * 16,
                    }
                },
                profile: {
                    auth: {mode: 'required'}
                }
            }
        });

        this.auth_options = auth_options;

        // this._init_oauth_client();
    }

    async login_post(request, reply, _user) {
        let {username, password} = request.payload;

        // Prefix username
        if (this.auth_options.username_prefix &&
            username.indexOf(this.auth_options.username_prefix) === -1)
            username += this.auth_options.username_prefix;

        // Find user
        let user = await User.findOne({email: username});
        if (!user) return reply(Boom.unauthorized("User not found"));

        // Check password
        let verified = await hash_verify(password, user.get('password'));
        if (verified !== true) return reply(Boom.unauthorized("Invalid credentials"));

        // Create new session
        let session = user.sessions.create({
            agent: request.headers['user-agent'],
            ip: request.info['remoteAddress']
        });

        // Revoke any older sessions of user with same user-agent
        user.sessions = user.sessions.filter(s => (s.agent != session.agent));

        // Add new session
        user.sessions.push(session);
        await user.save();

        // Sign session token
        let id_token = await jwt_sign({u: user._id, s: session._id}, this.auth_options.secret);

        return reply({id_token});
    }

    user(request, reply, user) {
        reply({user});
    }

    async user_post(request, reply, user) {
        // Upload profile photo
        let avatar = request.payload.avatar;

        if (avatar instanceof Buffer) {
            try {
                let img = await Sharp(avatar).resize(128, 128).webp({quality: 100}).toBuffer();
                user.avatar_etag = await upload('avatar', user._id + '.webp', img);
                await user.save();
            } catch (e) {
                return reply(Boom.badRequest("Error while uploading avatar"));
            }
        }

        reply({user});
    }

    // ==============================
    // OpenId Client functionality
    // ==============================
    // init_oauth_client() {
    //     // if (this.auth_options.client) {
    //     // const issuer = await Issuer.discover(this.auth_options.client.discover_url);
    //     // this.client = new issuer.Client(this.auth_options.client);
    //     // }
    // }
    //
    // oauth_login(request, reply, user) {
    //     if (!this.client) return reply(Boom.serverUnavailable("oauth"));
    //
    //     let opts = {
    //         redirect_uri: this.auth_options.redirect_uri,
    //         scope: 'profile email phone'
    //     };
    //
    //     reply(this.client.authorizationPost(opts));
    // }
    //
    // async oauth_callback(request, reply, user) {
    //     if (!this.client) return reply(Boom.serverUnavailable("oauth"));
    //
    //     console.log("Callback");
    //     let tokenSet = await this.client.authorizationCallback(this.auth_options.redirect_uri, request.query);
    //     console.log('received and validated tokens %j', tokenSet);
    //     console.log('validated id_token claims %j', tokenSet.claims);
    //
    //     reply(this.client.authorizationPost(opts));
    // }

}

module.exports = AuthController;<commit_msg>show avatar upload logs<commit_after>const Boom = require('boom');
const Controller = require('../controller');
// const {Issuer} = require('openid-client');
const User = require('./user');
const {hash_verify, jwt_sign} = require('../helpers/security');
const Sharp = require('../../vendor/sharp/index');
const {upload} = require('../../vendor/minio');

class AuthController extends Controller {

    constructor(auth_options) {
        super({
            prefix: '/api/auth',
            routes: {
                profile_post: {
                    auth: {mode: 'required'},
                    payload: {
                        maxBytes: 1048576 * 16,
                    }
                },
                profile: {
                    auth: {mode: 'required'}
                }
            }
        });

        this.auth_options = auth_options;

        // this._init_oauth_client();
    }

    async login_post(request, reply, _user) {
        let {username, password} = request.payload;

        // Prefix username
        if (this.auth_options.username_prefix &&
            username.indexOf(this.auth_options.username_prefix) === -1)
            username += this.auth_options.username_prefix;

        // Find user
        let user = await User.findOne({email: username});
        if (!user) return reply(Boom.unauthorized("User not found"));

        // Check password
        let verified = await hash_verify(password, user.get('password'));
        if (verified !== true) return reply(Boom.unauthorized("Invalid credentials"));

        // Create new session
        let session = user.sessions.create({
            agent: request.headers['user-agent'],
            ip: request.info['remoteAddress']
        });

        // Revoke any older sessions of user with same user-agent
        user.sessions = user.sessions.filter(s => (s.agent != session.agent));

        // Add new session
        user.sessions.push(session);
        await user.save();

        // Sign session token
        let id_token = await jwt_sign({u: user._id, s: session._id}, this.auth_options.secret);

        return reply({id_token});
    }

    user(request, reply, user) {
        reply({user});
    }

    async user_post(request, reply, user) {
        // Upload profile photo
        let avatar = request.payload.avatar;

        if (avatar instanceof Buffer) {
            try {
                let img = await Sharp(avatar).resize(128, 128).webp({quality: 100}).toBuffer();
                user.avatar_etag = await upload('avatar', user._id + '.webp', img);
                await user.save();
            } catch (e) {
                console.error(e)
                return reply(Boom.badRequest("Error while uploading avatar"));
            }
        }

        reply({user});
    }

    // ==============================
    // OpenId Client functionality
    // ==============================
    // init_oauth_client() {
    //     // if (this.auth_options.client) {
    //     // const issuer = await Issuer.discover(this.auth_options.client.discover_url);
    //     // this.client = new issuer.Client(this.auth_options.client);
    //     // }
    // }
    //
    // oauth_login(request, reply, user) {
    //     if (!this.client) return reply(Boom.serverUnavailable("oauth"));
    //
    //     let opts = {
    //         redirect_uri: this.auth_options.redirect_uri,
    //         scope: 'profile email phone'
    //     };
    //
    //     reply(this.client.authorizationPost(opts));
    // }
    //
    // async oauth_callback(request, reply, user) {
    //     if (!this.client) return reply(Boom.serverUnavailable("oauth"));
    //
    //     console.log("Callback");
    //     let tokenSet = await this.client.authorizationCallback(this.auth_options.redirect_uri, request.query);
    //     console.log('received and validated tokens %j', tokenSet);
    //     console.log('validated id_token claims %j', tokenSet.claims);
    //
    //     reply(this.client.authorizationPost(opts));
    // }

}

module.exports = AuthController;<|endoftext|>


<commit_before>/**
 * var connection = new Connection({ tag:  'groonga',
 *                                   host: 'localhost',
 *                                   port: 24224 });
 *
 * // for REST APIs
 * connection.emitMessage(
 *   { command: 'search',
 *     query:   'foobar' },
 *   function callback(result) {
 *     // codes to handle results from the backend
 *   }
 * );
 *
 * // for socket.io APIs
 * connection.on('notification', function listener(messageBody) { ... });
 * connection.emitVolatileMessage({ command: 'reindex' });
 */

var EventEmitter = require('events').EventEmitter;
var http = require('http');
var socketIo = require('socket.io');
var fluent = require('fluent-logger');

function Connection(params) {
  this._params = params;
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};

  this._sender = (
    this._params.sender ||
    fluent.createFluentSender(this._params.tag,
                              { host: this._params.host,
                                port: this._params.port })
  );
  this._server = http.createServer(this._handleHttpRequest.bind(this));
  this._socket = socketIo.listen(this._server);

  var self = this;
  this._socket.sockets.on('connection', function(socket) {
    socket.on(self._params.tag + '.message',
              self._handleMessage.bind(self));
  });
  this._socket.set('log level', 1);
};

Connection.prototype._handleHttpRequest = function(request, response) {
};

Connection.prototype._handleMessage = function(message) {
  var replyTo = message['reply_to'];
  if (replyTo) {
    this.emit('replyTo:' + replyTo, message.body);
  }
};

function createId() {
  return Date.now() + ':' + Math.round(Math.random() * 65536);
}

Connection.prototype.emitMessage = function(message, callback) {
  var id = createId();
  var message = {
    id:   id,
    body: message
  };
  this.once('replyTo:' + id, callback);
  this._sender.emit('message', message);
};

Connection.prototype.emitVolatileMessage = function(message) {
  var id = createId();
  var message = {
    id:   id,
    body: message
  };
  this._sender.emit('message', message);
};

export.Connection = Connection;
<commit_msg>Remove "emitVolatileMessage" method<commit_after>/**
 * var connection = new Connection({ tag:  'groonga',
 *                                   host: 'localhost',
 *                                   port: 24224 });
 *
 * // for REST APIs
 * connection.emitMessage(
 *   { command: 'search',
 *     query:   'foobar' },
 *   function callback(result) {
 *     // codes to handle results from the backend
 *   }
 * );
 *
 * // for socket.io APIs
 * connection.on('notification', function listener(messageBody) { ... });
 * // volatile message
 * connection.emitMessage({ command: 'reindex' });
 */

var EventEmitter = require('events').EventEmitter;
var http = require('http');
var socketIo = require('socket.io');
var fluent = require('fluent-logger');

function Connection(params) {
  this._params = params;
  this._init();
}

Connection.prototype = new EventEmitter();

Connection.prototype._init = function() {
  this._callbacks = {};

  this._sender = (
    this._params.sender ||
    fluent.createFluentSender(this._params.tag,
                              { host: this._params.host,
                                port: this._params.port })
  );
  this._server = http.createServer(this._handleHttpRequest.bind(this));
  this._socket = socketIo.listen(this._server);

  var self = this;
  this._socket.sockets.on('connection', function(socket) {
    socket.on(self._params.tag + '.message',
              self._handleMessage.bind(self));
  });
  this._socket.set('log level', 1);
};

Connection.prototype._handleHttpRequest = function(request, response) {
};

Connection.prototype._handleMessage = function(message) {
  var replyTo = message['reply_to'];
  if (replyTo) {
    this.emit('replyTo:' + replyTo, message.body);
  }
};

function createId() {
  return Date.now() + ':' + Math.round(Math.random() * 65536);
}

Connection.prototype.emitMessage = function(message, callback) {
  var id = createId();
  var message = {
    id:   id,
    body: message
  };
  if (callback) {
    this.once('replyTo:' + id, callback);
  }
  this._sender.emit('message', message);
};

export.Connection = Connection;
<|endoftext|>