<commit_before>Lizard.Widgets.TemplateWidget = Marionette.ItemView.extend({
  getTemplate: function() {
    return this.model.get('template');
  }//,
  //render: function() {
  //  debugger
  //}
});

WIDGET_CLASSES['template'] = Lizard.Widgets.TemplateWidget;
<commit_msg>Removed cruft<commit_after>Lizard.Widgets.TemplateWidget = Marionette.ItemView.extend({
  getTemplate: function() {
    return this.model.get('template');
  }
});

WIDGET_CLASSES['template'] = Lizard.Widgets.TemplateWidget;
<|endoftext|>


<commit_before>(function() {
  'use strict';

  function PointcloudService(THREE, Potree, POCLoader, $window, $rootScope, Messagebus, DrivemapService, sitesservice, CameraService, SceneService, PathControls, SiteBoxService) {

    var me = this;

    this.elRenderArea = null;

    me.settings = {
      pointCountTarget: 1.0,
      pointSize: 0.2,
      opacity: 1,
      showSkybox: true,
      interpolate: false,
      showStats: false,
      pointSizeType: Potree.PointSizeType.ATTENUATED,
      pointSizeTypes: Potree.PointSizeType,
      pointColorType: Potree.PointColorType.RGB,
      pointColorTypes: Potree.PointColorType,
      pointShapes: Potree.PointShape,
      pointShape: Potree.PointShape.SQUARE
    };

    me.stats = {
      nrPoints: 0,
      nrNodes: 0,
      sceneCoordinates: {
        x: 0,
        y: 0,
        z: 0
      },
      lasCoordinates: {
        x: 0,
        y: 0,
        z: 0,
        crs: 'unknown'
      }
    };

    var pointcloudPath = 'data/out_8/cloud.js';
    this.renderer = null;
    var camera;
    var scene;
    var raycaster;
    var pointcloud;
    var skybox;

	me.pathMesh = null;
    var prevCameraOrientation;

    var referenceFrame;
    var mouse = {
      x: 0,
      y: 0
    };

    function loadSkybox(path) {
      var scene = SceneService.getScene();

      var format = '.jpg';
      var urls = [
        path + 'px' + format, path + 'nx' + format,
        path + 'py' + format, path + 'ny' + format,
        path + 'pz' + format, path + 'nz' + format
      ];

      var textureCube = THREE.ImageUtils.loadTextureCube(urls, new THREE.CubeRefractionMapping());

      var shader = THREE.ShaderLib.cube;
      shader.uniforms.tCube.value = textureCube;

      var material = new THREE.ShaderMaterial({

          fragmentShader: shader.fragmentShader,
          vertexShader: shader.vertexShader,
          uniforms: shader.uniforms,
          depthWrite: false,
          side: THREE.BackSide

        }),

        mesh = new THREE.Mesh(new THREE.BoxGeometry(100000, 100000, 100000), material);
      scene.add(mesh);

      return {
        'camera': camera,
        'scene': scene
      };
    }

    function getMousePointCloudIntersection() {
      var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
      vector.unproject(camera);
      var direction = vector.sub(camera.position).normalize();
      var ray = new THREE.Ray(camera.position, direction);

      var pointClouds = [];
      scene.traverse(function(object) {
        if (object instanceof Potree.PointCloudOctree) {
          pointClouds.push(object);
        }
      });

      var closestPoint = null;
      var closestPointDistance = null;

      for (var i = 0; i < pointClouds.length; i++) {
        var pointcloud = pointClouds[i];
        var point = pointcloud.pick(me.renderer, camera, ray, {
          accuracy: 0.5
        });

        if (!point) {
          continue;
        }

        var distance = camera.position.distanceTo(point.position);

        if (!closestPoint || distance < closestPointDistance) {
          closestPoint = point;
          closestPointDistance = distance;
        }
      }

      return closestPoint ? closestPoint.position : null;
    }

    function updateStats() {
      if (me.settings.showStats) {
        if (pointcloud) {
          me.stats.nrPoints = pointcloud.numVisiblePoints;
          me.stats.nrNodes = pointcloud.numVisibleNodes;
        } else {
          me.stats.nrPoints = 'none';
          me.stats.nrNodes = 'none';
        }

        var I = getMousePointCloudIntersection();
        if (I) {
          var sceneCoordinates = I;
          me.stats.sceneCoordinates.x = sceneCoordinates.x.toFixed(2);
          me.stats.sceneCoordinates.y = sceneCoordinates.y.toFixed(2);
          me.stats.sceneCoordinates.z = sceneCoordinates.z.toFixed(2);
          var geoCoordinates = toGeo(sceneCoordinates);
          me.stats.lasCoordinates.x = geoCoordinates.x.toFixed(2);
          me.stats.lasCoordinates.y = geoCoordinates.y.toFixed(2);
          me.stats.lasCoordinates.z = geoCoordinates.z.toFixed(2);
        }

        // stats are changed in requestAnimationFrame loop,
        // which is outside the AngularJS $digest loop
        // to have changes to stats propagated to angular, we need to trigger a digest
        $rootScope.$digest();
      }
    }

    function onMouseMove(event) {
      mouse.x = (event.clientX / me.renderer.domElement.clientWidth) * 2 - 1;
      mouse.y = -(event.clientY / me.renderer.domElement.clientHeight) * 2 + 1;
    }

    this.initThree = function() {

      var width = $window.innerWidth;
      var height = $window.innerHeight;

      scene = SceneService.getScene();
      camera = CameraService.camera;
      CameraService.toGeo = toGeo;

      me.renderer = new THREE.WebGLRenderer();
      me.renderer.setSize(width, height);
      me.renderer.autoClear = false;
      me.renderer.domElement.addEventListener('mousemove', onMouseMove, false);

      raycaster = new THREE.Raycaster();
      raycaster.params = {
          "PointCloud" : {
              threshold : 0.1
          }
      };

      skybox = loadSkybox('bower_components/potree/resources/textures/skybox/');

      // enable frag_depth extension for the interpolation shader, if available
      me.renderer.context.getExtension('EXT_frag_depth');

      referenceFrame = new THREE.Object3D();

      SiteBoxService.listenTo(me.renderer.domElement);

      DrivemapService.load().then(this.loadPointcloud);
    };

    this.loadPointcloud = function() {
      // load pointcloud
      pointcloudPath = DrivemapService.getPointcloudUrl();
      me.stats.lasCoordinates.crs = DrivemapService.getCrs();

      POCLoader.load(pointcloudPath, function(geometry) {
        pointcloud = new Potree.PointCloudOctree(geometry);

        pointcloud.material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
        pointcloud.material.size = me.settings.pointSize;
        pointcloud.visiblePointsTarget = me.settings.pointCountTarget * 1000 * 1000;

        referenceFrame.add(pointcloud);
        referenceFrame.updateMatrixWorld(true); // doesn't seem to do anything
        // reference frame position to pointcloud position:
        referenceFrame.position.set(-pointcloud.position.x, -pointcloud.position.y, 0);
        // rotates to some unknown orientation:
        referenceFrame.updateMatrixWorld(true);
        // rotates point cloud to align with horizon
        referenceFrame.applyMatrix(new THREE.Matrix4().set(
          1, 0, 0, 0,
          0, 0, 1, 0,
          0, -1, 0, 0,
          0, 0, 0, 1
        ));
        referenceFrame.updateMatrixWorld(true);
        scene.add(referenceFrame);

        var myPath = DrivemapService.getCoordinates().map(
          function(coord) {
            return toLocal(new THREE.Vector3(coord[0], coord[1], coord[2]));
          }
        );

        PathControls.init(camera, myPath, me.renderer.domElement);

		me.pathMesh = PathControls.createPath()
		scene.add(me.pathMesh);
		me.pathMesh.visible = false; // disabled by default

      });

    };

    this.loadSiteBoxes = function() {
      for (var ix=0; ix < SiteBoxService.siteBoxList.length; ix++) {
        referenceFrame.add(SiteBoxService.siteBoxList[ix]);
      }
    }

    /**
     * transform from geo coordinates to local scene coordinates
     */
    function toLocal(position) {

      var scenePos = position.clone().applyMatrix4(referenceFrame.matrixWorld);

      return scenePos;
    }

    /**
     * transform from local scene coordinates to geo coordinates
     */
    function toGeo(object) {
      var geo;
      var inverse = new THREE.Matrix4().getInverse(referenceFrame.matrixWorld);

      if (object instanceof THREE.Vector3) {
        geo = object.clone().applyMatrix4(inverse);
      } else if (object instanceof THREE.Box3) {
        var geoMin = object.min.clone().applyMatrix4(inverse);
        var geoMax = object.max.clone().applyMatrix4(inverse);
        geo = new THREE.Box3(geoMin, geoMax);
      }

      return geo;
    }

    function addTextLabel(message, x, y, z) {
      var canvas = document.createElement('canvas');
      var context = canvas.getContext('2d');
      // context.font = "Bold " + fontsize + "px " + fontface;

      // get size data (height depends only on font size)
      // var metrics = context.measureText(message);

      // background color
      // context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g +
      // ","
      // + backgroundColor.b + "," + backgroundColor.a + ")";

      // context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
      // + borderColor.b + "," + borderColor.a + ")";

      // context.lineWidth = borderThickness;
      // roundRect(context, borderThickness/2, borderThickness/2, textWidth +
      // borderThickness, fontsize * 1.4 + borderThickness, 6);
      // 1.4 is extra height factor for text below baseline: g,j,p,q.

      // text color
      // context.fillStyle = "rgba(0, 0, 0, 1.0)";

      // context.fillText( message, borderThickness, fontsize + borderThickness);

      var imageObj = new Image();
      imageObj.onload = function() {
        context.drawImage(imageObj, 10, 10);
        context.font = '40pt Calibri';
        context.fillText(message, 30, 70);
        // canvas contents will be used for a texture
        var texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;

        var spriteMaterial = new THREE.SpriteMaterial({
          map: texture,
          useScreenCoordinates: false,
        });
        var sprite = new THREE.Sprite(spriteMaterial);
        // sprite.scale.set(100,50,1.0);
        sprite.scale.set(10, 5, 1.0);

        sprite.position.set(x, y, z);
        referenceFrame.add(sprite);
      };
      imageObj.src = 'data/label-small.png';
    }

    this.goHome = function() {
      var locationGeo = DrivemapService.getHomeLocation();
      var lookAtGeo = DrivemapService.getHomeLookAt();
      var locationLocal = toLocal(locationGeo);
      var lookAtLocal = toLocal(lookAtGeo);

      camera.position.set(locationLocal.x, locationLocal.y, locationLocal.z);

      camera.lookAt(lookAtLocal);
    };

    this.lookAtSite = function(site) {
      var coordGeo = sitesservice.centerOfSite(site);
      var posGeo = new THREE.Vector3(coordGeo[0], coordGeo[1], coordGeo[2]);
      var posLocal = toLocal(posGeo);
      camera.lookAt(posLocal);
      var camPos = posLocal.clone().setY(posLocal.y + 20);
      camera.position.copy(camPos);
    };

    this.showLabel = function(site) {
      var message = site.properties.description;
      var coordGeo = sitesservice.centerOfSite(site);
      var posGeo = new THREE.Vector3(coordGeo[0], coordGeo[1], coordGeo[2] + 10);
      var posLocal = toLocal(posGeo);
      addTextLabel(message, posLocal.x, -posLocal.z, posLocal.y);
    };

    this.updateMapFrustum = function() {
      var aspect = camera.aspect;
      var top = Math.tan(THREE.Math.degToRad(camera.fov * 0.5)) * camera.near;
      var bottom = -top;
      var left = aspect * bottom;
      var right = aspect * top;

      var camPos = new THREE.Vector3(0, 0, 0);
      left = new THREE.Vector3(left, 0, -camera.near).multiplyScalar(3000);
      right = new THREE.Vector3(right, 0, -camera.near).multiplyScalar(3000);
      camPos.applyMatrix4(camera.matrixWorld);
      left.applyMatrix4(camera.matrixWorld);
      right.applyMatrix4(camera.matrixWorld);

      camPos = toGeo(camPos);
      left = toGeo(left);
      right = toGeo(right);

      Messagebus.publish('cameraMoved', {
        cam: camPos,
        left: left,
        right: right
      });
    };

    this.update = function() {

      if (pointcloud) {
        pointcloud.material.size = me.settings.pointSize;
        pointcloud.visiblePointsTarget = me.settings.pointCountTarget * 1000 * 1000;
        pointcloud.material.opacity = me.settings.opacity;
        pointcloud.material.pointSizeType = me.settings.pointSizeType;
        pointcloud.material.pointColorType = me.settings.pointColorType;
        pointcloud.material.pointShape = me.settings.pointShape;
        pointcloud.material.interpolate = me.settings.interpolate;
        pointcloud.material.heightMin = 0;
        pointcloud.material.heightMax = 8;
        pointcloud.material.intensityMin = 0;
        pointcloud.material.intensityMax = 65000;

        pointcloud.update(camera, me.renderer);

      }

      PathControls.updateInput();

      // create hash for camera state
      var cameraOrientation = new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorld).determinant();
      if (cameraOrientation !== prevCameraOrientation) {
        this.updateMapFrustum();
      }
      // compare current camera state with state in previous render loop
      prevCameraOrientation = cameraOrientation;
      updateStats();
    };

    this.render = function() {
      // resize
      var width = $window.innerWidth;
      var height = $window.innerHeight;
      var aspect = width / height;

      camera.aspect = aspect;
      camera.updateProjectionMatrix();

      me.renderer.setSize(width, height);

      // render skybox
      if (me.settings.showSkybox) {
        skybox.camera.rotation.copy(camera.rotation);
        me.renderer.render(skybox.scene, skybox.camera);
      }
      console.log("\n\n\n");
      console.log(camera.position);
      console.log(CameraService.camera.position);
      CameraService.camera.position.copy(camera.position);
      console.log(camera.position);
      console.log(CameraService.camera.position);

      // console.log(angular.copy(CameraService.camera));
      SiteBoxService.siteBoxSelection(mouse.x, mouse.y, raycaster);

            var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
            vector.unproject(camera);
            raycaster.ray.set(camera.position, vector.sub(camera.position).normalize());

            // hovering over SiteBoxes
            var intersects = raycaster.intersectObjects(SiteBoxService.siteBoxList, false);

            // reset hovering
            SiteBoxService.siteBoxList.forEach(function (siteBox) {
                SiteBoxService.hoverOut(siteBox);
            });

            if (intersects.length > 0) {
                SiteBoxService.hoverOver(intersects[0].object);
            }

      // render scene
      me.renderer.render(scene, camera);

	  //MeasuringService.measuringTool.render();
    };

    this.loop = function() {
      requestAnimationFrame(me.loop);

      me.update();
      me.render();
    };

    this.attachCanvas = function(el) {
      me.elRenderArea = el;
      me.initThree();
      var canvas = me.renderer.domElement;
      el.appendChild(canvas);
      me.loop();
    };

    $rootScope.$watch(function() {
      return SiteBoxService.siteBoxList;
    }, this.loadSiteBoxes);

    // $rootScope.$watch(function (){
    //   return raycaster.intersectObjects(SiteBoxService.siteBoxList, false);
    // }, console.log);

  }

  angular.module('pattyApp.pointcloud')
    .service('PointcloudService', PointcloudService);
})();
<commit_msg>Moved SiteBox selection to SiteBoxService<commit_after>(function() {
  'use strict';

  function PointcloudService(THREE, Potree, POCLoader, $window, $rootScope, Messagebus, DrivemapService, sitesservice, CameraService, SceneService, PathControls, SiteBoxService) {

    var me = this;

    this.elRenderArea = null;

    me.settings = {
      pointCountTarget: 1.0,
      pointSize: 0.2,
      opacity: 1,
      showSkybox: true,
      interpolate: false,
      showStats: false,
      pointSizeType: Potree.PointSizeType.ATTENUATED,
      pointSizeTypes: Potree.PointSizeType,
      pointColorType: Potree.PointColorType.RGB,
      pointColorTypes: Potree.PointColorType,
      pointShapes: Potree.PointShape,
      pointShape: Potree.PointShape.SQUARE
    };

    me.stats = {
      nrPoints: 0,
      nrNodes: 0,
      sceneCoordinates: {
        x: 0,
        y: 0,
        z: 0
      },
      lasCoordinates: {
        x: 0,
        y: 0,
        z: 0,
        crs: 'unknown'
      }
    };

    var pointcloudPath = 'data/out_8/cloud.js';
    this.renderer = null;
    var camera;
    var scene;
    var raycaster;
    var pointcloud;
    var skybox;

	me.pathMesh = null;
    var prevCameraOrientation;

    var referenceFrame;
    var mouse = {
      x: 0,
      y: 0
    };

    function loadSkybox(path) {
      var scene = SceneService.getScene();

      var format = '.jpg';
      var urls = [
        path + 'px' + format, path + 'nx' + format,
        path + 'py' + format, path + 'ny' + format,
        path + 'pz' + format, path + 'nz' + format
      ];

      var textureCube = THREE.ImageUtils.loadTextureCube(urls, new THREE.CubeRefractionMapping());

      var shader = THREE.ShaderLib.cube;
      shader.uniforms.tCube.value = textureCube;

      var material = new THREE.ShaderMaterial({

          fragmentShader: shader.fragmentShader,
          vertexShader: shader.vertexShader,
          uniforms: shader.uniforms,
          depthWrite: false,
          side: THREE.BackSide

        }),

        mesh = new THREE.Mesh(new THREE.BoxGeometry(100000, 100000, 100000), material);
      scene.add(mesh);

      return {
        'camera': camera,
        'scene': scene
      };
    }

    function getMousePointCloudIntersection() {
      var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
      vector.unproject(camera);
      var direction = vector.sub(camera.position).normalize();
      var ray = new THREE.Ray(camera.position, direction);

      var pointClouds = [];
      scene.traverse(function(object) {
        if (object instanceof Potree.PointCloudOctree) {
          pointClouds.push(object);
        }
      });

      var closestPoint = null;
      var closestPointDistance = null;

      for (var i = 0; i < pointClouds.length; i++) {
        var pointcloud = pointClouds[i];
        var point = pointcloud.pick(me.renderer, camera, ray, {
          accuracy: 0.5
        });

        if (!point) {
          continue;
        }

        var distance = camera.position.distanceTo(point.position);

        if (!closestPoint || distance < closestPointDistance) {
          closestPoint = point;
          closestPointDistance = distance;
        }
      }

      return closestPoint ? closestPoint.position : null;
    }

    function updateStats() {
      if (me.settings.showStats) {
        if (pointcloud) {
          me.stats.nrPoints = pointcloud.numVisiblePoints;
          me.stats.nrNodes = pointcloud.numVisibleNodes;
        } else {
          me.stats.nrPoints = 'none';
          me.stats.nrNodes = 'none';
        }

        var I = getMousePointCloudIntersection();
        if (I) {
          var sceneCoordinates = I;
          me.stats.sceneCoordinates.x = sceneCoordinates.x.toFixed(2);
          me.stats.sceneCoordinates.y = sceneCoordinates.y.toFixed(2);
          me.stats.sceneCoordinates.z = sceneCoordinates.z.toFixed(2);
          var geoCoordinates = toGeo(sceneCoordinates);
          me.stats.lasCoordinates.x = geoCoordinates.x.toFixed(2);
          me.stats.lasCoordinates.y = geoCoordinates.y.toFixed(2);
          me.stats.lasCoordinates.z = geoCoordinates.z.toFixed(2);
        }

        // stats are changed in requestAnimationFrame loop,
        // which is outside the AngularJS $digest loop
        // to have changes to stats propagated to angular, we need to trigger a digest
        $rootScope.$digest();
      }
    }

    function onMouseMove(event) {
      mouse.x = (event.clientX / me.renderer.domElement.clientWidth) * 2 - 1;
      mouse.y = -(event.clientY / me.renderer.domElement.clientHeight) * 2 + 1;
    }

    this.initThree = function() {

      var width = $window.innerWidth;
      var height = $window.innerHeight;

      scene = SceneService.getScene();
      camera = CameraService.camera;
      CameraService.toGeo = toGeo;

      me.renderer = new THREE.WebGLRenderer();
      me.renderer.setSize(width, height);
      me.renderer.autoClear = false;
      me.renderer.domElement.addEventListener('mousemove', onMouseMove, false);

      raycaster = new THREE.Raycaster();
      raycaster.params = {
          "PointCloud" : {
              threshold : 0.1
          }
      };

      skybox = loadSkybox('bower_components/potree/resources/textures/skybox/');

      // enable frag_depth extension for the interpolation shader, if available
      me.renderer.context.getExtension('EXT_frag_depth');

      referenceFrame = new THREE.Object3D();

      SiteBoxService.listenTo(me.renderer.domElement);

      DrivemapService.load().then(this.loadPointcloud);
    };

    this.loadPointcloud = function() {
      // load pointcloud
      pointcloudPath = DrivemapService.getPointcloudUrl();
      me.stats.lasCoordinates.crs = DrivemapService.getCrs();

      POCLoader.load(pointcloudPath, function(geometry) {
        pointcloud = new Potree.PointCloudOctree(geometry);

        pointcloud.material.pointSizeType = Potree.PointSizeType.ADAPTIVE;
        pointcloud.material.size = me.settings.pointSize;
        pointcloud.visiblePointsTarget = me.settings.pointCountTarget * 1000 * 1000;

        referenceFrame.add(pointcloud);
        referenceFrame.updateMatrixWorld(true); // doesn't seem to do anything
        // reference frame position to pointcloud position:
        referenceFrame.position.set(-pointcloud.position.x, -pointcloud.position.y, 0);
        // rotates to some unknown orientation:
        referenceFrame.updateMatrixWorld(true);
        // rotates point cloud to align with horizon
        referenceFrame.applyMatrix(new THREE.Matrix4().set(
          1, 0, 0, 0,
          0, 0, 1, 0,
          0, -1, 0, 0,
          0, 0, 0, 1
        ));
        referenceFrame.updateMatrixWorld(true);
        scene.add(referenceFrame);

        var myPath = DrivemapService.getCoordinates().map(
          function(coord) {
            return toLocal(new THREE.Vector3(coord[0], coord[1], coord[2]));
          }
        );

        PathControls.init(camera, myPath, me.renderer.domElement);

		me.pathMesh = PathControls.createPath()
		scene.add(me.pathMesh);
		me.pathMesh.visible = false; // disabled by default

      });

    };

    this.loadSiteBoxes = function() {
      for (var ix=0; ix < SiteBoxService.siteBoxList.length; ix++) {
        referenceFrame.add(SiteBoxService.siteBoxList[ix]);
      }
    }

    /**
     * transform from geo coordinates to local scene coordinates
     */
    function toLocal(position) {

      var scenePos = position.clone().applyMatrix4(referenceFrame.matrixWorld);

      return scenePos;
    }

    /**
     * transform from local scene coordinates to geo coordinates
     */
    function toGeo(object) {
      var geo;
      var inverse = new THREE.Matrix4().getInverse(referenceFrame.matrixWorld);

      if (object instanceof THREE.Vector3) {
        geo = object.clone().applyMatrix4(inverse);
      } else if (object instanceof THREE.Box3) {
        var geoMin = object.min.clone().applyMatrix4(inverse);
        var geoMax = object.max.clone().applyMatrix4(inverse);
        geo = new THREE.Box3(geoMin, geoMax);
      }

      return geo;
    }

    function addTextLabel(message, x, y, z) {
      var canvas = document.createElement('canvas');
      var context = canvas.getContext('2d');
      // context.font = "Bold " + fontsize + "px " + fontface;

      // get size data (height depends only on font size)
      // var metrics = context.measureText(message);

      // background color
      // context.fillStyle = "rgba(" + backgroundColor.r + "," + backgroundColor.g +
      // ","
      // + backgroundColor.b + "," + backgroundColor.a + ")";

      // context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
      // + borderColor.b + "," + borderColor.a + ")";

      // context.lineWidth = borderThickness;
      // roundRect(context, borderThickness/2, borderThickness/2, textWidth +
      // borderThickness, fontsize * 1.4 + borderThickness, 6);
      // 1.4 is extra height factor for text below baseline: g,j,p,q.

      // text color
      // context.fillStyle = "rgba(0, 0, 0, 1.0)";

      // context.fillText( message, borderThickness, fontsize + borderThickness);

      var imageObj = new Image();
      imageObj.onload = function() {
        context.drawImage(imageObj, 10, 10);
        context.font = '40pt Calibri';
        context.fillText(message, 30, 70);
        // canvas contents will be used for a texture
        var texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;

        var spriteMaterial = new THREE.SpriteMaterial({
          map: texture,
          useScreenCoordinates: false,
        });
        var sprite = new THREE.Sprite(spriteMaterial);
        // sprite.scale.set(100,50,1.0);
        sprite.scale.set(10, 5, 1.0);

        sprite.position.set(x, y, z);
        referenceFrame.add(sprite);
      };
      imageObj.src = 'data/label-small.png';
    }

    this.goHome = function() {
      var locationGeo = DrivemapService.getHomeLocation();
      var lookAtGeo = DrivemapService.getHomeLookAt();
      var locationLocal = toLocal(locationGeo);
      var lookAtLocal = toLocal(lookAtGeo);

      camera.position.set(locationLocal.x, locationLocal.y, locationLocal.z);

      camera.lookAt(lookAtLocal);
    };

    this.lookAtSite = function(site) {
      var coordGeo = sitesservice.centerOfSite(site);
      var posGeo = new THREE.Vector3(coordGeo[0], coordGeo[1], coordGeo[2]);
      var posLocal = toLocal(posGeo);
      camera.lookAt(posLocal);
      var camPos = posLocal.clone().setY(posLocal.y + 20);
      camera.position.copy(camPos);
    };

    this.showLabel = function(site) {
      var message = site.properties.description;
      var coordGeo = sitesservice.centerOfSite(site);
      var posGeo = new THREE.Vector3(coordGeo[0], coordGeo[1], coordGeo[2] + 10);
      var posLocal = toLocal(posGeo);
      addTextLabel(message, posLocal.x, -posLocal.z, posLocal.y);
    };

    this.updateMapFrustum = function() {
      var aspect = camera.aspect;
      var top = Math.tan(THREE.Math.degToRad(camera.fov * 0.5)) * camera.near;
      var bottom = -top;
      var left = aspect * bottom;
      var right = aspect * top;

      var camPos = new THREE.Vector3(0, 0, 0);
      left = new THREE.Vector3(left, 0, -camera.near).multiplyScalar(3000);
      right = new THREE.Vector3(right, 0, -camera.near).multiplyScalar(3000);
      camPos.applyMatrix4(camera.matrixWorld);
      left.applyMatrix4(camera.matrixWorld);
      right.applyMatrix4(camera.matrixWorld);

      camPos = toGeo(camPos);
      left = toGeo(left);
      right = toGeo(right);

      Messagebus.publish('cameraMoved', {
        cam: camPos,
        left: left,
        right: right
      });
    };

    this.update = function() {

      if (pointcloud) {
        pointcloud.material.size = me.settings.pointSize;
        pointcloud.visiblePointsTarget = me.settings.pointCountTarget * 1000 * 1000;
        pointcloud.material.opacity = me.settings.opacity;
        pointcloud.material.pointSizeType = me.settings.pointSizeType;
        pointcloud.material.pointColorType = me.settings.pointColorType;
        pointcloud.material.pointShape = me.settings.pointShape;
        pointcloud.material.interpolate = me.settings.interpolate;
        pointcloud.material.heightMin = 0;
        pointcloud.material.heightMax = 8;
        pointcloud.material.intensityMin = 0;
        pointcloud.material.intensityMax = 65000;

        pointcloud.update(camera, me.renderer);

      }

      PathControls.updateInput();

      // create hash for camera state
      var cameraOrientation = new THREE.Matrix4().multiplyMatrices(camera.projectionMatrix, camera.matrixWorld).determinant();
      if (cameraOrientation !== prevCameraOrientation) {
        this.updateMapFrustum();
      }
      // compare current camera state with state in previous render loop
      prevCameraOrientation = cameraOrientation;
      updateStats();
    };

    this.render = function() {
      // resize
      var width = $window.innerWidth;
      var height = $window.innerHeight;
      var aspect = width / height;

      camera.aspect = aspect;
      camera.updateProjectionMatrix();

      me.renderer.setSize(width, height);

      // render skybox
      if (me.settings.showSkybox) {
        skybox.camera.rotation.copy(camera.rotation);
        me.renderer.render(skybox.scene, skybox.camera);
      }
      CameraService.camera.position.copy(camera.position);

      SiteBoxService.siteBoxSelection(mouse.x, mouse.y, raycaster);

      // render scene
      me.renderer.render(scene, camera);

	  //MeasuringService.measuringTool.render();
    };

    this.loop = function() {
      requestAnimationFrame(me.loop);

      me.update();
      me.render();
    };

    this.attachCanvas = function(el) {
      me.elRenderArea = el;
      me.initThree();
      var canvas = me.renderer.domElement;
      el.appendChild(canvas);
      me.loop();
    };

    $rootScope.$watch(function() {
      return SiteBoxService.siteBoxList;
    }, this.loadSiteBoxes);

    // $rootScope.$watch(function (){
    //   return raycaster.intersectObjects(SiteBoxService.siteBoxList, false);
    // }, console.log);

  }

  angular.module('pattyApp.pointcloud')
    .service('PointcloudService', PointcloudService);
})();
<|endoftext|>


<commit_before>'use strict';

angular
  .module('cluster.filter.service', ['cluster.filter.model'])
  .factory('ClusterFilterService', function ($location, _, clusterFilterModel) {

    function updateQueryParams() {
      $location.search('q',
          clusterFilterModel.filter.length > 0 ? clusterFilterModel.filter : null);
//      $location.search('hideHealth', sortFilter.hideHealthy ? true : null);
//      $location.search('hideInstances', sortFilter.showAllInstances ? null : true);
//      $location.search('hideDisabled', sortFilter.hideDisabled ? true : null);
//      $location.search('primary',
//          sortFilter.sortPrimary===defPrimary ? null: sortFilter.sortPrimary);
//      $location.search('secondary',
//          sortFilter.sortSecondary===defSecondary ? null:sortFilter.sortSecondary);
    }

    function updateClusterGroups(application) {
      var filter = clusterFilterModel.filter.toLowerCase();
//      var groups = [];
//      var totalInstancesDisplayed = 0;
      var serverGroups = filterServerGroupsForDisplay(application.serverGroups, application.cluster, filter);

//      var grouped = _.groupBy(serverGroups, primarySort);

      return serverGroups;

    }

    function filterServerGroupsForDisplay(serverGroups, clusters, filter) {
      return  _.chain(clusters)
        .collect('serverGroups')
        .flatten()
        .filter(function(serverGroup) {
          if (!filter) {
            return true;
          }
          return filter.split(' ').every(function(testWord) {
            return serverGroup.searchField.indexOf(testWord) !== -1;
          });
        })
//        .filter(checkAgainstActiveFilters)
        .value();
    }

    return {
      sortFilter: clusterFilterModel.sortFilter,
      updateQueryParams: updateQueryParams,
      updateClusterGroups: updateClusterGroups,
      filterServerGroupsForDisplay: filterServerGroupsForDisplay
    };
  }
);

<commit_msg>cleaning up redundant file<commit_after><|endoftext|>


<commit_before><commit_msg>added nlsn-chart-helper-svc comment<commit_after><|endoftext|>


<commit_before>define(function(require, exports, module) {

    // import famous material
    var Paper = require('famous-material/components/Paper');

    // import famous flex
    var LayoutController = require('famous-flex/LayoutController');
    var NavBarLayout = require('famous-flex/layouts/NavBarLayout');

    // import vanilla famo.us
    var Modifier = require('famous/core/Modifier');
    var Transform = require('famous/core/Transform');
    var Surface = require('famous/core/Surface');
    var Timer = require('famous/utilities/Timer');
    var ImageSurface = require('famous/surfaces/ImageSurface');

    /**
     * @class YouTubeVideo
     * @constructor
     * @param [options]
     *            {Object} Options to override the Paper with.
     */
    function YouTubeVideo(json) {
        Paper.call(this, YouTubeVideo.DEFAULT_OPTIONS);

        var video = video = {
            id : json.id,
            title : json.snippet.title,
            description : json.snippet.description,
            thumbnail : json.snippet.thumbnails['default']
        };

        var thumbnail = new Paper({
            size : [video.thumbnail.width, video.thumbnail.height],
            content : video.thumbnail.url,
            backing : new ImageSurface()
        });

        var title = new Paper({
            content : video.title
        });

        var description = new Paper({
            content : video.description
        });

        this.skelware.video = video;
        this.add(thumbnail);
    }

    YouTubeVideo.prototype = Object.create(Paper.prototype);
    YouTubeVideo.prototype.constructor = YouTubeVideo;
    module.exports = YouTubeVideo;

    YouTubeVideo.DEFAULT_OPTIONS = {
        depth : 5,
        size : [, 100],
        type : Paper.TYPE_TILE
    };
});
<commit_msg>Use the new built-in translation<commit_after>define(function(require, exports, module) {

    // import famous material
    var Paper = require('famous-material/components/Paper');

    // import famous flex
    var LayoutController = require('famous-flex/LayoutController');
    var NavBarLayout = require('famous-flex/layouts/NavBarLayout');

    // import vanilla famo.us
    var Modifier = require('famous/core/Modifier');
    var Transform = require('famous/core/Transform');
    var Surface = require('famous/core/Surface');
    var Timer = require('famous/utilities/Timer');
    var ImageSurface = require('famous/surfaces/ImageSurface');

    /**
     * @class YouTubeVideo
     * @constructor
     * @param [options]
     *            {Object} Options to override the Paper with.
     */
    function YouTubeVideo(json) {
        Paper.call(this, YouTubeVideo.DEFAULT_OPTIONS);

        var video = video = {
            id : json.id,
            title : json.snippet.title,
            description : json.snippet.description,
            thumbnail : json.snippet.thumbnails['default']
        };

        var thumbnail = new Paper({
            size : [video.thumbnail.width, video.thumbnail.height],
            content : video.thumbnail.url,
            backing : new ImageSurface()
        });

        var title = new Paper({
            content : video.title
        });

        var description = new Paper({
            content : video.description
        });

        this.skelware.video = video;
        this.add(thumbnail, 5, 5);
    }

    YouTubeVideo.prototype = Object.create(Paper.prototype);
    YouTubeVideo.prototype.constructor = YouTubeVideo;
    module.exports = YouTubeVideo;

    YouTubeVideo.DEFAULT_OPTIONS = {
        depth : 5,
        size : [, 100],
        type : Paper.TYPE_TILE
    };
});
<|endoftext|>


<commit_before>exports.ALLOY_DIR = 'app';
exports.GLOBAL_STYLE = 'app.tss';
exports.ROOT_NODE = 'Component';

exports.FILE_EXT = {
	VIEW: 'xml',
	STYLE: 'tss',
	MODEL: 'json',
	MIGRATION: 'js',
	CONTROLLER: 'js',
	CONFIG: 'json'
};

exports.DIR = {
	VIEW: 'views',
	STYLE: 'styles',
	CONTROLLER: 'controllers',
	MODEL: 'models',
	MIGRATION: 'migrations',
	CONFIG: 'config',
	ASSETS: 'assets',
	WIDGET: 'widgets',
	LIB: 'lib',
	VENDOR: 'vendor',
	COMPONENT: 'components'
};<commit_msg>changed root node to Alloy<commit_after>exports.ALLOY_DIR = 'app';
exports.GLOBAL_STYLE = 'app.tss';
exports.ROOT_NODE = 'Alloy';

exports.FILE_EXT = {
	VIEW: 'xml',
	STYLE: 'tss',
	MODEL: 'json',
	MIGRATION: 'js',
	CONTROLLER: 'js',
	CONFIG: 'json'
};

exports.DIR = {
	VIEW: 'views',
	STYLE: 'styles',
	CONTROLLER: 'controllers',
	MODEL: 'models',
	MIGRATION: 'migrations',
	CONFIG: 'config',
	ASSETS: 'assets',
	WIDGET: 'widgets',
	LIB: 'lib',
	VENDOR: 'vendor',
	COMPONENT: 'components'
};<|endoftext|>


<commit_before>import path from 'path';
import webdriver from 'selenium-webdriver';
import { expect } from 'chai';
import { delay, startChromeDriver, buildWebDriver } from '../func';
import footerStyle from '../../app/components/Footer.css';
import mainSectionStyle from '../../app/components/MainSection.css';
import todoItemStyle from '../../app/components/TodoItem.css';
import todoTextInputStyle from '../../app/components/TodoTextInput.css';

const findList = driver =>
  driver.findElements(webdriver.By.css(`.${mainSectionStyle.todoList} > li`));

const addTodo = async (driver, key) => {
  // add todo
  driver.findElement(webdriver.By.className(todoTextInputStyle.new))
    .sendKeys(key + webdriver.Key.RETURN);
  await delay(1000);
  const todos = await findList(driver);
  return { todo: todos[0], count: todos.length };
};

const editTodo = async (driver, index, key) => {
  let todos = await findList(driver);
  const label = todos[index].findElement(webdriver.By.tagName('label'));
  // dbl click to enable textarea
  await driver.actions().doubleClick(label).perform();
  await delay(500);
  // typing & enter
  driver.actions().sendKeys(key + webdriver.Key.RETURN).perform();
  await delay(1000);

  todos = await findList(driver);
  return { todo: todos[index], count: todos.length };
};

const completeTodo = async (driver, index) => {
  let todos = await findList(driver);
  todos[index].findElement(webdriver.By.className(todoItemStyle.toggle)).click();
  await delay(1000);
  todos = await findList(driver);
  return { todo: todos[index], count: todos.length };
};

const deleteTodo = async (driver, index) => {
  let todos = await findList(driver);
  driver.executeScript(
    `document.querySelectorAll('.${mainSectionStyle.todoList} > li')[${index}]
      .getElementsByClassName('${todoItemStyle.destroy}')[0].style.display = 'block'`
  );
  todos[index].findElement(webdriver.By.className(todoItemStyle.destroy)).click();
  await delay(1000);
  todos = await findList(driver);
  return { count: todos.length };
};

describe('window (popup) page', function test() {
  let driver;
  this.timeout(15000);

  before(async () => {
    await startChromeDriver();
    const extPath = path.resolve('build');
    driver = buildWebDriver(extPath);
    await driver.get('chrome://extensions-frame');
    const elems = await driver.findElements(webdriver.By.className('extension-list-item-wrapper'));
    let extensionId;
    for (const elem of elems) {
      extensionId = extensionId || await elem.getAttribute('id');
    }
    await driver.get(`chrome-extension://${extensionId}/window.html`);
  });

  after(async () => driver.quit());

  it('should open Redux TodoMVC Example', async () => {
    const title = await driver.getTitle();
    expect(title).to.equal('Redux TodoMVC Example (Window)');
  });

  it('should can add todo', async () => {
    const { todo, count } = await addTodo(driver, 'Add tests');
    expect(count).to.equal(2);
    const text = await todo.findElement(webdriver.By.tagName('label')).getText();
    expect(text).to.equal('Add tests');
  });

  it('should can edit todo', async () => {
    const { todo, count } = await editTodo(driver, 0, 'Ya ');
    expect(count).to.equal(2);
    const text = await todo.findElement(webdriver.By.tagName('label')).getText();
    expect(text).to.equal('Add testsYa');
  });

  it('should can complete todo', async () => {
    const { todo, count } = await completeTodo(driver, 0);
    expect(count).to.equal(2);
    const className = await todo.getAttribute('class');
    const { completed, normal } = todoItemStyle;
    expect(className).to.equal(`${completed} ${normal}`);
  });

  it('should can complete all todos', async () => {
    driver.findElement(webdriver.By.className(mainSectionStyle.toggleAll)).click();
    const todos = await findList(driver);
    const classNames = await Promise.all(todos.map(todo => todo.getAttribute('class')));
    const { completed, normal } = todoItemStyle;
    expect(classNames.every(name => name === `${completed} ${normal}`)).to.equal(true);
  });

  it('should can delete todo', async () => {
    const { count } = await deleteTodo(driver, 0);
    expect(count).to.equal(1);
  });

  it('should can clear completed todos if completed todos count > 0', async () => {
    // current todo count: 1
    await addTodo(driver, 'Add 1');
    const { count } = await addTodo(driver, 'Add 2');
    expect(count).to.equal(3);

    await completeTodo(driver, 0);
    driver.findElement(webdriver.By.className(footerStyle.clearCompleted)).click();

    const todos = await findList(driver);
    const classNames = await Promise.all(todos.map(todo => todo.getAttribute('class')));
    expect(classNames.every(name => name !== 'completed')).to.equal(true);
  });

  it('should cannot clear completed todos if completed todos count = 0', async () => {
    const todos = await driver.findElements(webdriver.By.className(footerStyle.clearCompleted));
    expect(todos.length).to.equal(0);
  });

  it('should can filter active todos', async () => {
    // current todo count: 2
    await addTodo(driver, 'Add 1');
    const { count } = await addTodo(driver, 'Add 2');
    expect(count).to.equal(3);

    await completeTodo(driver, 0);
    let todos = await driver.findElements(webdriver.By.css(`.${footerStyle.filters} > li`));
    todos[1].click();
    await delay(1000);
    todos = await findList(driver);
    expect(todos.length).to.equal(2);
  });

  it('should can filter completed todos', async () => {
    // current todo count: 2
    let todos = await driver.findElements(webdriver.By.css(`.${footerStyle.filters} > li`));
    todos[2].click();
    await delay(1000);
    todos = await findList(driver);
    expect(todos.length).to.equal(1);
  });
});
<commit_msg>Use xpath with extension name to get extension id for E2E test<commit_after>import path from 'path';
import webdriver from 'selenium-webdriver';
import { expect } from 'chai';
import { delay, startChromeDriver, buildWebDriver } from '../func';
import footerStyle from '../../app/components/Footer.css';
import mainSectionStyle from '../../app/components/MainSection.css';
import todoItemStyle from '../../app/components/TodoItem.css';
import todoTextInputStyle from '../../app/components/TodoTextInput.css';
import manifest from '../../build/manifest.json';

const extensionName = manifest.name;

const findList = driver =>
  driver.findElements(webdriver.By.css(`.${mainSectionStyle.todoList} > li`));

const addTodo = async (driver, key) => {
  // add todo
  driver.findElement(webdriver.By.className(todoTextInputStyle.new))
    .sendKeys(key + webdriver.Key.RETURN);
  await delay(1000);
  const todos = await findList(driver);
  return { todo: todos[0], count: todos.length };
};

const editTodo = async (driver, index, key) => {
  let todos = await findList(driver);
  const label = todos[index].findElement(webdriver.By.tagName('label'));
  // dbl click to enable textarea
  await driver.actions().doubleClick(label).perform();
  await delay(500);
  // typing & enter
  driver.actions().sendKeys(key + webdriver.Key.RETURN).perform();
  await delay(1000);

  todos = await findList(driver);
  return { todo: todos[index], count: todos.length };
};

const completeTodo = async (driver, index) => {
  let todos = await findList(driver);
  todos[index].findElement(webdriver.By.className(todoItemStyle.toggle)).click();
  await delay(1000);
  todos = await findList(driver);
  return { todo: todos[index], count: todos.length };
};

const deleteTodo = async (driver, index) => {
  let todos = await findList(driver);
  driver.executeScript(
    `document.querySelectorAll('.${mainSectionStyle.todoList} > li')[${index}]
      .getElementsByClassName('${todoItemStyle.destroy}')[0].style.display = 'block'`
  );
  todos[index].findElement(webdriver.By.className(todoItemStyle.destroy)).click();
  await delay(1000);
  todos = await findList(driver);
  return { count: todos.length };
};

describe('window (popup) page', function test() {
  let driver;
  this.timeout(15000);

  before(async () => {
    await startChromeDriver();
    const extPath = path.resolve('build');
    driver = buildWebDriver(extPath);
    await driver.get('chrome://extensions-frame');
    const elems = await driver.findElements(webdriver.By.xpath(
      '//div[contains(@class, "extension-list-item-wrapper") and ' +
      `.//h2[contains(text(), "${extensionName}")]]`
    ));
    const extensionId = await elems[0].getAttribute('id');
    await driver.get(`chrome-extension://${extensionId}/window.html`);
  });

  after(async () => driver.quit());

  it('should open Redux TodoMVC Example', async () => {
    const title = await driver.getTitle();
    expect(title).to.equal('Redux TodoMVC Example (Window)');
  });

  it('should can add todo', async () => {
    const { todo, count } = await addTodo(driver, 'Add tests');
    expect(count).to.equal(2);
    const text = await todo.findElement(webdriver.By.tagName('label')).getText();
    expect(text).to.equal('Add tests');
  });

  it('should can edit todo', async () => {
    const { todo, count } = await editTodo(driver, 0, 'Ya ');
    expect(count).to.equal(2);
    const text = await todo.findElement(webdriver.By.tagName('label')).getText();
    expect(text).to.equal('Add testsYa');
  });

  it('should can complete todo', async () => {
    const { todo, count } = await completeTodo(driver, 0);
    expect(count).to.equal(2);
    const className = await todo.getAttribute('class');
    const { completed, normal } = todoItemStyle;
    expect(className).to.equal(`${completed} ${normal}`);
  });

  it('should can complete all todos', async () => {
    driver.findElement(webdriver.By.className(mainSectionStyle.toggleAll)).click();
    const todos = await findList(driver);
    const classNames = await Promise.all(todos.map(todo => todo.getAttribute('class')));
    const { completed, normal } = todoItemStyle;
    expect(classNames.every(name => name === `${completed} ${normal}`)).to.equal(true);
  });

  it('should can delete todo', async () => {
    const { count } = await deleteTodo(driver, 0);
    expect(count).to.equal(1);
  });

  it('should can clear completed todos if completed todos count > 0', async () => {
    // current todo count: 1
    await addTodo(driver, 'Add 1');
    const { count } = await addTodo(driver, 'Add 2');
    expect(count).to.equal(3);

    await completeTodo(driver, 0);
    driver.findElement(webdriver.By.className(footerStyle.clearCompleted)).click();

    const todos = await findList(driver);
    const classNames = await Promise.all(todos.map(todo => todo.getAttribute('class')));
    expect(classNames.every(name => name !== 'completed')).to.equal(true);
  });

  it('should cannot clear completed todos if completed todos count = 0', async () => {
    const todos = await driver.findElements(webdriver.By.className(footerStyle.clearCompleted));
    expect(todos.length).to.equal(0);
  });

  it('should can filter active todos', async () => {
    // current todo count: 2
    await addTodo(driver, 'Add 1');
    const { count } = await addTodo(driver, 'Add 2');
    expect(count).to.equal(3);

    await completeTodo(driver, 0);
    let todos = await driver.findElements(webdriver.By.css(`.${footerStyle.filters} > li`));
    todos[1].click();
    await delay(1000);
    todos = await findList(driver);
    expect(todos.length).to.equal(2);
  });

  it('should can filter completed todos', async () => {
    // current todo count: 2
    let todos = await driver.findElements(webdriver.By.css(`.${footerStyle.filters} > li`));
    todos[2].click();
    await delay(1000);
    todos = await findList(driver);
    expect(todos.length).to.equal(1);
  });
});
<|endoftext|>


<commit_before>var alexa = require('alexa-app');
var request = require('request-promise');
var express = require('express');

var express_app = express();

var app = new alexa.app('connect');
app.express({ expressApp: express_app });

app.pre = function (request, response, type) {
    if (request.applicationId != "amzn1.ask.skill.33d79728-0f5a-44e7-ae22-ccf0b0c0e9e0") {
        throw "Invalid applicationId";
    }
};

app.intent('PlayIntent', {
    "utterances": [
        "play",
        "resume",
        "continue"
    ]
},
    function (req, res) {
        request.put("https://api.spotify.com/v1/me/player/play").auth(null, null, true, req.getSession().get("accessToken"));
        res.say('Playing');
    }
);

app.intent('PauseIntent', {
    "utterances": [
        "pause"
    ]
},
    function (req, res) {
        request.put("https://api.spotify.com/v1/me/player/pause").auth(null, null, true, req.getSession().get("accessToken"));
        res.say('Paused');
    }
);

app.intent('GetDevicesIntent', {
    "utterances": [
        "devices",
        "list",
        "search",
        "find"
    ]
},
    function (req, res) {
        return request.get({
            url: "https://api.spotify.com/v1/me/player/devices",
            auth: {
                "bearer": req.getSession().get("accessToken")
            },
            json: true
        })
            .then(function (body) {
                var devices = body.devices || [];
                var deviceNames = [];
                res.say("I found these connect devices:");
                for (var i = 0; i < devices.length; i++) {
                    //Number each device
                    deviceNames.push((i + 1) + ". " + devices[i].name);
                    //Add the device number to JSON
                    devices[i].number = (i + 1);
                }
                //Comma separated list of device names
                res.say([deviceNames.slice(0, -1).join(', '), deviceNames.slice(-1)[0]].join(deviceNames.length < 2 ? '' : ', and '));
                req.getSession().set("devices", devices);
                res.shouldEndSession(false);
            })
            .catch(function (err) {
                console.error('error:', err.message);
            });
    }
);

app.intent('DevicePlayIntent', {
    "slots": {
        "DEVICENUMBER": "AMAZON.NUMBER"
    },
    "utterances": [
        "play on {-|DEVICENUMBER}",
        "play on number {-|DEVICENUMBER}",
        "play on device {-|DEVICENUMBER}",
        "play on device number {-|DEVICENUMBER}"
    ]
},
    function (req, res) {
        if (req.hasSession()) {
            if (req.slot("DEVICENUMBER")) {
                var deviceNumber = req.slot("DEVICENUMBER");
                var devices = req.getSession().get("devices") || [];
                var deviceId, deviceName;
                for (var i = 0; i < devices.length; i++) {
                    if (devices[i].number == deviceNumber) {
                        deviceId = devices[i].id;
                        deviceName = devices[i].name;
                    }
                }
                request.put({
                    url: "https://api.spotify.com/v1/me/player",
                    auth: {
                        "bearer": req.getSession().get("accessToken")
                    },
                    body: {
                        "device_ids": [
                            deviceId
                        ],
                        "play": true
                    },
                    json: true
                });
                res.say("Playing on device " + deviceNumber + ": " + deviceName);
            }
        }
    });

express_app.use(express.static(__dirname));
express_app.get('/', function (req, res) {
    res.redirect('https://github.com/thorpelawrence/alexa-spotify-connect');
});

app.intent('DeviceTransferIntent', {
    "slots": {
        "DEVICENUMBER": "AMAZON.NUMBER"
    },
    "utterances": [
        "transfer to {-|DEVICENUMBER}",
        "transfer to number {-|DEVICENUMBER}",
        "transfer to device {-|DEVICENUMBER}",
        "transfer to device number {-|DEVICENUMBER}"
    ]
},
    function (req, res) {
        if (req.hasSession()) {
            if (req.slot("DEVICENUMBER")) {
                var deviceNumber = req.slot("DEVICENUMBER");
                var devices = req.getSession().get("devices") || [];
                var deviceId, deviceName;
                for (var i = 0; i < devices.length; i++) {
                    if (devices[i].number == deviceNumber) {
                        deviceId = devices[i].id;
                        deviceName = devices[i].name;
                    }
                }
                request.put({
                    url: "https://api.spotify.com/v1/me/player",
                    auth: {
                        "bearer": req.getSession().get("accessToken")
                    },
                    body: {
                        "device_ids": [
                            deviceId
                        ]
                    },
                    json: true
                });
                res.say("Transferring to device " + deviceNumber + ": " + deviceName);
            }
        }
    });

//Only listen if run directly, not if required as a module
if (require.main === module) {
    var port = process.env.PORT || 8888;
    console.log("Listening on port " + port);
    express_app.listen(port);
}

module.exports = app;
<commit_msg>Fix session access for accessToken<commit_after>var alexa = require('alexa-app');
var request = require('request-promise');
var express = require('express');

var express_app = express();

var app = new alexa.app('connect');
app.express({ expressApp: express_app });

app.pre = function (request, response, type) {
    if (request.applicationId != "amzn1.ask.skill.33d79728-0f5a-44e7-ae22-ccf0b0c0e9e0") {
        throw "Invalid applicationId";
    }
};

app.intent('PlayIntent', {
    "utterances": [
        "play",
        "resume",
        "continue"
    ]
},
    function (req, res) {
        request.put("https://api.spotify.com/v1/me/player/play").auth(null, null, true, req.getSession().user.accessToken);
        res.say('Playing');
    }
);

app.intent('PauseIntent', {
    "utterances": [
        "pause"
    ]
},
    function (req, res) {
        request.put("https://api.spotify.com/v1/me/player/pause").auth(null, null, true, req.getSession().user.accessToken);
        res.say('Paused');
    }
);

app.intent('GetDevicesIntent', {
    "utterances": [
        "devices",
        "list",
        "search",
        "find"
    ]
},
    function (req, res) {
        return request.get({
            url: "https://api.spotify.com/v1/me/player/devices",
            auth: {
                "bearer": req.getSession().user.accessToken
            },
            json: true
        })
            .then(function (body) {
                var devices = body.devices || [];
                var deviceNames = [];
                res.say("I found these connect devices:");
                for (var i = 0; i < devices.length; i++) {
                    //Number each device
                    deviceNames.push((i + 1) + ". " + devices[i].name);
                    //Add the device number to JSON
                    devices[i].number = (i + 1);
                }
                //Comma separated list of device names
                res.say([deviceNames.slice(0, -1).join(', '), deviceNames.slice(-1)[0]].join(deviceNames.length < 2 ? '' : ', and '));
                req.getSession().set("devices", devices);
                res.shouldEndSession(false);
            })
            .catch(function (err) {
                console.error('error:', err.message);
            });
    }
);

app.intent('DevicePlayIntent', {
    "slots": {
        "DEVICENUMBER": "AMAZON.NUMBER"
    },
    "utterances": [
        "play on {-|DEVICENUMBER}",
        "play on number {-|DEVICENUMBER}",
        "play on device {-|DEVICENUMBER}",
        "play on device number {-|DEVICENUMBER}"
    ]
},
    function (req, res) {
        if (req.hasSession()) {
            if (req.slot("DEVICENUMBER")) {
                var deviceNumber = req.slot("DEVICENUMBER");
                var devices = req.getSession().get("devices") || [];
                var deviceId, deviceName;
                for (var i = 0; i < devices.length; i++) {
                    if (devices[i].number == deviceNumber) {
                        deviceId = devices[i].id;
                        deviceName = devices[i].name;
                    }
                }
                request.put({
                    url: "https://api.spotify.com/v1/me/player",
                    auth: {
                        "bearer": req.getSession().user.accessToken
                    },
                    body: {
                        "device_ids": [
                            deviceId
                        ],
                        "play": true
                    },
                    json: true
                });
                res.say("Playing on device " + deviceNumber + ": " + deviceName);
            }
        }
    });

express_app.use(express.static(__dirname));
express_app.get('/', function (req, res) {
    res.redirect('https://github.com/thorpelawrence/alexa-spotify-connect');
});

app.intent('DeviceTransferIntent', {
    "slots": {
        "DEVICENUMBER": "AMAZON.NUMBER"
    },
    "utterances": [
        "transfer to {-|DEVICENUMBER}",
        "transfer to number {-|DEVICENUMBER}",
        "transfer to device {-|DEVICENUMBER}",
        "transfer to device number {-|DEVICENUMBER}"
    ]
},
    function (req, res) {
        if (req.hasSession()) {
            if (req.slot("DEVICENUMBER")) {
                var deviceNumber = req.slot("DEVICENUMBER");
                var devices = req.getSession().get("devices") || [];
                var deviceId, deviceName;
                for (var i = 0; i < devices.length; i++) {
                    if (devices[i].number == deviceNumber) {
                        deviceId = devices[i].id;
                        deviceName = devices[i].name;
                    }
                }
                request.put({
                    url: "https://api.spotify.com/v1/me/player",
                    auth: {
                        "bearer": req.getSession().user.accessToken
                    },
                    body: {
                        "device_ids": [
                            deviceId
                        ]
                    },
                    json: true
                });
                res.say("Transferring to device " + deviceNumber + ": " + deviceName);
            }
        }
    });

//Only listen if run directly, not if required as a module
if (require.main === module) {
    var port = process.env.PORT || 8888;
    console.log("Listening on port " + port);
    express_app.listen(port);
}

module.exports = app;
<|endoftext|>


<commit_before>import { assert } from 'chai';

import * as RA from '../src/index';
import eq from './shared/eq';

describe('ensureArray', function() {
  context('given argument is not an array', function() {
    it('wraps value into singleton array', function() {
      const arrayPrototype = Array.prototype;

      eq(RA.ensureArray(void 0), [void 0]);
      eq(RA.ensureArray({}), [{}]);
      eq(RA.ensureArray(null), [null]);
      eq(RA.ensureArray(undefined), [undefined]);
      eq(RA.ensureArray(42), [42]);
      eq(RA.ensureArray('Array'), ['Array']);
      eq(RA.ensureArray(true), [true]);
      eq(RA.ensureArray(false), [false]);
      eq(RA.ensureArray({ __proto__: arrayPrototype }), [
        { __proto__: arrayPrototype },
      ]);
    });
  });

  context('given argument is empty array', function() {
    let emptyArray;

    beforeEach(function() {
      emptyArray = [];
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(emptyArray), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(emptyArray), emptyArray);
    });
  });

  context('given argument is filled array', function() {
    let filledArray;

    beforeEach(function() {
      filledArray = [42];
    });

    specify('should return array of length 1', function() {
      assert.lengthOf(RA.ensureArray(filledArray), 1);
    });

    specify('should be the same filled array', function() {
      assert.strictEqual(RA.ensureArray(filledArray), filledArray);
    });
  });

  context('given argument is array instance', function() {
    let arrayInstance;

    beforeEach(function() {
      arrayInstance = new Array();
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(arrayInstance), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(arrayInstance), arrayInstance);
    });
  });

  context('given argument is Array.prototype', function() {
    let arrayPrototype;

    beforeEach(function() {
      arrayPrototype = Array.prototype;
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(arrayPrototype), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(arrayPrototype), arrayPrototype);
    });
  });
});
<commit_msg>test(ensureArray): add test for placeholder support<commit_after>import { assert } from 'chai';
import * as R from 'ramda';

import * as RA from '../src/index';
import eq from './shared/eq';

describe('ensureArray', function() {
  context('given argument is not an array', function() {
    it('wraps value into singleton array', function() {
      const arrayPrototype = Array.prototype;

      eq(RA.ensureArray(void 0), [void 0]);
      eq(RA.ensureArray({}), [{}]);
      eq(RA.ensureArray(null), [null]);
      eq(RA.ensureArray(undefined), [undefined]);
      eq(RA.ensureArray(42), [42]);
      eq(RA.ensureArray('Array'), ['Array']);
      eq(RA.ensureArray(true), [true]);
      eq(RA.ensureArray(false), [false]);
      eq(RA.ensureArray({ __proto__: arrayPrototype }), [
        { __proto__: arrayPrototype },
      ]);
    });
  });

  context('given argument is empty array', function() {
    let emptyArray;

    beforeEach(function() {
      emptyArray = [];
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(emptyArray), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(emptyArray), emptyArray);
    });
  });

  context('given argument is filled array', function() {
    let filledArray;

    beforeEach(function() {
      filledArray = [42];
    });

    specify('should return array of length 1', function() {
      assert.lengthOf(RA.ensureArray(filledArray), 1);
    });

    specify('should be the same filled array', function() {
      assert.strictEqual(RA.ensureArray(filledArray), filledArray);
    });
  });

  context('given argument is array instance', function() {
    let arrayInstance;

    beforeEach(function() {
      arrayInstance = new Array();
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(arrayInstance), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(arrayInstance), arrayInstance);
    });
  });

  context('given argument is Array.prototype', function() {
    let arrayPrototype;

    beforeEach(function() {
      arrayPrototype = Array.prototype;
    });

    specify('should return empty array', function() {
      assert.lengthOf(RA.ensureArray(arrayPrototype), 0);
    });

    specify('should be the same array instance', function() {
      assert.strictEqual(RA.ensureArray(arrayPrototype), arrayPrototype);
    });
  });

  it('should support placeholder to specify "gaps"', function() {
    const ensureArray = RA.ensureArray(R.__);

    eq(ensureArray(1), [1]);
  });
});
<|endoftext|>


<commit_before>"use strict";

let errors = require("../src/errors");

describe("Test Errors", () => {

	it("test error types", () => {
		expect(errors.ServiceNotFoundError).toBeDefined();
	});

	it("test ServiceNotFoundError", () => {
		let data = {};
		let err = new errors.ServiceNotFoundError("Something went wrong!", data);
		expect(err).toBeDefined();
		expect(err).toBeInstanceOf(Error);
		expect(err.name).toBe("ServiceNotFoundError");
		expect(err.message).toBe("Something went wrong!");
		expect(err.data).toBe(data);
	});

	it("test ValidationError", () => {
		let data = {};
		let err = new errors.ValidationError("Param is not correct!", data);
		expect(err).toBeDefined();
		expect(err).toBeInstanceOf(Error);
		expect(err.name).toBe("ValidationError");
		expect(err.message).toBe("Param is not correct!");
		expect(err.data).toBe(data);
	});

});<commit_msg>increment coverage<commit_after>"use strict";

let errors = require("../src/errors");

describe("Test Errors", () => {

	it("test error types", () => {
		expect(errors.ServiceNotFoundError).toBeDefined();
	});

	it("test ServiceNotFoundError", () => {
		let data = {};
		let err = new errors.ServiceNotFoundError("Something went wrong!", data);
		expect(err).toBeDefined();
		expect(err).toBeInstanceOf(Error);
		expect(err.name).toBe("ServiceNotFoundError");
		expect(err.message).toBe("Something went wrong!");
		expect(err.data).toBe(data);
	});

	it("test RequestTimeoutError", () => {
		let data = {};
		let err = new errors.RequestTimeoutError("Something went wrong!", data);
		expect(err).toBeDefined();
		expect(err).toBeInstanceOf(Error);
		expect(err.name).toBe("RequestTimeoutError");
		expect(err.message).toBe("Something went wrong!");
		expect(err.data).toBe(data);
	});

	it("test ValidationError", () => {
		let data = {};
		let err = new errors.ValidationError("Param is not correct!", data);
		expect(err).toBeDefined();
		expect(err).toBeInstanceOf(Error);
		expect(err.name).toBe("ValidationError");
		expect(err.message).toBe("Param is not correct!");
		expect(err.data).toBe(data);
	});

});<|endoftext|>


<commit_before>import test from 'ava';
import sinon from 'sinon';

import JSONLoader from '../src/JSONLoader';
import * as Request from '../src/request';

const fakeRequest = (fn) => {
  if (Request.getResource.restore) {
    Request.getResource.restore();
  }
  sinon.stub(Request, 'getResource').callsFake(fn);
}

test.serial('#load works for simple JSON files', async t => {
  const OBJECT = {foo: 'bar'};
  fakeRequest((path) => Promise.resolve(OBJECT));
  const result = await JSONLoader.load('some.json');
  t.deepEqual(result[0], OBJECT);
});

test.serial('#load merges JSON files based on simple spec', async t => {
  const FILE1 = {
    foo: 'bar',
    baz: {
      _load: 'file2.json'
    }
  };
  const FILE2 = 42;
  const EXPECTED = {
    foo: 'bar',
    baz: FILE2
  }
  fakeRequest((file) => {
    const resource = file === 'file1.json' ? FILE1 : FILE2;
    return Promise.resolve(resource);
  });
  const result = await JSONLoader.load('file1.json');
  t.deepEqual(result[0], EXPECTED);
});

test.serial('#load overrides specified attributes in merged json', async t => {
  const FILE1 = {
    foo: 'bar',
    baz: {
      _load: 'file2.json',
      _override: {
        test: 42
      }
    }
  };
  const FILE2 = {
    spam: 'eggs',
    test: 'hello world'
  };
  const EXPECTED = {
    foo: 'bar',
    baz: {
      spam: 'eggs',
      test: 42
    }
  }
  fakeRequest((file) => {
    const resource = file === 'file1.json' ? FILE1 : FILE2;
    return Promise.resolve(resource);
  });
  const result = await JSONLoader.load('file1.json');
  t.deepEqual(result[0], EXPECTED);
});

test.serial('#load only merges 10 levels deep', async t => {
  const FILES = {
    'file1.json': {foo: {_load: 'file2.json'}},
    'file2.json': {foo: {_load: 'file3.json'}},
    'file3.json': {foo: {_load: 'file4.json'}},
    'file4.json': {foo: {_load: 'file5.json'}},
    'file5.json': {foo: {_load: 'file6.json'}},
    'file6.json': {foo: {_load: 'file7.json'}},
    'file7.json': {foo: {_load: 'file8.json'}},
    'file8.json': {foo: {_load: 'file9.json'}},
    'file9.json': {foo: {_load: 'file10.json'}},
    'file10.json': {foo: {_load: 'file11.json'}},
    'file11.json': {foo: 'bar'}
  }

  const EXPECTED = {
    foo: 'bar',
    baz: {
      spam: 'eggs',
      test: 42
    }
  }
  fakeRequest((file) => {
    return Promise.resolve(FILES[file]);
  });

  await t.throws(JSONLoader.load('file1.json'));
});
<commit_msg>Add test for multi attribute calls<commit_after>import test from 'ava';
import sinon from 'sinon';

import JSONLoader from '../src/JSONLoader';
import * as Request from '../src/request';

const fakeRequest = (fn) => {
  if (Request.getResource.restore) {
    Request.getResource.restore();
  }
  sinon.stub(Request, 'getResource').callsFake(fn);
}

test.serial('#load works for simple JSON files', async t => {
  const OBJECT = {foo: 'bar'};
  fakeRequest((path) => Promise.resolve(OBJECT));
  const result = await JSONLoader.load('some.json');
  t.deepEqual(result[0], OBJECT);
});

test.serial('#load merges JSON files based on simple spec', async t => {
  const FILE1 = {
    foo: 'bar',
    baz: {
      _load: 'file2.json'
    }
  };
  const FILE2 = 42;
  const EXPECTED = {
    foo: 'bar',
    baz: FILE2
  }
  fakeRequest((file) => {
    const resource = file === 'file1.json' ? FILE1 : FILE2;
    return Promise.resolve(resource);
  });
  const result = await JSONLoader.load('file1.json');
  t.deepEqual(result[0], EXPECTED);
});

test.serial('#load overrides specified attributes in merged json', async t => {
  const FILE1 = {
    foo: 'bar',
    baz: {
      _load: 'file2.json',
      _override: {
        test: 42
      }
    }
  };
  const FILE2 = {
    spam: 'eggs',
    test: 'hello world'
  };
  const EXPECTED = {
    foo: 'bar',
    baz: {
      spam: 'eggs',
      test: 42
    }
  }
  fakeRequest((file) => {
    const resource = file === 'file1.json' ? FILE1 : FILE2;
    return Promise.resolve(resource);
  });
  const result = await JSONLoader.load('file1.json');
  t.deepEqual(result[0], EXPECTED);
});

test.serial('#load only merges 10 levels deep', async t => {
  const FILES = {
    'file1.json': {foo: {_load: 'file2.json'}},
    'file2.json': {foo: {_load: 'file3.json'}},
    'file3.json': {foo: {_load: 'file4.json'}},
    'file4.json': {foo: {_load: 'file5.json'}},
    'file5.json': {foo: {_load: 'file6.json'}},
    'file6.json': {foo: {_load: 'file7.json'}},
    'file7.json': {foo: {_load: 'file8.json'}},
    'file8.json': {foo: {_load: 'file9.json'}},
    'file9.json': {foo: {_load: 'file10.json'}},
    'file10.json': {foo: {_load: 'file11.json'}},
    'file11.json': {foo: 'bar'}
  }

  const EXPECTED = {
    foo: 'bar',
    baz: {
      spam: 'eggs',
      test: 42
    }
  }
  fakeRequest((file) => {
    return Promise.resolve(FILES[file]);
  });

  await t.throws(JSONLoader.load('file1.json'));
});

test.serial('#load works for multiple files', async t => {
  const FILE1 = {
    foo: 'bar',
    baz: 42
  };
  const FILE2 = {
    'hello': 'world'
  };
  fakeRequest((file) => {
    const resource = file === 'file1.json' ? FILE1 : FILE2;
    return Promise.resolve(resource);
  });

  const result = await JSONLoader.load('file1.json', 'file2.json');
  t.deepEqual(result, [FILE1, FILE2]);
});
<|endoftext|>


<commit_before>const sinon = require('sinon');
const expect = require('unexpected')
  .clone()
  .use(require('unexpected-sinon'));
const Knorm = require('../lib/Knorm');
const KnormError = require('../lib/KnormError');
const Field = require('../lib/Field');
const Model = require('../lib/Model');
const Query = require('../lib/Query');
const Connection = require('../lib/Connection');
const Transaction = require('../lib/Transaction');

describe('Knorm', () => {
  it('exposes Field, Model, Query, Transaction as statics', () => {
    expect(Knorm.Field, 'to be', Field);
    expect(Knorm.Model, 'to be', Model);
    expect(Knorm.Query, 'to be', Query);
    expect(Knorm.Connection, 'to be', Connection);
    expect(Knorm.Transaction, 'to be', Transaction);
  });

  describe('constructor', () => {
    it('creates scoped Field, Model, Query, Connection, Transaction', () => {
      const knorm = new Knorm();

      expect(knorm.Field.prototype, 'to be a', Field);
      expect(knorm.Model.prototype, 'to be a', Model);
      expect(knorm.Query.prototype, 'to be a', Query);
      expect(knorm.Connection.prototype, 'to be a', Connection);
      expect(knorm.Transaction.prototype, 'to be a', Transaction);

      expect(knorm.Model.Field, 'to be', knorm.Field);
      expect(knorm.Model.Query, 'to be', knorm.Query);

      expect(knorm.Query.Connection, 'to be', knorm.Connection);
      expect(knorm.Model.Query.Connection, 'to be', knorm.Connection);
      expect(knorm.Transaction.Connection, 'to be', knorm.Connection);
    });

    it('adds an accessor to the knorm instance', function() {
      const knorm = new Knorm();

      class User extends knorm.Model {}
      User.table = 'user';

      expect(knorm.Field.knorm, 'to be', knorm);
      expect(knorm.Model.knorm, 'to be', knorm);
      expect(knorm.Query.knorm, 'to be', knorm);
      expect(knorm.Connection.knorm, 'to be', knorm);
      expect(knorm.Transaction.knorm, 'to be', knorm);

      expect(knorm.Field.prototype.knorm, 'to be', knorm);
      expect(knorm.Model.prototype.knorm, 'to be', knorm);
      expect(knorm.Query.prototype.knorm, 'to be', knorm);
      expect(knorm.Connection.prototype.knorm, 'to be', knorm);
      expect(knorm.Transaction.prototype.knorm, 'to be', knorm);

      const KnormUser = knorm.models.User;

      expect(KnormUser.knorm, 'to be', knorm);
      expect(KnormUser.Field.knorm, 'to be', knorm);
      expect(KnormUser.Query.knorm, 'to be', knorm);
      expect(KnormUser.Query.Connection.knorm, 'to be', knorm);

      expect(KnormUser.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Field.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Query.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Query.Connection.prototype.knorm, 'to be', knorm);
    });

    it('creates new classes per instance', () => {
      const firstOrm = new Knorm();
      const secondOrm = new Knorm();
      expect(firstOrm.Query, 'not to be', secondOrm.Query);
    });

    describe('with the `fieldToColumn` option provided', () => {
      it('configures it as the field-to-column-name mapping function', () => {
        const { Model } = new Knorm({
          fieldToColumn(field) {
            return field.toLowerCase();
          }
        });
        Model.fields = { firstName: { type: 'string' } };
        expect(Model.fields.firstName.column, 'to be', 'firstname');
      });

      it('calls it with `this` set to the field instance', () => {
        let wasCalled;
        const { Model } = new Knorm({
          fieldToColumn() {
            wasCalled = true;
            expect(this.constructor.name, 'to be', 'Field');
          }
        });
        Model.fields = { firstName: { type: 'string' } };
        expect(wasCalled, 'to be true');
      });
    });

    describe('with no `fieldToColumn` option provided', () => {
      it('does not configure a field-to-column-name mapping function', () => {
        const { Model } = new Knorm();
        Model.fields = { firstName: { type: 'string' } };
        expect(Model.fields.firstName.column, 'to be', 'firstName');
      });
    });
  });

  describe('use', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('throws if not provided a plugin', () => {
      expect(
        () => knorm.use(),
        'to throw',
        new KnormError('no plugin provided')
      );
    });

    it('throws an error if provided an invalid plugin', () => {
      expect(
        () => knorm.use('foo'),
        'to throw',
        new KnormError('invalid plugin provided')
      );
    });

    it('throws an error if the plugin has no name', () => {
      expect(
        () => knorm.use({ init() {} }),
        'to throw',
        new KnormError('plugins should have a `name`')
      );
    });

    it('throws an error if a plugin by the same name is already added', () => {
      expect(
        () =>
          knorm.use({ name: 'foo', init() {} }).use({ name: 'foo', init() {} }),
        'to throw',
        new KnormError('plugin `foo` has already been added')
      );
    });

    it('allows plugins to access themselves by name', function() {
      let ran = false;
      const plugin = {
        name: 'foo',
        init(knorm) {
          expect(knorm.plugins.foo, 'to be', plugin);
          ran = true;
        }
      };
      expect(ran, 'to be false');
      knorm.use(plugin);
      expect(ran, 'to be true');
    });

    describe('when called with a function', function() {
      it('passes itself to the function', () => {
        const plugin = sinon.spy().named('plugin');
        knorm.use(plugin);
        expect(plugin, 'to have calls satisfying', () => plugin(knorm));
      });

      it("registers the plugin by the function's name", () => {
        const foo = () => {};
        knorm.use(foo);
        expect(knorm.plugins.foo, 'to be', foo);
      });

      it('allows chaining', () => {
        const foo = () => {};
        expect(knorm.use(foo), 'to equal', knorm);
      });
    });

    describe('when called with an object with an `init` function', function() {
      it('passes itself to the `init` function', () => {
        const init = sinon.spy().named('init');
        knorm.use({ name: 'foo', init });
        expect(init, 'to have calls satisfying', () => init(knorm));
      });

      it('allows chaining', () => {
        expect(knorm.use({ name: 'foo', init() {} }), 'to equal', knorm);
      });
    });
  });

  describe('addModel', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('throws if not provided a model', () => {
      expect(
        () => knorm.addModel(),
        'to throw',
        new KnormError('no model provided')
      );
    });

    it('throws if the model is not a subclass of Model', () => {
      expect(
        () => knorm.addModel(class Foo {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if the model extends a model from a different Knorm instance', () => {
      const knorm1 = new Knorm();
      const knorm2 = new Knorm();
      expect(
        () => knorm1.addModel(class Foo extends knorm2.Model {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if the model extends `Model` directly', () => {
      expect(
        () => knorm.addModel(class Foo extends Model {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if a model by the same name is already added', () => {
      knorm.addModel(class Foo extends knorm.Model {});
      expect(
        () => knorm.addModel(class Foo extends knorm.Model {}),
        'to throw',
        new KnormError('model `Foo` has already been added')
      );
    });

    it('adds the model to the Knorm instance', () => {
      class Foo extends knorm.Model {}

      knorm.addModel(Foo);

      expect(knorm.models.Foo, 'to be', Foo);
    });

    it('adds a model that extends another model', () => {
      class Foo extends knorm.Model {}
      class Bar extends Foo {}

      knorm.addModel(Bar);

      expect(knorm.models.Bar, 'to be', Bar);
    });

    it('allows plugins to update knorm.Model', () => {
      knorm.Model = class Foo extends knorm.Model {};
      knorm.addModel(knorm.Model);
    });

    it('allows chaining', () => {
      class Foo extends knorm.Model {}
      expect(knorm.addModel(Foo), 'to be', knorm);
    });
  });

  describe('clone', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('returns a Knorm instance', () => {
      expect(knorm.clone(), 'to be a', Knorm);
    });

    it('returns a different instance', () => {
      expect(knorm.clone(), 'not to be', knorm);
    });

    it('adds models on the original instance to the clone', () => {
      class Foo extends knorm.Model {}
      knorm.addModel(Foo);
      const clone = knorm.clone();
      expect(clone.models.Foo, 'to be', Foo);
    });

    it('adds plugins on the original instance to the clone', () => {
      function foo(knorm) {
        knorm.Model = class Foo extends knorm.Model {};
      }

      knorm.use(foo);
      const clone = knorm.clone();

      expect(clone.plugins.foo, 'to be', foo);
      expect(clone.Model.name, 'to be', 'Foo');
    });

    it('allows adding new models to the clone only', () => {
      const clone = knorm.clone();

      class Bar extends clone.Model {}
      clone.addModel(Bar);

      expect(clone.models.Bar, 'to be', Bar);
      expect(knorm.models.Bar, 'to be undefined');
    });

    it('allows adding new plugins to the clone only', () => {
      const clone = knorm.clone();

      function foo(knorm) {
        knorm.Model = class Foo extends knorm.Model {};
      }

      clone.use(foo);

      expect(clone.plugins.foo, 'to be', foo);
      expect(clone.Model.name, 'to be', 'Foo');

      expect(knorm.plugins, 'to be empty');
      expect(knorm.Model.name, 'to be', 'Model');
    });
  });

  describe('updateTransaction', () => {
    it('updates Knorm.prototype.Transaction', () => {
      class Foo {}
      const knorm = new Knorm().updateTransaction(Foo);
      expect(knorm.Transaction, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateTransaction(Foo), 'to be', knorm);
    });
  });

  describe('updateModel', () => {
    it('updates Knorm.prototype.Model', () => {
      class Foo {}
      const knorm = new Knorm().updateModel(Foo);
      expect(knorm.Model, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateModel(Foo), 'to be', knorm);
    });
  });

  describe('updateQuery', () => {
    it('updates Knorm.prototype.Query', () => {
      class Foo {}
      const knorm = new Knorm().updateQuery(Foo);
      expect(knorm.Query, 'to be', Foo);
    });

    it('updates Knorm.Model.Query', () => {
      class Foo {}
      const knorm = new Knorm().updateQuery(Foo);
      expect(knorm.Model.Query, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateQuery(Foo), 'to be', knorm);
    });
  });

  describe('updateField', () => {
    it('updates Knorm.prototype.Field', () => {
      class Foo {}
      const knorm = new Knorm().updateField(Foo);
      expect(knorm.Field, 'to be', Foo);
    });

    it('updates Knorm.Model.Field', () => {
      class Foo {}
      const knorm = new Knorm().updateField(Foo);
      expect(knorm.Model.Field, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateField(Foo), 'to be', knorm);
    });
  });

  describe('updateConnection', () => {
    it('updates Knorm.prototype.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Connection, 'to be', Foo);
    });

    it('updates Knorm.Query.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Query.Connection, 'to be', Foo);
    });

    it('updates Knorm.Transaction.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Transaction.Connection, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateConnection(Foo), 'to be', knorm);
    });
  });
});
<commit_msg>test(Knorm): fix incomplete test<commit_after>const sinon = require('sinon');
const expect = require('unexpected')
  .clone()
  .use(require('unexpected-sinon'));
const Knorm = require('../lib/Knorm');
const KnormError = require('../lib/KnormError');
const Field = require('../lib/Field');
const Model = require('../lib/Model');
const Query = require('../lib/Query');
const Connection = require('../lib/Connection');
const Transaction = require('../lib/Transaction');

describe('Knorm', () => {
  it('exposes Field, Model, Query, Transaction as statics', () => {
    expect(Knorm.Field, 'to be', Field);
    expect(Knorm.Model, 'to be', Model);
    expect(Knorm.Query, 'to be', Query);
    expect(Knorm.Connection, 'to be', Connection);
    expect(Knorm.Transaction, 'to be', Transaction);
  });

  describe('constructor', () => {
    it('creates scoped Field, Model, Query, Connection, Transaction', () => {
      const knorm = new Knorm();

      expect(knorm.Field.prototype, 'to be a', Field);
      expect(knorm.Model.prototype, 'to be a', Model);
      expect(knorm.Query.prototype, 'to be a', Query);
      expect(knorm.Connection.prototype, 'to be a', Connection);
      expect(knorm.Transaction.prototype, 'to be a', Transaction);

      expect(knorm.Model.Field, 'to be', knorm.Field);
      expect(knorm.Model.Query, 'to be', knorm.Query);

      expect(knorm.Query.Connection, 'to be', knorm.Connection);
      expect(knorm.Model.Query.Connection, 'to be', knorm.Connection);
      expect(knorm.Transaction.Connection, 'to be', knorm.Connection);
    });

    it('adds an accessor to the knorm instance', function() {
      const knorm = new Knorm();

      class User extends knorm.Model {}
      User.table = 'user';

      expect(knorm.Field.knorm, 'to be', knorm);
      expect(knorm.Model.knorm, 'to be', knorm);
      expect(knorm.Query.knorm, 'to be', knorm);
      expect(knorm.Connection.knorm, 'to be', knorm);
      expect(knorm.Transaction.knorm, 'to be', knorm);

      expect(knorm.Field.prototype.knorm, 'to be', knorm);
      expect(knorm.Model.prototype.knorm, 'to be', knorm);
      expect(knorm.Query.prototype.knorm, 'to be', knorm);
      expect(knorm.Connection.prototype.knorm, 'to be', knorm);
      expect(knorm.Transaction.prototype.knorm, 'to be', knorm);

      const KnormUser = knorm.models.User;

      expect(KnormUser.knorm, 'to be', knorm);
      expect(KnormUser.Field.knorm, 'to be', knorm);
      expect(KnormUser.Query.knorm, 'to be', knorm);
      expect(KnormUser.Query.Connection.knorm, 'to be', knorm);

      expect(KnormUser.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Field.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Query.prototype.knorm, 'to be', knorm);
      expect(KnormUser.Query.Connection.prototype.knorm, 'to be', knorm);
    });

    it('creates new classes per instance', () => {
      const firstOrm = new Knorm();
      const secondOrm = new Knorm();
      expect(firstOrm.Query, 'not to be', secondOrm.Query);
    });

    describe('with the `fieldToColumn` option provided', () => {
      it('configures it as the field-to-column-name mapping function', () => {
        const { Model } = new Knorm({
          fieldToColumn(field) {
            return field.toLowerCase();
          }
        });
        Model.fields = { firstName: { type: 'string' } };
        expect(Model.fields.firstName.column, 'to be', 'firstname');
      });

      it('calls it with `this` set to the field instance', () => {
        let wasCalled;
        const { Model } = new Knorm({
          fieldToColumn() {
            wasCalled = true;
            expect(this.constructor.name, 'to be', 'Field');
          }
        });
        Model.fields = { firstName: { type: 'string' } };
        expect(wasCalled, 'to be true');
      });
    });

    describe('with no `fieldToColumn` option provided', () => {
      it('does not configure a field-to-column-name mapping function', () => {
        const { Model } = new Knorm();
        Model.fields = { firstName: { type: 'string' } };
        expect(Model.fields.firstName.column, 'to be', 'firstName');
      });
    });
  });

  describe('use', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('throws if not provided a plugin', () => {
      expect(
        () => knorm.use(),
        'to throw',
        new KnormError('no plugin provided')
      );
    });

    it('throws an error if provided an invalid plugin', () => {
      expect(
        () => knorm.use('foo'),
        'to throw',
        new KnormError('invalid plugin provided')
      );
    });

    it('throws an error if the plugin has no name', () => {
      expect(
        () => knorm.use({ init() {} }),
        'to throw',
        new KnormError('plugins should have a `name`')
      );
    });

    it('throws an error if a plugin by the same name is already added', () => {
      expect(
        () =>
          knorm.use({ name: 'foo', init() {} }).use({ name: 'foo', init() {} }),
        'to throw',
        new KnormError('plugin `foo` has already been added')
      );
    });

    it('allows plugins to access themselves by name', function() {
      let ran = false;
      const plugin = {
        name: 'foo',
        init(knorm) {
          expect(knorm.plugins.foo, 'to be', plugin);
          ran = true;
        }
      };
      expect(ran, 'to be false');
      knorm.use(plugin);
      expect(ran, 'to be true');
    });

    describe('when called with a function', function() {
      it('passes itself to the function', () => {
        const plugin = sinon.spy().named('plugin');
        knorm.use(plugin);
        expect(plugin, 'to have calls satisfying', () => plugin(knorm));
      });

      it("registers the plugin by the function's name", () => {
        const foo = () => {};
        knorm.use(foo);
        expect(knorm.plugins.foo, 'to be', foo);
      });

      it('allows chaining', () => {
        const foo = () => {};
        expect(knorm.use(foo), 'to equal', knorm);
      });
    });

    describe('when called with an object with an `init` function', function() {
      it('passes itself to the `init` function', () => {
        const init = sinon.spy().named('init');
        knorm.use({ name: 'foo', init });
        expect(init, 'to have calls satisfying', () => init(knorm));
      });

      it('allows chaining', () => {
        expect(knorm.use({ name: 'foo', init() {} }), 'to equal', knorm);
      });
    });
  });

  describe('addModel', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('throws if not provided a model', () => {
      expect(
        () => knorm.addModel(),
        'to throw',
        new KnormError('no model provided')
      );
    });

    it('throws if the model is not a subclass of Model', () => {
      expect(
        () => knorm.addModel(class Foo {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if the model extends a model from a different Knorm instance', () => {
      const knorm1 = new Knorm();
      const knorm2 = new Knorm();
      expect(
        () => knorm1.addModel(class Foo extends knorm2.Model {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if the model extends `Model` directly', () => {
      expect(
        () => knorm.addModel(class Foo extends Model {}),
        'to throw',
        new KnormError('model should be a subclass of `knorm.Model`')
      );
    });

    it('throws if a model by the same name is already added', () => {
      knorm.addModel(class Foo extends knorm.Model {});
      expect(
        () => knorm.addModel(class Foo extends knorm.Model {}),
        'to throw',
        new KnormError('model `Foo` has already been added')
      );
    });

    it('adds the model to the Knorm instance', () => {
      class Foo extends knorm.Model {}

      knorm.addModel(Foo);

      expect(knorm.models.Foo, 'to be', Foo);
    });

    it('adds a model that extends another model', () => {
      class Foo extends knorm.Model {}
      class Bar extends Foo {}

      knorm.addModel(Bar);

      expect(knorm.models.Bar, 'to be', Bar);
    });

    it('allows plugins to update knorm.Model', () => {
      knorm.Model = class Foo extends knorm.Model {};
      knorm.addModel(knorm.Model);
      expect(knorm.Model, 'to be', knorm.Model);
    });

    it('allows chaining', () => {
      class Foo extends knorm.Model {}
      expect(knorm.addModel(Foo), 'to be', knorm);
    });
  });

  describe('clone', () => {
    let knorm;

    beforeEach(() => {
      knorm = new Knorm();
    });

    it('returns a Knorm instance', () => {
      expect(knorm.clone(), 'to be a', Knorm);
    });

    it('returns a different instance', () => {
      expect(knorm.clone(), 'not to be', knorm);
    });

    it('adds models on the original instance to the clone', () => {
      class Foo extends knorm.Model {}
      knorm.addModel(Foo);
      const clone = knorm.clone();
      expect(clone.models.Foo, 'to be', Foo);
    });

    it('adds plugins on the original instance to the clone', () => {
      function foo(knorm) {
        knorm.Model = class Foo extends knorm.Model {};
      }

      knorm.use(foo);
      const clone = knorm.clone();

      expect(clone.plugins.foo, 'to be', foo);
      expect(clone.Model.name, 'to be', 'Foo');
    });

    it('allows adding new models to the clone only', () => {
      const clone = knorm.clone();

      class Bar extends clone.Model {}
      clone.addModel(Bar);

      expect(clone.models.Bar, 'to be', Bar);
      expect(knorm.models.Bar, 'to be undefined');
    });

    it('allows adding new plugins to the clone only', () => {
      const clone = knorm.clone();

      function foo(knorm) {
        knorm.Model = class Foo extends knorm.Model {};
      }

      clone.use(foo);

      expect(clone.plugins.foo, 'to be', foo);
      expect(clone.Model.name, 'to be', 'Foo');

      expect(knorm.plugins, 'to be empty');
      expect(knorm.Model.name, 'to be', 'Model');
    });
  });

  describe('updateTransaction', () => {
    it('updates Knorm.prototype.Transaction', () => {
      class Foo {}
      const knorm = new Knorm().updateTransaction(Foo);
      expect(knorm.Transaction, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateTransaction(Foo), 'to be', knorm);
    });
  });

  describe('updateModel', () => {
    it('updates Knorm.prototype.Model', () => {
      class Foo {}
      const knorm = new Knorm().updateModel(Foo);
      expect(knorm.Model, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateModel(Foo), 'to be', knorm);
    });
  });

  describe('updateQuery', () => {
    it('updates Knorm.prototype.Query', () => {
      class Foo {}
      const knorm = new Knorm().updateQuery(Foo);
      expect(knorm.Query, 'to be', Foo);
    });

    it('updates Knorm.Model.Query', () => {
      class Foo {}
      const knorm = new Knorm().updateQuery(Foo);
      expect(knorm.Model.Query, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateQuery(Foo), 'to be', knorm);
    });
  });

  describe('updateField', () => {
    it('updates Knorm.prototype.Field', () => {
      class Foo {}
      const knorm = new Knorm().updateField(Foo);
      expect(knorm.Field, 'to be', Foo);
    });

    it('updates Knorm.Model.Field', () => {
      class Foo {}
      const knorm = new Knorm().updateField(Foo);
      expect(knorm.Model.Field, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateField(Foo), 'to be', knorm);
    });
  });

  describe('updateConnection', () => {
    it('updates Knorm.prototype.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Connection, 'to be', Foo);
    });

    it('updates Knorm.Query.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Query.Connection, 'to be', Foo);
    });

    it('updates Knorm.Transaction.Connection', () => {
      class Foo {}
      const knorm = new Knorm().updateConnection(Foo);
      expect(knorm.Transaction.Connection, 'to be', Foo);
    });

    it('allows chaining', () => {
      class Foo {}
      const knorm = new Knorm();
      expect(knorm.updateConnection(Foo), 'to be', knorm);
    });
  });
});
<|endoftext|>