<commit_before>var ZOOM_FACTOR = 0.05,
    MAX_FOV = 100, //zoom out
    MIN_FOV = 20, //zoom in
    KEY_A = 97,
    KEY_D = 100,
    KEY_W = 119,
    KEY_S = 115,
    KEY_R = 114,
    KEY_F = 102,
    KEY_X = 120,
    KEY_Y = 121,
    KEY_C = 99,
    KEY_SX = 88,
    KEY_SY = 89,
    KEY_SC = 67,
    WIDTH = 1500,
    HEIGHT = 900,
    mouse = [0.5, 0.5];

window.axis_x = new THREE.Vector3( 1, 0, 0 );
window.axis_y = new THREE.Vector3( 0, 1, 0 );
window.axis_z = new THREE.Vector3( 0, 0, 1 );
var deltaDistance = 10; //distance to move
var deltaRotation = 0.05; //rotation step

renderButton.onclick = function() {
  initGraph();
  window.$GV.renderGraph();
}

function renderGraph() {
  var MIN_X = MAX_X = nodes_obj[0].getFeature('coords').x,
      MIN_Y = MAX_Y = nodes_obj[0].getFeature('coords').y,
      MIN_Z = MAX_Z = nodes_obj[0].getFeature('coords').z,
      AVG_X = AVG_Y = AVG_Z = 0;

  for(node in nodes_obj) {
    var x = nodes_obj[node].getFeature('coords').x;
    var y = nodes_obj[node].getFeature('coords').y;
    var z = nodes_obj[node].getFeature('coords').z;

    MIN_X = Math.min(MIN_X, x);
    MIN_Y = Math.min(MIN_Y, y);
    MIN_Z = Math.min(MIN_Z, z);

    MAX_X = Math.max(MAX_X, x);
    MAX_Y = Math.max(MAX_Y, y);
    MAX_Z = Math.max(MAX_Z, z);
  }
  AVG_X = (MAX_X - MIN_X) / 2;
  AVG_Y = (MAX_Y - MIN_Y) / 2;
  AVG_Z = (MAX_Z - MIN_Z) / 2;

  var scene = new THREE.Scene(); // Create a Three.js scene object.
  var camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 0.1, 1000); //TODO change to 0.1// Define the perspective camera's attributes.
  var renderer = new THREE.WebGLRenderer({ antialias: false }); //window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer(); // Fallback to canvas renderer, if necessary.
  renderer.setSize(WIDTH, HEIGHT); // Set the size of the WebGL viewport.
  renderer.setClearColor( 0x000000, 1 );
  //renderer.setPixelRatio( window.devicePixelRatio );
  //renderer.gammaInput = true;
	//renderer.gammaOutput = true;
  var element = document.getElementById("containerGraph");
  element.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM.

  var i = 0;
  var vertices = new Float32Array( graph.nrNodes() * 3 );
  for(node in nodes_obj) {
    var x = nodes_obj[node].getFeature('coords').x;
    var y = nodes_obj[node].getFeature('coords').y;
    var z = nodes_obj[node].getFeature('coords').z;

    vertices[ i*3 ] = x - AVG_X;
    vertices[ i*3 + 1 ] = y - AVG_Y;
    vertices[ i*3 + 2 ] = z - AVG_Z;
    i++;
  }

  var geometry = new THREE.BufferGeometry();
  geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
  geometry.addAttribute('color', new THREE.BufferAttribute( 0x8aa7ff, 3));

  var material = new THREE.PointsMaterial({ // MeshBasicMaterial
    color: 0x8aa7ff,
    size: 10
    //map: texture
  });

  particles = new THREE.Points( geometry, material );
	//scene.add( particles );

  //EDGE
  var materialLine = new THREE.LineBasicMaterial({
    color: 0x81cf28,
    transparent : true,
    opacity: 0.5//default is 1; range: 0.0 - 1.0
   //vertexColors: THREE.VertexColors  //,
    //linewidth: 1
  });

  window.network = new THREE.Group();
  console.log(network);
  network.add(particles);

  [und_edges, dir_edges].forEach(function(edges) {
    var i = 0;
    var positionLine = new Float32Array(Object.keys(edges).length * 6); //2 vertices * 3 xyz
    for (var edge_index in edges) {
      var edge = edges[edge_index];
      var node_a_id = edge._node_a.getID();
      var node_b_id = edge._node_b.getID();

      positionLine[ i * 6 ] = nodes_obj[node_a_id].getFeature('coords').x - AVG_X;
      positionLine[ i * 6 + 1 ] = nodes_obj[node_a_id].getFeature('coords').y - AVG_Y;
      positionLine[ i * 6 + 2 ] = nodes_obj[node_a_id].getFeature('coords').z - AVG_Z;
      positionLine[ i * 6 + 3 ] = nodes_obj[node_b_id].getFeature('coords').x - AVG_X;
      positionLine[ i * 6 + 4 ] = nodes_obj[node_b_id].getFeature('coords').y - AVG_Y;
      positionLine[ i * 6 + 5 ] = nodes_obj[node_b_id].getFeature('coords').z - AVG_Z;
      i++;
    }
    var geometryLine = new THREE.BufferGeometry();
    geometryLine.addAttribute('position', new THREE.BufferAttribute(positionLine, 3));
    //geometryLine.addAttribute('color', new THREE.BufferAttribute( 0xff700e, 3));
    //geometry.computeBoundingSphere();
    var line = new THREE.Line( geometryLine, materialLine );
    //scene.add( line );
    network.add(line);
  });

  network.translateX(-MAX_X/2);
  network.translateY(-MAX_Y/2);
  network.translateZ(-MAX_Z/2);
  scene.add(network);
  camera.position.z = Math.max(MAX_X, MAX_Y);
  //camera.position.z = 500; // Move the camera away from the origin, down the positive z-axis.
  //camera.lookat(new THREE.Vector3(0,0,0));

  //The X axis is red. The Y axis is green. The Z axis is blue.
  //var axisHelper = new THREE.AxisHelper( Math.max(MAX_X, Math.max(MAX_Y, MAX_Z)) );
  //scene.add( axisHelper );
  //network.applyMatrix(axisHelper.matrixWorld);

  var updateGraph = function () {
    renderer.render(scene, camera); // Each time we change the position of the cube object, we must re-render it.
    //requestAnimationFrame(render); // Call the render() function up to 60 times per second (i.e., up to 60 animation frames per second).
  };
  window.requestAnimationFrame(updateGraph);

  window.addEventListener('keypress', key, false);
  function key(event) {
    switch (event.charCode) {
      case KEY_W: //zoom in
        camera.position.y = camera.position.y - deltaDistance; break;
        //network.translateY(deltaDistance); break;
      case KEY_S: //zoom out
        camera.position.y = camera.position.y + deltaDistance; break;
        //network.translateY(-deltaDistance); break;
      case KEY_A: //move left
        camera.position.x = camera.position.x + deltaDistance; break;
        //network.translateX(-deltaDistance); break;
      case KEY_D: //move right
        camera.position.x = camera.position.x - deltaDistance; break;
        //network.translateX(deltaDistance); break;
      case KEY_R:
        network.translateZ(deltaDistance); break;
      case KEY_F:
        network.translateZ(-deltaDistance); break;

      case KEY_X:
        //network.rotation.x += deltaRotation; break;
        network.rotateOnAxis(axis_x, deltaRotation);
        axis_y.applyAxisAngle(axis_x, -deltaRotation);
        axis_z.applyAxisAngle(axis_x, -deltaRotation);
        break;
      case KEY_SX:
        //network.rotation.x -= deltaRotation; break;
        network.rotateOnAxis(axis_x, -deltaRotation);
        axis_y.applyAxisAngle(axis_x, deltaRotation);
        axis_z.applyAxisAngle(axis_x, deltaRotation);
        break;
      case KEY_Y:
        //network.rotation.y += deltaRotation; break;
        network.rotateOnAxis(axis_y, deltaRotation);
        axis_x.applyAxisAngle(axis_y, -deltaRotation);
        axis_z.applyAxisAngle(axis_y, -deltaRotation);
        break;
      case KEY_SY:
        //network.rotation.y -= deltaRotation; break;
        network.rotateOnAxis(axis_y, -deltaRotation);
        axis_x.applyAxisAngle(axis_y, deltaRotation);
        axis_z.applyAxisAngle(axis_y, deltaRotation);
        break;
      case KEY_C:
        //network.rotation.z += deltaRotation; break;
        network.rotateOnAxis(axis_z, deltaRotation);
        axis_x.applyAxisAngle(axis_z, -deltaRotation);
        axis_y.applyAxisAngle(axis_z, -deltaRotation);
        break;
      case KEY_SC:
        //network.rotation.z -= deltaRotation; break;
        network.rotateOnAxis(axis_z, -deltaRotation);
        axis_x.applyAxisAngle(axis_z, deltaRotation);
        axis_y.applyAxisAngle(axis_z, deltaRotation);
        break;
      default:
        break;
    }
    //camera.updateProjectionMatrix();
    window.requestAnimationFrame(updateGraph);
  }

  //zoom in and out
  window.addEventListener('mousewheel', mousewheel, false);
  function mousewheel(event) {
    //wheel down: negative value
    //wheel up: positive value
    if(event.shiftKey) {
      var delta = deltaRotation;
      if(event.wheelDelta < 0) {
        network.rotateOnAxis(axis_z, -deltaRotation);
        delta *= -1;
        axis_x.applyAxisAngle(axis_z, deltaRotation);
        axis_y.applyAxisAngle(axis_z, deltaRotation);
      }
      else {
        network.rotateOnAxis(axis_z, deltaRotation);
        delta *= -1;
        axis_x.applyAxisAngle(axis_z, -deltaRotation);
        axis_y.applyAxisAngle(axis_z, -deltaRotation);
      }
    }
    else {
      camera.fov -= ZOOM_FACTOR * event.wheelDeltaY;
      camera.fov = Math.max( Math.min( camera.fov, MAX_FOV ), MIN_FOV );
      camera.projectionMatrix = new THREE.Matrix4().makePerspective(camera.fov, WIDTH / HEIGHT, camera.near, camera.far);
    }
    window.requestAnimationFrame(updateGraph);
  }

  document.addEventListener( 'mousemove', mouseMove, false );
  function mouseMove(event) {

    if(event.shiftKey && event.which == 1) {
      if(event.movementX > 0) {
        network.rotateOnAxis(axis_y, deltaRotation);
        axis_x.applyAxisAngle(axis_y, -deltaRotation);
        axis_z.applyAxisAngle(axis_y, -deltaRotation);
      }
      else if(event.movementX < 0) {
        network.rotateOnAxis(axis_y, -deltaRotation);
        axis_x.applyAxisAngle(axis_y, deltaRotation);
        axis_z.applyAxisAngle(axis_y, deltaRotation);
      }
      else if(event.movementY > 0) {
        network.rotateOnAxis(axis_x, deltaRotation);
        axis_y.applyAxisAngle(axis_x, -deltaRotation);
        axis_z.applyAxisAngle(axis_x, -deltaRotation);
      }
      else if(event.movementY < 0) {
        network.rotateOnAxis(axis_x, -deltaRotation);
        axis_y.applyAxisAngle(axis_x, deltaRotation);
        axis_z.applyAxisAngle(axis_x, deltaRotation);
      }
    }
    //left mouse button
    else if(event.which == 1) {
      var mouseX = event.clientX / WIDTH;
      var mouseY = event.clientY / HEIGHT;
      //movement in y: up is negative, down is positive
      camera.position.x = camera.position.x - (mouseX * event.movementX);
      camera.position.y = camera.position.y + (mouseY * event.movementY);
    }

    window.requestAnimationFrame(updateGraph);
  }

  window.addEventListener('mouseup', mouseup, false);
  function mouseup(event) {
    //console.log("up");
  }

  window.addEventListener('click', mousedown, false);
  function mousedown(event) {

    //var raycaster = new THREE.Raycaster(); // create once
    //var mouse = new THREE.Vector2();

    //event.preventDefault();

    //mouse.x = ( event.clientX / WIDTH ) * 2 - 1; //renderer.domElement.width
    //mouse.y = - ( event.clientY / HEIGHT ) * 2 + 1; //renderer.domElement.height

    //// update the picking ray with the camera and mouse position
    //raycaster.setFromCamera( mouse, camera );
    //// calculate objects intersecting the picking ray
    //var intersects = raycaster.intersectObjects( nodes.children );
    //for ( var i = 0; i < intersects.length; i++ ) {
      //intersects[ i ].object.material.color.set( 0xff0000 );
    //}
    ////console.log(nodes.children);
    //updateGraph();
  }

  window.addEventListener('resize', windowResize, false);
  function windowResize() {
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
    renderer.setSize(WIDTH, HEIGHT);
  }
}

function switchTo2D(network) {
  for(var i = 0; i < network.children[0].children.length; i++) {
    network.children[0].children[i].position.setZ(0);
  }

  for(var i = 0; i < network.children[1].children.length; i++) {
    network.children[1].children[i].geometry.vertices[0].setZ(0);
    network.children[1].children[i].geometry.vertices[1].setZ(0);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
  }
  window.requestAnimationFrame(updateGraph);
}

function switchTo3D() {
  for(node in node_keys) {
    var z = nodes_obj[node].getFeature('coords').z;
    network.children[0].children[node].position.setZ(z);
  }

  var i = 0; //TODO
  for (var u_edge in und_edges) {
    edge = und_edges[u_edge];
    node_a_id = edge._node_a.getID();
    node_b_id = edge._node_b.getID();

    var z_a = nodes_obj[node_a_id].getFeature('coords').z;
    var z_b = nodes_obj[node_b_id].getFeature('coords').z;

    network.children[1].children[i].geometry.vertices[0].setZ(z_a);
    network.children[1].children[i].geometry.vertices[1].setZ(z_b);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
    i++;
  }
  for (var d_edge in dir_edges) {
    edge = dir_edges[d_edge];
    node_a_id = edge._node_a.getID();
    node_b_id = edge._node_b.getID();

    var z_a = nodes_obj[node_a_id].getFeature('coords').z;
    var z_b = nodes_obj[node_b_id].getFeature('coords').z;

    network.children[1].children[i].geometry.vertices[0].setZ(z_a);
    network.children[1].children[i].geometry.vertices[1].setZ(z_b);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
    i++;
  }
  window.requestAnimationFrame(updateGraph);
}

if (window !== 'undefined') {
  // window.test = test;

  window.$GV = {
    renderGraph: renderGraph,
    switchTo2D: switchTo2D,
    switchTo3D: switchTo3D
  }
}
<commit_msg>changed rotation a bit, fixed object z axis<commit_after>var ZOOM_FACTOR = 0.05,
    MAX_FOV = 100, //zoom out
    MIN_FOV = 20, //zoom in
    KEY_A = 97,
    KEY_D = 100,
    KEY_W = 119,
    KEY_S = 115,
    KEY_R = 114,
    KEY_F = 102,
    KEY_X = 120,
    KEY_Y = 121,
    KEY_C = 99,
    KEY_SX = 88,
    KEY_SY = 89,
    KEY_SC = 67,
    WIDTH = 1500,
    HEIGHT = 900,
    mouse = [0.5, 0.5];

window.axis_x = new THREE.Vector3( 1, 0, 0 );
window.axis_y = new THREE.Vector3( 0, 1, 0 );
window.axis_z = new THREE.Vector3( 0, 0, 1 );
var deltaDistance = 10; //distance to move
var deltaRotation = 0.05; //rotation step

renderButton.onclick = function() {
  initGraph();
  window.$GV.renderGraph();
}

function renderGraph() {
  var MIN_X = MAX_X = nodes_obj[0].getFeature('coords').x,
      MIN_Y = MAX_Y = nodes_obj[0].getFeature('coords').y,
      MIN_Z = MAX_Z = nodes_obj[0].getFeature('coords').z,
      AVG_X = AVG_Y = AVG_Z = 0;

  for(node in nodes_obj) {
    var x = nodes_obj[node].getFeature('coords').x;
    var y = nodes_obj[node].getFeature('coords').y;
    var z = nodes_obj[node].getFeature('coords').z;

    MIN_X = Math.min(MIN_X, x);
    MIN_Y = Math.min(MIN_Y, y);
    MIN_Z = Math.min(MIN_Z, z);

    MAX_X = Math.max(MAX_X, x);
    MAX_Y = Math.max(MAX_Y, y);
    MAX_Z = Math.max(MAX_Z, z);
  }
  AVG_X = (MAX_X - MIN_X) / 2;
  AVG_Y = (MAX_Y - MIN_Y) / 2;
  AVG_Z = (MAX_Z - MIN_Z) / 2;

  var scene = new THREE.Scene(); // Create a Three.js scene object.
  var camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 0.1, 1000); //TODO change to 0.1// Define the perspective camera's attributes.
  var renderer = new THREE.WebGLRenderer({ antialias: false }); //window.WebGLRenderingContext ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer(); // Fallback to canvas renderer, if necessary.
  renderer.setSize(WIDTH, HEIGHT); // Set the size of the WebGL viewport.
  renderer.setClearColor( 0x000000, 1 );
  //renderer.setPixelRatio( window.devicePixelRatio );
  //renderer.gammaInput = true;
	//renderer.gammaOutput = true;
  var element = document.getElementById("containerGraph");
  element.appendChild(renderer.domElement); // Append the WebGL viewport to the DOM.

  var i = 0;
  var vertices = new Float32Array( graph.nrNodes() * 3 );
  for(node in nodes_obj) {
    var x = nodes_obj[node].getFeature('coords').x;
    var y = nodes_obj[node].getFeature('coords').y;
    var z = nodes_obj[node].getFeature('coords').z;

    vertices[ i*3 ] = x - AVG_X;
    vertices[ i*3 + 1 ] = y - AVG_Y;
    vertices[ i*3 + 2 ] = z - AVG_Z;
    i++;
  }

  var geometry = new THREE.BufferGeometry();
  geometry.addAttribute('position', new THREE.BufferAttribute(vertices, 3));
  geometry.addAttribute('color', new THREE.BufferAttribute( 0x8aa7ff, 3));

  var material = new THREE.PointsMaterial({ // MeshBasicMaterial
    color: 0x8aa7ff,
    size: 10
    //map: texture
  });

  particles = new THREE.Points( geometry, material );
	//scene.add( particles );

  //EDGE
  var materialLine = new THREE.LineBasicMaterial({
    color: 0x81cf28,
    transparent : true,
    opacity: 0.5//default is 1; range: 0.0 - 1.0
   //vertexColors: THREE.VertexColors  //,
    //linewidth: 1
  });

  window.network = new THREE.Group();
  console.log(network);
  network.add(particles);

  [und_edges, dir_edges].forEach(function(edges) {
    var i = 0;
    var positionLine = new Float32Array(Object.keys(edges).length * 6); //2 vertices * 3 xyz
    for (var edge_index in edges) {
      var edge = edges[edge_index];
      var node_a_id = edge._node_a.getID();
      var node_b_id = edge._node_b.getID();

      positionLine[ i * 6 ] = nodes_obj[node_a_id].getFeature('coords').x - AVG_X;
      positionLine[ i * 6 + 1 ] = nodes_obj[node_a_id].getFeature('coords').y - AVG_Y;
      positionLine[ i * 6 + 2 ] = nodes_obj[node_a_id].getFeature('coords').z - AVG_Z;
      positionLine[ i * 6 + 3 ] = nodes_obj[node_b_id].getFeature('coords').x - AVG_X;
      positionLine[ i * 6 + 4 ] = nodes_obj[node_b_id].getFeature('coords').y - AVG_Y;
      positionLine[ i * 6 + 5 ] = nodes_obj[node_b_id].getFeature('coords').z - AVG_Z;
      i++;
    }
    var geometryLine = new THREE.BufferGeometry();
    geometryLine.addAttribute('position', new THREE.BufferAttribute(positionLine, 3));
    //geometryLine.addAttribute('color', new THREE.BufferAttribute( 0xff700e, 3));
    //geometry.computeBoundingSphere();
    var line = new THREE.Line( geometryLine, materialLine );
    //scene.add( line );
    network.add(line);
  });

  // network.translateX(-MAX_X/2);
  // network.translateY(-MAX_Y/2);
  // network.translateZ(-MAX_Z/2);
  scene.add(network);
  camera.position.z = Math.max(MAX_X, MAX_Y);
  //camera.position.z = 500; // Move the camera away from the origin, down the positive z-axis.
  //camera.lookat(new THREE.Vector3(0,0,0));

  //The X axis is red. The Y axis is green. The Z axis is blue.
  //var axisHelper = new THREE.AxisHelper( Math.max(MAX_X, Math.max(MAX_Y, MAX_Z)) );
  //scene.add( axisHelper );
  //network.applyMatrix(axisHelper.matrixWorld);

  var updateGraph = function () {
    renderer.render(scene, camera); // Each time we change the position of the cube object, we must re-render it.
    //requestAnimationFrame(render); // Call the render() function up to 60 times per second (i.e., up to 60 animation frames per second).
  };
  window.requestAnimationFrame(updateGraph);

  window.addEventListener('keypress', key, false);
  function key(event) {
    switch (event.charCode) {
      case KEY_W: //zoom in
        camera.position.y = camera.position.y - deltaDistance; break;
        //network.translateY(deltaDistance); break;
      case KEY_S: //zoom out
        camera.position.y = camera.position.y + deltaDistance; break;
        //network.translateY(-deltaDistance); break;
      case KEY_A: //move left
        camera.position.x = camera.position.x + deltaDistance; break;
        //network.translateX(-deltaDistance); break;
      case KEY_D: //move right
        camera.position.x = camera.position.x - deltaDistance; break;
        //network.translateX(deltaDistance); break;
      case KEY_R:
        network.translateZ(deltaDistance); break;
      case KEY_F:
        network.translateZ(-deltaDistance); break;

      case KEY_X:
        //network.rotation.x += deltaRotation; break;
        network.rotateOnAxis(axis_x, deltaRotation);
        axis_y.applyAxisAngle(axis_x, -deltaRotation);
        // axis_z.applyAxisAngle(axis_x, -deltaRotation);
        break;
      case KEY_SX:
        //network.rotation.x -= deltaRotation; break;
        network.rotateOnAxis(axis_x, -deltaRotation);
        axis_y.applyAxisAngle(axis_x, deltaRotation);
        // axis_z.applyAxisAngle(axis_x, deltaRotation);
        break;
      case KEY_Y:
        //network.rotation.y += deltaRotation; break;
        network.rotateOnAxis(axis_y, deltaRotation);
        axis_x.applyAxisAngle(axis_y, -deltaRotation);
        // axis_z.applyAxisAngle(axis_y, -deltaRotation);
        break;
      case KEY_SY:
        //network.rotation.y -= deltaRotation; break;
        network.rotateOnAxis(axis_y, -deltaRotation);
        axis_x.applyAxisAngle(axis_y, deltaRotation);
        // axis_z.applyAxisAngle(axis_y, deltaRotation);
        break;
      case KEY_C:
        //network.rotation.z += deltaRotation; break;
        network.rotateOnAxis(axis_z, deltaRotation);
        axis_x.applyAxisAngle(axis_z, -deltaRotation);
        axis_y.applyAxisAngle(axis_z, -deltaRotation);
        break;
      case KEY_SC:
        //network.rotation.z -= deltaRotation; break;
        network.rotateOnAxis(axis_z, -deltaRotation);
        axis_x.applyAxisAngle(axis_z, deltaRotation);
        axis_y.applyAxisAngle(axis_z, deltaRotation);
        break;
      default:
        break;
    }
    //camera.updateProjectionMatrix();
    window.requestAnimationFrame(updateGraph);
  }

  //zoom in and out
  window.addEventListener('mousewheel', mousewheel, false);
  function mousewheel(event) {
    //wheel down: negative value
    //wheel up: positive value
    if(event.shiftKey) {
      if(event.wheelDelta < 0) {
        network.rotateOnAxis(axis_y, -deltaRotation);
        axis_x.applyAxisAngle(axis_y, deltaRotation);
        // axis_z.applyAxisAngle(axis_y, deltaRotation);
      }
      else {
        network.rotateOnAxis(axis_y, deltaRotation);
        axis_x.applyAxisAngle(axis_y, -deltaRotation);
        // axis_z.applyAxisAngle(axis_y, -deltaRotation);
      }
    }
    else {
      camera.fov -= ZOOM_FACTOR * event.wheelDeltaY;
      camera.fov = Math.max( Math.min( camera.fov, MAX_FOV ), MIN_FOV );
      camera.projectionMatrix = new THREE.Matrix4().makePerspective(camera.fov, WIDTH / HEIGHT, camera.near, camera.far);
    }
    window.requestAnimationFrame(updateGraph);
  }

  document.addEventListener( 'mousemove', mouseMove, false );
  function mouseMove(event) {

    if(event.shiftKey && event.which == 1) {
      if(event.movementX > 0) {
        network.rotateOnAxis(axis_z, deltaRotation);
        axis_x.applyAxisAngle(axis_z, -deltaRotation);
        axis_y.applyAxisAngle(axis_z, -deltaRotation);
      }
      else if(event.movementX < 0) {
        network.rotateOnAxis(axis_z, -deltaRotation);
        axis_x.applyAxisAngle(axis_z, deltaRotation);
        axis_y.applyAxisAngle(axis_z, deltaRotation);
      }
      else if(event.movementY > 0) {
        network.rotateOnAxis(axis_x, deltaRotation);
        axis_y.applyAxisAngle(axis_x, -deltaRotation);
        // axis_z.applyAxisAngle(axis_x, -deltaRotation);
      }
      else if(event.movementY < 0) {
        network.rotateOnAxis(axis_x, -deltaRotation);
        axis_y.applyAxisAngle(axis_x, deltaRotation);
        // axis_z.applyAxisAngle(axis_x, deltaRotation);
      }
    }
    //left mouse button
    else if(event.which == 1) {
      var mouseX = event.clientX / WIDTH;
      var mouseY = event.clientY / HEIGHT;
      //movement in y: up is negative, down is positive
      camera.position.x = camera.position.x - (mouseX * event.movementX);
      camera.position.y = camera.position.y + (mouseY * event.movementY);
    }

    window.requestAnimationFrame(updateGraph);
  }

  window.addEventListener('mouseup', mouseup, false);
  function mouseup(event) {
    //console.log("up");
  }

  window.addEventListener('click', mousedown, false);
  function mousedown(event) {

    //var raycaster = new THREE.Raycaster(); // create once
    //var mouse = new THREE.Vector2();

    //event.preventDefault();

    //mouse.x = ( event.clientX / WIDTH ) * 2 - 1; //renderer.domElement.width
    //mouse.y = - ( event.clientY / HEIGHT ) * 2 + 1; //renderer.domElement.height

    //// update the picking ray with the camera and mouse position
    //raycaster.setFromCamera( mouse, camera );
    //// calculate objects intersecting the picking ray
    //var intersects = raycaster.intersectObjects( nodes.children );
    //for ( var i = 0; i < intersects.length; i++ ) {
      //intersects[ i ].object.material.color.set( 0xff0000 );
    //}
    ////console.log(nodes.children);
    //updateGraph();
  }

  window.addEventListener('resize', windowResize, false);
  function windowResize() {
    camera.aspect = WIDTH / HEIGHT;
    camera.updateProjectionMatrix();
    renderer.setSize(WIDTH, HEIGHT);
  }
}

function switchTo2D(network) {
  for(var i = 0; i < network.children[0].children.length; i++) {
    network.children[0].children[i].position.setZ(0);
  }

  for(var i = 0; i < network.children[1].children.length; i++) {
    network.children[1].children[i].geometry.vertices[0].setZ(0);
    network.children[1].children[i].geometry.vertices[1].setZ(0);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
  }
  window.requestAnimationFrame(updateGraph);
}

function switchTo3D() {
  for(node in node_keys) {
    var z = nodes_obj[node].getFeature('coords').z;
    network.children[0].children[node].position.setZ(z);
  }

  var i = 0; //TODO
  for (var u_edge in und_edges) {
    edge = und_edges[u_edge];
    node_a_id = edge._node_a.getID();
    node_b_id = edge._node_b.getID();

    var z_a = nodes_obj[node_a_id].getFeature('coords').z;
    var z_b = nodes_obj[node_b_id].getFeature('coords').z;

    network.children[1].children[i].geometry.vertices[0].setZ(z_a);
    network.children[1].children[i].geometry.vertices[1].setZ(z_b);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
    i++;
  }
  for (var d_edge in dir_edges) {
    edge = dir_edges[d_edge];
    node_a_id = edge._node_a.getID();
    node_b_id = edge._node_b.getID();

    var z_a = nodes_obj[node_a_id].getFeature('coords').z;
    var z_b = nodes_obj[node_b_id].getFeature('coords').z;

    network.children[1].children[i].geometry.vertices[0].setZ(z_a);
    network.children[1].children[i].geometry.vertices[1].setZ(z_b);
    network.children[1].children[i].geometry.verticesNeedUpdate = true;
    i++;
  }
  window.requestAnimationFrame(updateGraph);
}

if (window !== 'undefined') {
  // window.test = test;

  window.$GV = {
    renderGraph: renderGraph,
    switchTo2D: switchTo2D,
    switchTo3D: switchTo3D
  }
}
<|endoftext|>


<commit_before>/**
 * Constructs a new cross storage client given the url to a hub. By default,
 * an iframe is created within the document body that points to the url. It
 * also accepts an options object, which may include a timeout, frameId, and
 * promise. The timeout, in milliseconds, is applied to each request and
 * defaults to 3000ms. The options object may also include a frameId,
 * identifying an existing frame on which to install its listeners. If the
 * promise key is supplied the constructor for a Promise, that Promise library
 * will be used instead of the default window.Promise.
 *
 * @example
 * var storage = new CrossStorageClient('https://store.example.com/hub.html');
 *
 * @example
 * var storage = new CrossStorageClient('https://store.example.com/hub.html', {
 *   timeout: 5000,
 *   frameId: 'storageFrame'
 * });
 *
 * @constructor
 *
 * @param {string} url    The url to a cross storage hub
 * @param {object} [opts] An optional object containing additional options,
 *                        including timeout, frameId, and promise
 *
 * @property {string}   _id        A UUID v4 id
 * @property {function} _promise   The Promise object to use
 * @property {string}   _frameId   The id of the iFrame pointing to the hub url
 * @property {string}   _origin    The hub's origin
 * @property {object}   _requests  Mapping of request ids to callbacks
 * @property {bool}     _connected Whether or not it has connected
 * @property {bool}     _closed    Whether or not the client has closed
 * @property {int}      _count     Number of requests sent
 * @property {function} _listener  The listener added to the window
 * @property {Window}   _hub       The hub window
 */
function CrossStorageClient(url, opts) {
  opts = opts || {};

  this._id        = CrossStorageClient._generateUUID();
  this._promise   = opts.promise || Promise;
  this._frameId   = opts.frameId || 'CrossStorageClient-' + this._id;
  this._origin    = CrossStorageClient._getOrigin(url);
  this._requests  = {};
  this._connected = false;
  this._closed    = false;
  this._count     = 0;
  this._timeout   = opts.timeout || 3000;
  this._listener  = null;

  this._installListener();

  var frame;
  if (opts.frameId) {
    frame = document.getElementById(opts.frameId);
  }

  // If using a passed iframe, poll the hub for a ready message
  if (frame) {
    this._poll();
  }

  // Create the frame if not found or specified
  frame = frame || this._createFrame(url);
  this._hub = frame.contentWindow;
}

/**
 * The styles to be applied to the generated iFrame. Defines a set of properties
 * that hide the element by positioning it outside of the visible area, and
 * by modifying its display.
 *
 * @member {Object}
 */
CrossStorageClient.frameStyle = {
  display:  'none',
  position: 'absolute',
  top:      '-999px',
  left:     '-999px'
};

/**
 * Returns the origin of an url, with cross browser support. Accommodates
 * the lack of location.origin in IE, as well as the discrepancies in the
 * inclusion of the port when using the default port for a protocol, e.g.
 * 443 over https.
 *
 * @param   {string} url The url to a cross storage hub
 * @returns {string} The origin of the url
 */
CrossStorageClient._getOrigin = function(url) {
  var uri, origin;

  uri = document.createElement('a');
  uri.href = url;

  origin = uri.protocol + '//' + uri.host;
  origin = origin.replace(/:80$|:443$/, '');

  return origin;
};

/**
 * UUID v4 generation, taken from: http://stackoverflow.com/questions/
 * 105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
 *
 * @returns {string} A UUID v4 string
 */
CrossStorageClient._generateUUID = function() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16|0, v = c == 'x' ? r : (r&0x3|0x8);

    return v.toString(16);
  });
};

/**
 * Returns a promise that is fulfilled when a connection has been established
 * with the cross storage hub. Its use is required to avoid sending any
 * requests prior to initialization being complete.
 *
 * @returns {Promise} A promise that is resolved on connect
 */
CrossStorageClient.prototype.onConnect = function() {
  var client = this;

  if (this._connected) {
    return this._promise.resolve();
  } else if (this._closed) {
    return this._promise.reject(new Error('CrossStorageClient has closed'));
  }

  // Queue connect requests for client re-use
  if (!this._requests.connect) {
    this._requests.connect = [];
  }

  return new this._promise(function(resolve, reject) {
    var timeout = setTimeout(function() {
      reject(new Error('CrossStorageClient could not connect'));
    }, client._timeout);

    client._requests.connect.push(function(err) {
      clearTimeout(timeout);
      if (err) return reject(err);

      resolve();
    });
  });
};

/**
 * Sets a key to the specified value, optionally accepting a ttl to passively
 * expire the key after a number of milliseconds. Returns a promise that is
 * fulfilled on success, or rejected if any errors setting the key occurred,
 * or the request timed out.
 *
 * @param   {string}  key   The key to set
 * @param   {*}       value The value to assign
 * @param   {int}     ttl   Time to live in milliseconds
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.set = function(key, value, ttl) {
  return this._request('set', {
    key:   key,
    value: value,
    ttl:   ttl
  });
};

/**
 * Accepts one or more keys for which to retrieve their values. Returns a
 * promise that is settled on hub response or timeout. On success, it is
 * fulfilled with the value of the key if only passed a single argument.
 * Otherwise it's resolved with an array of values. On failure, it is rejected
 * with the corresponding error message.
 *
 * @param   {...string} key The key to retrieve
 * @returns {Promise}   A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.get = function(key) {
  var args = Array.prototype.slice.call(arguments);

  return this._request('get', {keys: args});
};

/**
 * Accepts one or more keys for deletion. Returns a promise that is settled on
 * hub response or timeout.
 *
 * @param   {...string} key The key to delete
 * @returns {Promise}   A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.del = function() {
  var args = Array.prototype.slice.call(arguments);

  return this._request('del', {keys: args});
};

/**
 * Returns a promise that, when resolved, passes an array of all keys
 * currently in storage.
 *
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.getKeys = function() {
  return this._request('getKeys');
};

/**
 * Deletes the iframe and sets the connected state to false. The client can
 * no longer be used after being invoked.
 */
CrossStorageClient.prototype.close = function() {
  var frame = document.getElementById(this._frameId);
  if (frame) {
    frame.parentNode.removeChild(frame);
  }

  // Support IE8 with detachEvent
  if (window.removeEventListener) {
    window.removeEventListener('message', this._listener, false);
  } else {
    window.detachEvent('onmessage', this._listener);
  }

  this._connected = false;
  this._closed = true;
};

/**
 * Installs the necessary listener for the window message event. When a message
 * is received, the client's _connected status is changed to true, and the
 * onConnect promise is fulfilled. Given a response message, the callback
 * corresponding to its request is invoked. If response.error holds a truthy
 * value, the promise associated with the original request is rejected with
 * the error. Otherwise the promise is fulfilled and passed response.result.
 *
 * @private
 */
CrossStorageClient.prototype._installListener = function() {
  var client = this;

  this._listener = function(message) {
    var i, error;

    if (client._closed) return;

    // Ignore messages not from our hub
    if (message.origin !== client._origin) return;

    // LocalStorage isn't available in the hub
    if (message.data === 'unavailable') {
      if (!client._closed) client.close();
      if (!client._requests.connect) return;

      error = new Error('Closing client. Could not access localStorage in hub.');
      for (i = 0; i < client._requests.connect.length; i++) {
        client._requests.connect[i](error);
      }

      return;
    }

    // Handle initial connection
    if (!client._connected) {
      client._connected = true;
      if (!client._requests.connect) return;

      for (i = 0; i < client._requests.connect.length; i++) {
        client._requests.connect[i](error);
      }
      delete client._requests.connect;
    }

    if (message.data === 'ready') return;

    // All other messages
    var response = JSON.parse(message.data);
    if (!response.id) return;

    if (client._requests[response.id]) {
      client._requests[response.id](response.error, response.result);
    }
  };

  // Support IE8 with attachEvent
  if (window.addEventListener) {
    window.addEventListener('message', this._listener, false);
  } else {
    window.attachEvent('onmessage', this._listener);
  }
};

/**
 * Invoked when a frame id was passed to the client, rather than allowing
 * the client to create its own iframe. Polls the hub for a ready event to
 * establish a connected state.
 */
CrossStorageClient.prototype._poll = function() {
  var client, interval;

  client = this;
  interval = setInterval(function() {
    if (client._connected) return clearInterval(interval);
    if (!client._hub) return;

    client._hub.postMessage('poll', client._origin);
  }, 1000);
};

/**
 * Creates a new iFrame containing the hub. Applies the necessary styles to
 * hide the element from view, prior to adding it to the document body.
 * Returns the created element.
 *
 * @private
 *
 * @param  {string}            url The url to the hub
 * returns {HTMLIFrameElement} The iFrame element itself
 */
CrossStorageClient.prototype._createFrame = function(url) {
  var frame = window.document.createElement('iframe');
  frame.id = this._frameId;

  // Style the iframe
  for (var key in CrossStorageClient.frameStyle) {
    if (CrossStorageClient.frameStyle.hasOwnProperty(key)) {
      frame.style[key] = CrossStorageClient.frameStyle[key];
    }
  }

  window.document.body.appendChild(frame);
  frame.src = url;

  return frame;
};

/**
 * Sends a message containing the given method and params to the hub. Stores
 * a callback in the _requests object for later invocation on message, or
 * deletion on timeout. Returns a promise that is settled in either instance.
 *
 * @private
 *
 * @param   {string}  method The method to invoke
 * @param   {*}       params The arguments to pass
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype._request = function(method, params) {
  var req, client;

  if (this._closed) {
    return this._promise.reject(new Error('CrossStorageClient has closed'));
  }

  client = this;
  client._count++;

  req = {
    id:     this._id + ':' + client._count,
    method: method,
    params: params
  };

  return new this._promise(function(resolve, reject) {
    // Timeout if a response isn't received after 4s
    var timeout = setTimeout(function() {
      if (!client._requests[req.id]) return;

      delete client._requests[req.id];
      reject(new Error('Timeout: could not perform ' + req.method));
    }, client._timeout);

    // Add request callback
    client._requests[req.id] = function(err, result) {
      clearTimeout(timeout);
      if (err) return reject(new Error(err));
      resolve(result);
    };

    // In case we have a broken Array.prototype.toJSON, e.g. because of
    // old versions of prototype
    var originalToJSON;

    if (Array.prototype.toJSON) {
      originalToJSON = Array.prototype.toJSON;
      Array.prototype.toJSON = null;
    }

    // Send serialized message
    client._hub.postMessage(JSON.stringify(req), client._origin);

    // Restore original toJSON
    if (originalToJSON) {
      Array.prototype.toJSON = originalToJSON;
    }
  });
};
<commit_msg>Ignore unsupported messages to the client<commit_after>/**
 * Constructs a new cross storage client given the url to a hub. By default,
 * an iframe is created within the document body that points to the url. It
 * also accepts an options object, which may include a timeout, frameId, and
 * promise. The timeout, in milliseconds, is applied to each request and
 * defaults to 3000ms. The options object may also include a frameId,
 * identifying an existing frame on which to install its listeners. If the
 * promise key is supplied the constructor for a Promise, that Promise library
 * will be used instead of the default window.Promise.
 *
 * @example
 * var storage = new CrossStorageClient('https://store.example.com/hub.html');
 *
 * @example
 * var storage = new CrossStorageClient('https://store.example.com/hub.html', {
 *   timeout: 5000,
 *   frameId: 'storageFrame'
 * });
 *
 * @constructor
 *
 * @param {string} url    The url to a cross storage hub
 * @param {object} [opts] An optional object containing additional options,
 *                        including timeout, frameId, and promise
 *
 * @property {string}   _id        A UUID v4 id
 * @property {function} _promise   The Promise object to use
 * @property {string}   _frameId   The id of the iFrame pointing to the hub url
 * @property {string}   _origin    The hub's origin
 * @property {object}   _requests  Mapping of request ids to callbacks
 * @property {bool}     _connected Whether or not it has connected
 * @property {bool}     _closed    Whether or not the client has closed
 * @property {int}      _count     Number of requests sent
 * @property {function} _listener  The listener added to the window
 * @property {Window}   _hub       The hub window
 */
function CrossStorageClient(url, opts) {
  opts = opts || {};

  this._id        = CrossStorageClient._generateUUID();
  this._promise   = opts.promise || Promise;
  this._frameId   = opts.frameId || 'CrossStorageClient-' + this._id;
  this._origin    = CrossStorageClient._getOrigin(url);
  this._requests  = {};
  this._connected = false;
  this._closed    = false;
  this._count     = 0;
  this._timeout   = opts.timeout || 3000;
  this._listener  = null;

  this._installListener();

  var frame;
  if (opts.frameId) {
    frame = document.getElementById(opts.frameId);
  }

  // If using a passed iframe, poll the hub for a ready message
  if (frame) {
    this._poll();
  }

  // Create the frame if not found or specified
  frame = frame || this._createFrame(url);
  this._hub = frame.contentWindow;
}

/**
 * The styles to be applied to the generated iFrame. Defines a set of properties
 * that hide the element by positioning it outside of the visible area, and
 * by modifying its display.
 *
 * @member {Object}
 */
CrossStorageClient.frameStyle = {
  display:  'none',
  position: 'absolute',
  top:      '-999px',
  left:     '-999px'
};

/**
 * Returns the origin of an url, with cross browser support. Accommodates
 * the lack of location.origin in IE, as well as the discrepancies in the
 * inclusion of the port when using the default port for a protocol, e.g.
 * 443 over https.
 *
 * @param   {string} url The url to a cross storage hub
 * @returns {string} The origin of the url
 */
CrossStorageClient._getOrigin = function(url) {
  var uri, origin;

  uri = document.createElement('a');
  uri.href = url;

  origin = uri.protocol + '//' + uri.host;
  origin = origin.replace(/:80$|:443$/, '');

  return origin;
};

/**
 * UUID v4 generation, taken from: http://stackoverflow.com/questions/
 * 105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
 *
 * @returns {string} A UUID v4 string
 */
CrossStorageClient._generateUUID = function() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16|0, v = c == 'x' ? r : (r&0x3|0x8);

    return v.toString(16);
  });
};

/**
 * Returns a promise that is fulfilled when a connection has been established
 * with the cross storage hub. Its use is required to avoid sending any
 * requests prior to initialization being complete.
 *
 * @returns {Promise} A promise that is resolved on connect
 */
CrossStorageClient.prototype.onConnect = function() {
  var client = this;

  if (this._connected) {
    return this._promise.resolve();
  } else if (this._closed) {
    return this._promise.reject(new Error('CrossStorageClient has closed'));
  }

  // Queue connect requests for client re-use
  if (!this._requests.connect) {
    this._requests.connect = [];
  }

  return new this._promise(function(resolve, reject) {
    var timeout = setTimeout(function() {
      reject(new Error('CrossStorageClient could not connect'));
    }, client._timeout);

    client._requests.connect.push(function(err) {
      clearTimeout(timeout);
      if (err) return reject(err);

      resolve();
    });
  });
};

/**
 * Sets a key to the specified value, optionally accepting a ttl to passively
 * expire the key after a number of milliseconds. Returns a promise that is
 * fulfilled on success, or rejected if any errors setting the key occurred,
 * or the request timed out.
 *
 * @param   {string}  key   The key to set
 * @param   {*}       value The value to assign
 * @param   {int}     ttl   Time to live in milliseconds
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.set = function(key, value, ttl) {
  return this._request('set', {
    key:   key,
    value: value,
    ttl:   ttl
  });
};

/**
 * Accepts one or more keys for which to retrieve their values. Returns a
 * promise that is settled on hub response or timeout. On success, it is
 * fulfilled with the value of the key if only passed a single argument.
 * Otherwise it's resolved with an array of values. On failure, it is rejected
 * with the corresponding error message.
 *
 * @param   {...string} key The key to retrieve
 * @returns {Promise}   A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.get = function(key) {
  var args = Array.prototype.slice.call(arguments);

  return this._request('get', {keys: args});
};

/**
 * Accepts one or more keys for deletion. Returns a promise that is settled on
 * hub response or timeout.
 *
 * @param   {...string} key The key to delete
 * @returns {Promise}   A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.del = function() {
  var args = Array.prototype.slice.call(arguments);

  return this._request('del', {keys: args});
};

/**
 * Returns a promise that, when resolved, passes an array of all keys
 * currently in storage.
 *
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype.getKeys = function() {
  return this._request('getKeys');
};

/**
 * Deletes the iframe and sets the connected state to false. The client can
 * no longer be used after being invoked.
 */
CrossStorageClient.prototype.close = function() {
  var frame = document.getElementById(this._frameId);
  if (frame) {
    frame.parentNode.removeChild(frame);
  }

  // Support IE8 with detachEvent
  if (window.removeEventListener) {
    window.removeEventListener('message', this._listener, false);
  } else {
    window.detachEvent('onmessage', this._listener);
  }

  this._connected = false;
  this._closed = true;
};

/**
 * Installs the necessary listener for the window message event. When a message
 * is received, the client's _connected status is changed to true, and the
 * onConnect promise is fulfilled. Given a response message, the callback
 * corresponding to its request is invoked. If response.error holds a truthy
 * value, the promise associated with the original request is rejected with
 * the error. Otherwise the promise is fulfilled and passed response.result.
 *
 * @private
 */
CrossStorageClient.prototype._installListener = function() {
  var client = this;

  this._listener = function(message) {
    var i, error, response;

    if (client._closed) return;

    // Ignore messages not from our hub
    if (message.origin !== client._origin) return;

    // LocalStorage isn't available in the hub
    if (message.data === 'unavailable') {
      if (!client._closed) client.close();
      if (!client._requests.connect) return;

      error = new Error('Closing client. Could not access localStorage in hub.');
      for (i = 0; i < client._requests.connect.length; i++) {
        client._requests.connect[i](error);
      }

      return;
    }

    // Handle initial connection
    if (!client._connected) {
      client._connected = true;
      if (!client._requests.connect) return;

      for (i = 0; i < client._requests.connect.length; i++) {
        client._requests.connect[i](error);
      }
      delete client._requests.connect;
    }

    if (message.data === 'ready') return;

    // All other messages
    try {
      response = JSON.parse(message.data);
    } catch(e) {
      return;
    }

    if (!response.id) return;

    if (client._requests[response.id]) {
      client._requests[response.id](response.error, response.result);
    }
  };

  // Support IE8 with attachEvent
  if (window.addEventListener) {
    window.addEventListener('message', this._listener, false);
  } else {
    window.attachEvent('onmessage', this._listener);
  }
};

/**
 * Invoked when a frame id was passed to the client, rather than allowing
 * the client to create its own iframe. Polls the hub for a ready event to
 * establish a connected state.
 */
CrossStorageClient.prototype._poll = function() {
  var client, interval;

  client = this;
  interval = setInterval(function() {
    if (client._connected) return clearInterval(interval);
    if (!client._hub) return;

    client._hub.postMessage('poll', client._origin);
  }, 1000);
};

/**
 * Creates a new iFrame containing the hub. Applies the necessary styles to
 * hide the element from view, prior to adding it to the document body.
 * Returns the created element.
 *
 * @private
 *
 * @param  {string}            url The url to the hub
 * returns {HTMLIFrameElement} The iFrame element itself
 */
CrossStorageClient.prototype._createFrame = function(url) {
  var frame = window.document.createElement('iframe');
  frame.id = this._frameId;

  // Style the iframe
  for (var key in CrossStorageClient.frameStyle) {
    if (CrossStorageClient.frameStyle.hasOwnProperty(key)) {
      frame.style[key] = CrossStorageClient.frameStyle[key];
    }
  }

  window.document.body.appendChild(frame);
  frame.src = url;

  return frame;
};

/**
 * Sends a message containing the given method and params to the hub. Stores
 * a callback in the _requests object for later invocation on message, or
 * deletion on timeout. Returns a promise that is settled in either instance.
 *
 * @private
 *
 * @param   {string}  method The method to invoke
 * @param   {*}       params The arguments to pass
 * @returns {Promise} A promise that is settled on hub response or timeout
 */
CrossStorageClient.prototype._request = function(method, params) {
  var req, client;

  if (this._closed) {
    return this._promise.reject(new Error('CrossStorageClient has closed'));
  }

  client = this;
  client._count++;

  req = {
    id:     this._id + ':' + client._count,
    method: method,
    params: params
  };

  return new this._promise(function(resolve, reject) {
    // Timeout if a response isn't received after 4s
    var timeout = setTimeout(function() {
      if (!client._requests[req.id]) return;

      delete client._requests[req.id];
      reject(new Error('Timeout: could not perform ' + req.method));
    }, client._timeout);

    // Add request callback
    client._requests[req.id] = function(err, result) {
      clearTimeout(timeout);
      if (err) return reject(new Error(err));
      resolve(result);
    };

    // In case we have a broken Array.prototype.toJSON, e.g. because of
    // old versions of prototype
    var originalToJSON;

    if (Array.prototype.toJSON) {
      originalToJSON = Array.prototype.toJSON;
      Array.prototype.toJSON = null;
    }

    // Send serialized message
    client._hub.postMessage(JSON.stringify(req), client._origin);

    // Restore original toJSON
    if (originalToJSON) {
      Array.prototype.toJSON = originalToJSON;
    }
  });
};
<|endoftext|>


<commit_before>
'use strict';

var url    = require( 'url' );
var query  = require( 'querystring' );
var http   = require( 'http' );
var https  = require( 'https' );
var crypto = require( 'crypto' );
var util   = require( 'util' );
var events = require( 'events' );

var OAuth = {
  util: require( './util' )
};

var OAuthClient = (function() {

  var $;

  // Default options
  var defaults = {
    // The OAuth protocol version
    version: 1,
    // Consumer credentials
    consumer: {},
    // Consumer access tokens
    token: {},
    // Request options
    options: {
      // API base URL
      baseUrl: '',
      // Request token URL
      tokenUrl: '',
      // Access token URL
      accessUrl: '',
      // OAuth signature method
      signatureMethod: 'HMAC-SHA1',
      // HTTP headers
      headers: {
        'Accept': '*/*',
        'Connection': 'Close',
        'User-Agent': 'node.js ' + process.versions.node
      }
    }
  };

  // Constructor
  function OAuthClient( options ) {

    // Sanity check / shortcut
    if( !(this instanceof OAuthClient) )
      return new OAuthClient( options );

    // Call parent constructor
    // events.EventEmitter.call( this );

    // configure
    OAuth.util.extend(
      true, this, defaults, options
    );

  }

  // Inherit EventEmitter
  // util.inherits( OAuthClient, events.EventEmitter );

  // Prototype shortcut reference
  $ = OAuthClient.prototype;

  $.getNonce = function() {

    var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
        nonce = '';

    for( var i = 32, c = chars.length; i < c; i++ )
      nonce += chars[ ( Math.random() * c ) | 0 ];

    return nonce;

  };

  $.getTime = function() {
    return ( new Date().getTime() / 1000 ) | 0;
  };

  $.getRequestToken = function( params, callback ) {
    this.getToken( this.options.tokenUrl, params, callback );
  };

  $.getAccessToken = function( params, callback ) {
    this.getToken( this.options.accessUrl, params, callback );
  };

  $.getToken = function( resource, params, callback ) {

    var self = this;

    this.get(
      resource, params || {},
      function( error, data, response ) {

        if( response.statusCode === 200 ) {
          data = query.parse( data );
          self.token = {
            key: data.oauth_token,
            secret: data.oauth_token_secret
          };
        }

        if( callback )
          callback( error, self.token, response );

      }
    );

  };

  $.request = function( method, resource, params, callback ) {

    method = method.toUpperCase();

    resource = this.options.baseUrl + resource;
    resource = url.parse( resource );

    params = this.prepareParams( method, resource, params );
    params = query.stringify( params );

    var ssl = resource.protocol === 'https:'
    var layer = ssl ? https : http;
    var options = url.parse( resource );

    var body = '';

    if( method === 'POST' || method === 'PUT' ) {
      body = params;
    } else {
      options.path += '?' + params;
    }

    var request = layer.request( options, function( response ) {

      var data = '';
      var ended = false;

      response.setEncoding( 'utf8' );
      response.on( 'data', function( chunk ) {
        data += chunk;
      });
      response.on( 'end', function() {
        ended = true;
        callback( null, data, response );
      });
      response.on( 'close', function( error ) {
        if( !ended ) {
          callback( error, data, response );
        }
      });

    });

    request.on( 'error', function( error ) {
      callback( error, null, null );
    });

    request.end( body, 'utf8' );

  };

  $.get = function( resource, params, callback ) {
    this.request( 'GET', resource, params, callback );
  };

  $.post = function( resource, params, callback ) {
    this.request( 'POST', resource, params, callback );
  };

  $.put = function( resource, params, callback ) {
    this.request( 'PUT', resource, params, callback );
  };

  $.delete = function( resource, params, callback ) {
    this.request( 'DELETE', resource, params, callback );
  };

  $.prepareParams = function( method, resource, params ) {

    params = OAuth.util.extend({
      'oauth_timestamp':        this.getTime(),
      'oauth_version':          this.version,
      'oauth_nonce':            this.getNonce(),
      'oauth_signature_method': this.options.signatureMethod,
      'oauth_consumer_key':     this.consumer.key
    }, params );

    if( this.token.key )
      params['oauth_token'] = this.token.key;

    // Sort parameters alphabetically
    var keys = Object.keys( params ).sort();
    var i, key, swap = params, params = {};

    for( i in keys ) {
      key = keys[i];
      params[ key ] = swap[ key ];
    }

    params['oauth_signature'] = this.sign( method, resource, params );

    return params;

  };

  $.sign = function( method, resource, params ) {

    resource = url.parse( resource );
    resource = resource.protocol + '//'
             + resource.host
             + resource.path;
    resource = OAuth.util.encodeComponent( resource )

    // Remove `oauth_signature` if present
    // ref: spec: 9.1.1 ("the oauth_signature parameter MUST be excluded.")
    if( params.oauth_signature )
      delete params.oauth_signature;

    params = query.stringify( params );
    params = OAuth.util.encodeComponent( params );

    var base = [ method, resource, params ].join( '&' );
    var key  = [ this.consumer.secret, this.token.secret ].join( '&' );
    var hash = '';

    switch( this.options.signatureMethod ) {
      case 'HMAC-SHA1':
        hash = crypto.createHmac( 'sha1', key ).update( base ).digest( 'base64' );
        break;
      case 'PLAINTEXT':
        hash = OAuth.util.encodeComponent( key )
        break;
      default:
        throw new Error( 'Signature method not implemented.' );
        break;
    }

    return hash;

  };

  return OAuthClient;

})();

module.exports = OAuthClient;
<commit_msg>Added documentation<commit_after>
'use strict';

var url    = require( 'url' );
var query  = require( 'querystring' );
var http   = require( 'http' );
var https  = require( 'https' );
var crypto = require( 'crypto' );
var util   = require( 'util' );
var events = require( 'events' );

var OAuth = {
  util: require( './util' )
};

var OAuthClient = (function() {

  var $;

  /*
   * Default options
   *
   * @api internal static
   */
  var defaults = {
    // The OAuth protocol version
    version: 1,
    // Consumer credentials
    consumer: {},
    // Consumer access tokens
    token: {},
    // Request options
    options: {
      // API base URL
      baseUrl: '',
      // Request token URL
      tokenUrl: '',
      // Access token URL
      accessUrl: '',
      // OAuth signature method
      signatureMethod: 'HMAC-SHA1',
      // HTTP headers
      headers: {
        'Accept': '*/*',
        'Connection': 'Close',
        'User-Agent': 'node.js ' + process.versions.node
      }
    }
  };

  /*
   * Constructs a new OAuthClient from
   * given options.
   *
   * @api public
   * @param {Object} options
   * @return {OAuthClient}
   */
  function OAuthClient( options ) {

    // Sanity check / shortcut
    if( !(this instanceof OAuthClient) )
      return new OAuthClient( options );

    // Call parent constructor
    // events.EventEmitter.call( this );

    // configure
    OAuth.util.extend(
      true, this, defaults, options
    );

  }

  // Inherit EventEmitter
  // util.inherits( OAuthClient, events.EventEmitter );

  // Prototype shortcut reference
  $ = OAuthClient.prototype;

  /*
   * Generates a nonce to be
   * used in a OAuth request.
   *
   * @api public
   * @return {String} nonce
   */
  $.getNonce = function() {

    var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
        nonce = '';

    for( var i = 32, c = chars.length; i < c; i++ )
      nonce += chars[ ( Math.random() * c ) | 0 ];

    return nonce;

  };

  /*
   * Gets the current time in seconds.
   *
   * @api public
   * @return {Number} timestamp
   */
  $.getTime = function() {
    return ( new Date().getTime() / 1000 ) | 0;
  };

  $.getRequestToken = function( params, callback ) {
    this.getToken( this.options.tokenUrl, params, callback );
  };

  $.getAccessToken = function( params, callback ) {
    this.getToken( this.options.accessUrl, params, callback );
  };

  $.getToken = function( resource, params, callback ) {

    var self = this;

    this.get(
      resource, params || {},
      function( error, data, response ) {

        if( response.statusCode === 200 ) {
          data = query.parse( data );
          self.token = {
            key: data.oauth_token,
            secret: data.oauth_token_secret
          };
        }

        if( callback )
          callback( error, self.token, response );

      }
    );

  };

  /*
   * Performs a HTTP request against `resource`
   * with given `method` and `params`. On completion or
   * error `callback` is called with `error`, `data` and `response`.
   *
   * @api public
   * @param {String} method
   * @param {String} resource
   * @param {Object} params
   * @param {Function} callback
   */
  $.request = function( method, resource, params, callback ) {

    method = method.toUpperCase();

    resource = this.options.baseUrl + resource;
    resource = url.parse( resource );

    params = this.prepareParams( method, resource, params );
    params = query.stringify( params );

    var ssl = resource.protocol === 'https:'
    var layer = ssl ? https : http;
    var options = url.parse( resource );

    var body = '';

    if( method === 'POST' || method === 'PUT' ) {
      body = params;
    } else {
      options.path += '?' + params;
    }

    var request = layer.request( options, function( response ) {

      var data = '';
      var ended = false;

      response.setEncoding( 'utf8' );
      response.on( 'data', function( chunk ) {
        data += chunk;
      });
      response.on( 'end', function() {
        ended = true;
        callback( null, data, response );
      });
      response.on( 'close', function( error ) {
        if( !ended ) {
          callback( error, data, response );
        }
      });

    });

    request.on( 'error', function( error ) {
      callback( error, null, null );
    });

    request.end( body, 'utf8' );

  };

  /*
   * Same as `OAuthClient.request()`, but with 'GET'
   * as preset `method`
   *
   * @api public
   * @param {String} resource
   * @param {Object} params
   * @param {Function} callback
   */
  $.get = function( resource, params, callback ) {
    this.request( 'GET', resource, params, callback );
  };

  /*
   * Same as `OAuthClient.request()`, but with 'POST'
   * as preset `method`
   *
   * @api public
   * @param {String} resource
   * @param {Object} params
   * @param {Function} callback
   */
  $.post = function( resource, params, callback ) {
    this.request( 'POST', resource, params, callback );
  };

  /*
   * Same as `OAuthClient.request()`, but with 'PUT'
   * as preset `method`
   *
   * @api public
   * @param {String} resource
   * @param {Object} params
   * @param {Function} callback
   */
  $.put = function( resource, params, callback ) {
    this.request( 'PUT', resource, params, callback );
  };

  /*
   * Same as `OAuthClient.request()`, but with 'DELETE'
   * as preset `method`
   *
   * @api public
   * @param {String} resource
   * @param {Object} params
   * @param {Function} callback
   */
  $.delete = function( resource, params, callback ) {
    this.request( 'DELETE', resource, params, callback );
  };

  /*
   * Prepares given `params` (Adds standard OAuth parameters,
   * sorts them and finally adds the signature).
   *
   * @api public
   * @param {String} method
   * @param {String|Object} resource
   * @param {Object} params
   */
  $.prepareParams = function( method, resource, params ) {

    params = OAuth.util.extend({
      'oauth_timestamp':        this.getTime(),
      'oauth_version':          this.version,
      'oauth_nonce':            this.getNonce(),
      'oauth_signature_method': this.options.signatureMethod,
      'oauth_consumer_key':     this.consumer.key
    }, params );

    if( this.token.key )
      params['oauth_token'] = this.token.key;

    // Sort parameters alphabetically
    var keys = Object.keys( params ).sort();
    var i, key, swap = params, params = {};

    for( i in keys ) {
      key = keys[i];
      params[ key ] = swap[ key ];
    }

    params['oauth_signature'] = this.sign( method, resource, params );

    return params;

  };

  /*
   * Creates the OAuth signature from
   * `method`, `resource` and `params`.
   *
   * @api public
   * @param {String} method
   * @param {String|Object} resource
   * @param {Object} params
   */
  $.sign = function( method, resource, params ) {

    resource = url.parse( resource );
    resource = resource.protocol + '//'
             + resource.host
             + resource.path;
    resource = OAuth.util.encodeComponent( resource )

    // Remove `oauth_signature` if present
    // ref: spec: 9.1.1 ("the oauth_signature parameter MUST be excluded.")
    if( params.oauth_signature )
      delete params.oauth_signature;

    params = query.stringify( params );
    params = OAuth.util.encodeComponent( params );

    var base = [ method, resource, params ].join( '&' );
    var key  = [ this.consumer.secret, this.token.secret ].join( '&' );
    var hash = '';

    switch( this.options.signatureMethod ) {
      case 'HMAC-SHA1':
        hash = crypto.createHmac( 'sha1', key ).update( base ).digest( 'base64' );
        break;
      case 'PLAINTEXT':
        hash = OAuth.util.encodeComponent( key )
        break;
      default:
        throw new Error( 'Signature method not implemented.' );
        break;
    }

    return hash;

  };

  return OAuthClient;

})();

module.exports = OAuthClient;
<|endoftext|>


<commit_before>// manipulate.js

__$__.Manipulate = {
    /**
     * @param edgeData
     * @param callback
     */
    addEdge: function(edgeData, callback) {
        // TODO: should search simultaneously for efficiency
        // search candidates for reference of the node on the from side
        let from = __$__.Manipulate.searchNode(edgeData.from);
        // search candidates for reference of the node on the to side
        let to = __$__.Manipulate.searchNode(edgeData.to);

        let candidates = __$__.Manipulate.candidates(from, to);
        callback();
        // TODO: move the cursor position to a safe position.
        __$__.Manipulate.startAutoCompletion(candidates);
    },

    /**
     * @param edgeData
     * @param callback
     */
    editEdge: function(edgeData, callback) {
        if (__$__.edges._data[edgeData.id].from !== edgeData.from) {
            // In the case that the user edits the from-side of the edge
            callback();
        } else {
            // In the case that the user edits the to-side of the edge

            // TODO: should search simultaneously for efficiency
            // search candidates for reference of the node on the from side
            let from = __$__.Manipulate.searchNode(edgeData.from);
            // search candidates for reference of the node on the to side
            let to = __$__.Manipulate.searchNode(edgeData.to);

            let candidates = __$__.Manipulate.candidates(from, to, edgeData.id);
            callback();
            // TODO: move the cursor position to a safe position.
            __$__.Manipulate.startAutoCompletion(candidates);
        }
    },

    /**
     * @param endNodeId{String}
     *
     * @return Object
     */
    searchNode: function(/*startNodeIds, */endNodeId) {
        // this variable is a table that represents which edges the node is pointed to.
        // {nodeId: [edgeId1, edgeId2, ...]}
        let node2Edges = new Object();
        Object.keys(__$__.edges._data).forEach(edgeId => {
            let edge = __$__.edges._data[edgeId];
            if (node2Edges[edge.to]) {
                node2Edges[edge.to].push(edge.id);
            } else {
                node2Edges[edge.to] = [edge.id];
            }
        });

        // this table is a memo for dynamic programming.
        let table = new Object();
        table[endNodeId] = [{label: []}];

        let rec = function(edgeId, acc) {
            if (acc.passedEdgeIds[edgeId]) {
                return;
            }
            let edge = __$__.edges._data[edgeId];

            acc.label.unshift(edge.label);
            acc.passedEdgeIds[edgeId] = true;

            // register
            if (!table[edge.from]) {
                table[edge.from] = [];
            }
            table[edge.from].push({
                label: Object.assign([], acc.label)
            });

            if (node2Edges[edge.from])
                node2Edges[edge.from].forEach(eId => {
                    rec(eId, acc)
                });

            acc.label.shift();
            delete acc.passedEdgeIds[edgeId];
        };

        if (node2Edges[endNodeId])
            node2Edges[endNodeId].forEach(edgeId => {
                rec(edgeId, {label: [], passedEdgeIds: {}});
            });
        return table;
    },

    /**
     * @param from
     * @param to
     * @param prop
     * @returns [{}]
     */
    candidates(from, to, prop) {
        let candidates = [];
        Object.keys(from).forEach(nodeId1 => {
            if (nodeId1.slice(0, 11) === '__Variable-') {
                Object.keys(to).forEach(nodeId2 => {
                    if (nodeId2.slice(0, 11) === '__Variable-') {
                        from[nodeId1].forEach(labels_l => {
                            if (!labels_l.length && nodeId1 === '__Variable-this')
                                return;
                            let exp_l = labels_l.label.concat([((prop) ? __$__.edges._data[prop].label : '${0:prop}')]).join('.');
                            let score_l = labels_l.label.length;
                            if (labels_l.label[0] === 'this') score_l += 0.2;

                            to[nodeId2].forEach(labels_r => {
                                let exp_r = labels_r.label.join('.');
                                let score_r = labels_r.label.length;
                                if (labels_r.label[0] === 'this') score_r += 0.2;

                                let score = score_l + score_r;
                                candidates.push({
                                    // score_l: score_l,
                                    // score_r: score_r,
                                    prop: prop,
                                    score: -score,
                                    stmt: exp_l + ' = ' + exp_r + ';',
                                    exp_l: exp_l,
                                    exp_r: exp_r
                                });
                            });
                        });
                    }
                });
            }
        });
        return candidates;
    },

    /**
     * @param candidates
     */
    startAutoCompletion(candidates) {
        if (Object.keys(candidates).length === 0) {
            let staticWordCompleter = {
                getCompletions: function(editor, session, pos, prefix, callback) {
                    callback(null, [{
                        caption: 'impossible',
                        value: '',
                        meta: 'impossible'
                    }]);
                }
            };
            __$__.langTools.setCompleters([staticWordCompleter]);
            __$__.startAutocomplete(__$__.editor);
        } else {
            let staticWordCompleter = {
                getCompletions: function (editor, session, pos, prefix, callback) {
                    let cs = candidates;
                    callback(null, cs.map(function (candidate) {
                        if (candidate.prop)
                            return {
                                caption: candidate.stmt,
                                value: candidate.stmt,
                                score: candidate.score
                            };
                        else
                            return {
                                caption: candidate.stmt.replace(/\$\{[\s\S]*\}/, "[prop]"),
                                score: candidate.score,
                                snippet: candidate.stmt
                            };
                    }));
                }
            };
            __$__.langTools.setCompleters([staticWordCompleter]);
            __$__.startAutocomplete(__$__.editor);
        }
    }
};<commit_msg>bug fix<commit_after>// manipulate.js

__$__.Manipulate = {
    /**
     * @param edgeData
     * @param callback
     */
    addEdge: function(edgeData, callback) {
        // TODO: should search simultaneously for efficiency
        // search candidates for reference of the node on the from side
        let from = __$__.Manipulate.searchNode(edgeData.from);
        // search candidates for reference of the node on the to side
        let to = __$__.Manipulate.searchNode(edgeData.to);

        let candidates = __$__.Manipulate.candidates(from, to);
        callback();
        // TODO: move the cursor position to a safe position.
        __$__.Manipulate.startAutoCompletion(candidates);
    },

    /**
     * @param edgeData
     * @param callback
     */
    editEdge: function(edgeData, callback) {
        if (__$__.edges._data[edgeData.id].from !== edgeData.from) {
            // In the case that the user edits the from-side of the edge
            callback();
        } else {
            // In the case that the user edits the to-side of the edge

            // TODO: should search simultaneously for efficiency
            // search candidates for reference of the node on the from side
            let from = __$__.Manipulate.searchNode(edgeData.from);
            // search candidates for reference of the node on the to side
            let to = __$__.Manipulate.searchNode(edgeData.to);

            let candidates = __$__.Manipulate.candidates(from, to, edgeData.id);
            callback();
            // TODO: move the cursor position to a safe position.
            __$__.Manipulate.startAutoCompletion(candidates);
        }
    },

    /**
     * @param endNodeId{String}
     *
     * @return Object
     */
    searchNode: function(/*startNodeIds, */endNodeId) {
        // this variable is a table that represents which edges the node is pointed to.
        // {nodeId: [edgeId1, edgeId2, ...]}
        let node2Edges = new Object();
        Object.keys(__$__.edges._data).forEach(edgeId => {
            let edge = __$__.edges._data[edgeId];
            if (node2Edges[edge.to]) {
                node2Edges[edge.to].push(edge.id);
            } else {
                node2Edges[edge.to] = [edge.id];
            }
        });

        // this table is a memo for dynamic programming.
        let table = new Object();
        table[endNodeId] = [{label: []}];

        let rec = function(edgeId, acc) {
            if (acc.passedEdgeIds[edgeId]) {
                return;
            }
            let edge = __$__.edges._data[edgeId];

            acc.label.unshift(edge.label);
            acc.passedEdgeIds[edgeId] = true;

            // register
            if (!table[edge.from]) {
                table[edge.from] = [];
            }
            table[edge.from].push({
                label: Object.assign([], acc.label)
            });

            if (node2Edges[edge.from])
                node2Edges[edge.from].forEach(eId => {
                    rec(eId, acc)
                });

            acc.label.shift();
            delete acc.passedEdgeIds[edgeId];
        };

        if (node2Edges[endNodeId])
            node2Edges[endNodeId].forEach(edgeId => {
                rec(edgeId, {label: [], passedEdgeIds: {}});
            });
        return table;
    },

    /**
     * @param from
     * @param to
     * @param prop
     * @returns [{}]
     */
    candidates(from, to, prop) {
        let candidates = [];
        Object.keys(from).forEach(nodeId1 => {
            if (nodeId1.slice(0, 11) === '__Variable-') {
                Object.keys(to).forEach(nodeId2 => {
                    if (nodeId2.slice(0, 11) === '__Variable-') {
                        from[nodeId1].forEach(labels_l => {
                            if (!labels_l.label.length && nodeId1 === '__Variable-this')
                                return;
                            let exp_l = labels_l.label.concat([((prop) ? __$__.edges._data[prop].label : '${0:prop}')]).join('.');
                            let score_l = labels_l.label.length;
                            if (labels_l.label[0] === 'this') score_l += 0.2;

                            to[nodeId2].forEach(labels_r => {
                                let exp_r = labels_r.label.join('.');
                                let score_r = labels_r.label.length;
                                if (labels_r.label[0] === 'this') score_r += 0.2;

                                let score = score_l + score_r;
                                candidates.push({
                                    // score_l: score_l,
                                    // score_r: score_r,
                                    prop: prop,
                                    score: -score,
                                    stmt: exp_l + ' = ' + exp_r + ';',
                                    exp_l: exp_l,
                                    exp_r: exp_r
                                });
                            });
                        });
                    }
                });
            }
        });
        return candidates;
    },

    /**
     * @param candidates
     */
    startAutoCompletion(candidates) {
        if (Object.keys(candidates).length === 0) {
            let staticWordCompleter = {
                getCompletions: function(editor, session, pos, prefix, callback) {
                    callback(null, [{
                        caption: 'impossible',
                        value: '',
                        meta: 'impossible'
                    }]);
                }
            };
            __$__.langTools.setCompleters([staticWordCompleter]);
            __$__.startAutocomplete(__$__.editor);
        } else {
            let staticWordCompleter = {
                getCompletions: function (editor, session, pos, prefix, callback) {
                    let cs = candidates;
                    callback(null, cs.map(function (candidate) {
                        if (candidate.prop)
                            return {
                                caption: candidate.stmt,
                                value: candidate.stmt,
                                score: candidate.score
                            };
                        else
                            return {
                                caption: candidate.stmt.replace(/\$\{[\s\S]*\}/, "[prop]"),
                                score: candidate.score,
                                snippet: candidate.stmt
                            };
                    }));
                }
            };
            __$__.langTools.setCompleters([staticWordCompleter]);
            __$__.startAutocomplete(__$__.editor);
        }
    }
};<|endoftext|>


<commit_before>var util = require('./util')
	, nativeUtil = require('./nativeUtil')
	, fsRoot = "cdvfile://localhost/persistent/"

module.exports = exports = {}

exports.readFile = function (path, options, cb) {
	nativeUtil.whenFsReady(function () {
		if (!cb) {
  		cb = options
  		options = {}
  	}
  	util.defaults(options)
  	;(options.url !== false && util.url(path))
			? util.readAjax(path, options, cb)
			: readFile(path, options, cb)
	})
}

function readFile (path, options, cb) {
  window.fs.root.getFile(path
  	, {
  		create: false
  	}
  	, function (fileEntry) {
    fileEntry.file(function (file) {
      var reader = new FileReader()
      reader.onloadend = function (err) {
      	if (err.error) {
      		cb(err)
      	} else {
        	cb(null, this.result)
      	}
      }
      reader.readAsText(file)
    }, function (err) {
    	err.failPoint = 'fileEntry.file'
    	cb(err)
    })
  }, function (err) {
  	err.failPoint = 'getFile'
  	cb(err)
  })
}

exports.writeFile = function (path, data, options, cb) {
	try {
		nativeUtil.whenFsReady(function () {
			if (!cb) {
	  		cb = options
	  		options = {}
	  	}
	  	util.defaults(options)
	  	;(options.url !== false && util.url(data))
				? writeHttp(path, data, options, cb)
				: writeFile(path, data, options, cb)
		})
	} catch (e) {
		alert(e)
	}
}

function writeFile (path, data, options, cb) {
	window.fs.root.getFile(path
		, {
			create: true
		}
		, function (fileEntry) {
	    fileEntry.createWriter(function (fileWriter) {
	      fileWriter.onwriteend = function (err) {
	      	if (err.error) {
	        	cb(err)
	        } else {
	        	cb(null)
	        }
	      }
	      fileWriter.onerror = function(err) {
	      	err.failPoint = 'onerror'
	        cb(err)
	      }
	    	fileWriter.write(data)
	    }, function (err) {
	    	err.failPoint = 'createWriter'
	    	cb(err)
	    })
  }, function (err) {
  	err.failPoint = 'getFile'
  	cb(err)
  })
}

function writeHttp (path, url, options, cb) {
	var fileTransfer = new FileTransfer()
		, uri = encodeURI(url)
		, error
	fileTransfer.download(
    uri
    , fsRoot + path
    , function (entry) {
			entry.file(function (file) {
				if (file.size !== 0) {
					cb(null, file)
				} else {
					error = new Error("Downloaded file empty")
					error.file = file
					cb(error)
				}
			}, function (err) {
				err.failPoint = 'fileEntry.file'
				cb(err)
			})
    }
    , function (err) {
			cb(err)
    }
    , false
	);
}

exports.exists = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(path
			, { create : false }
			, function () {
				cb(true)
			}
			, function () {
				cb(false)
			})
	})
}

exports.mkdirp = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		var folderParts = path.split('/')

		var createDir = function(rootDir, folders) {
			// Throw out './' or '/' and move on. Prevents: '/foo/.//bar'.
			if (folders[0] == '.' || folders[0] == '') {
				folders = folders.slice(1)
			}
			rootDir.getDirectory(folders[0]
				, { create: true }
				, function (dirEntry) {
					if (dirEntry.isDirectory) {
						if (folders.length && folders.length > 1) {
							createDir(dirEntry, folders.slice(1))
						} else {
							cb(null)
						}
					} else {
						var error = new Error(path + ' is not a directory')
						cb(error)
					}
				}
				, function (err) {
					if (err.code === FileError.INVALID_MODIFICATION_ERR) {
						cb(null)
					} else {
						cb(err)
					}
				})
		}

		createDir(window.fs.root, folderParts)
	})
}

exports.remove = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getDirectory(
	    path
	    , { create : true, exclusive : false }
	    , function (entry) {
	      entry.removeRecursively(
	      	function (status) {
	      		if (status === "OK") {
	      			cb(null)
	      		} else {
	      			cb(status)
	      		}
	      	}
	      	, function (event) {
	      			event.failPoint = "entre.removeRecursively"
	      			cb(event)
	      		})
	    }
	    , function (event) {
		    	event.failPoint = "fs.root.getDirectory"
		    	cb(event)
		    });
	})
}

exports.rename = function (oldPath, newPath, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(oldPath
			, {}
			, function (entry) {
				move(entry
					, window.fs.root
					, newPath
					, cb)

			}
			, function (err) {
				if (err.code === 11) { // TYPE_MISMATCH_ERR
					window.fs.root.getDirectory(oldPath
						, {}
						, function (entry) {
							move(entry
								, window.fs.root
								, newPath
								, cb)
						}
						, function (err) {
							cb(err)
						})
				} else {
					cb(err)
				}
			})
	})
}

exports.copy = function (oldPath, newPath, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(oldPath
			, {}
			, function (entry) {
				var lastSlashIndex = newPath.lastIndexOf('/')
					, newName
				if (lastSlashIndex !== -1) {
					newName = newPath.substring(lastSlashIndex + 1)
					window.fs.root.getDirectory(newPath.substring(0, lastSlashIndex)
						, {}
						, function (dirEntry) {
							finish(dirEntry)
						}
						, function (err) {
							cb(err)
						})
				} else {
					newName = newPath
					finish(window.fs.root)
				}
				function finish (parent) {
					entry.copyTo(parent
						, newName
						, function (entry) {
							cb(null)
						}
						, function (err) {
							cb(err)
						})
				}
			}
			, function (err) {
				cb(err)
			})
	})
}

function move (entry, root, newPath, cb) {
	entry.moveTo(root
		, newPath
		, function () {
			cb(null)
		}
		, function (err) {
			cb(err)
		})
}

exports.getURL = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(path
			, {}
			, function (entry) {
				cb(null, entry.toURL())
				// cb(null, entry.toInternalURL())
				// cb(null, entry.fullPath)
			}
			, function (err) {
				cb(err)
			})
	})
}

exports.getRoot = function (cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile("rootReference.txt"
			, { create: true }
			, function (entry) {
				var url = entry.toURL()
					, root = url.slice(0, url.lastIndexOf('/') + 1)
				cb(null, root)
				// cb(null, entry.toInternalURL())
				// cb(null, entry.fullPath)
			}
			, function (err) {
				cb(err)
			})
	})
}

exports.readdir = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getDirectory(path
			, {}
			, function (dirEntry) {
				var reader = dirEntry.createReader()
				reader.readEntries(function (entries) {
					var names = []
						, l = entries.length
						, i
						, name
					for (i = 0; i < l; i += 1) {
						var name = entries[i].fullPath
						if (name.lastIndexOf('/') === name.length - 1) {
							name = name.slice(0, -1)
						}
						names.push(name)
					}
					cb(null, names)
				}
				, function (err) {
					cb(err)
				})
			}
			, function (err) {
				cb(err)
			})
	})
}<commit_msg>Removed comments and remove leading slash in file names returned by readdir<commit_after>var util = require('./util')
	, nativeUtil = require('./nativeUtil')
	, fsRoot = "cdvfile://localhost/persistent/"

module.exports = exports = {}

exports.readFile = function (path, options, cb) {
	nativeUtil.whenFsReady(function () {
		if (!cb) {
  		cb = options
  		options = {}
  	}
  	util.defaults(options)
  	;(options.url !== false && util.url(path))
			? util.readAjax(path, options, cb)
			: readFile(path, options, cb)
	})
}

function readFile (path, options, cb) {
  window.fs.root.getFile(path
  	, {
  		create: false
  	}
  	, function (fileEntry) {
    fileEntry.file(function (file) {
      var reader = new FileReader()
      reader.onloadend = function (err) {
      	if (err.error) {
      		cb(err)
      	} else {
        	cb(null, this.result)
      	}
      }
      reader.readAsText(file)
    }, function (err) {
    	err.failPoint = 'fileEntry.file'
    	cb(err)
    })
  }, function (err) {
  	err.failPoint = 'getFile'
  	cb(err)
  })
}

exports.writeFile = function (path, data, options, cb) {
	try {
		nativeUtil.whenFsReady(function () {
			if (!cb) {
	  		cb = options
	  		options = {}
	  	}
	  	util.defaults(options)
	  	;(options.url !== false && util.url(data))
				? writeHttp(path, data, options, cb)
				: writeFile(path, data, options, cb)
		})
	} catch (e) {
		alert(e)
	}
}

function writeFile (path, data, options, cb) {
	window.fs.root.getFile(path
		, {
			create: true
		}
		, function (fileEntry) {
	    fileEntry.createWriter(function (fileWriter) {
	      fileWriter.onwriteend = function (err) {
	      	if (err.error) {
	        	cb(err)
	        } else {
	        	cb(null)
	        }
	      }
	      fileWriter.onerror = function(err) {
	      	err.failPoint = 'onerror'
	        cb(err)
	      }
	    	fileWriter.write(data)
	    }, function (err) {
	    	err.failPoint = 'createWriter'
	    	cb(err)
	    })
  }, function (err) {
  	err.failPoint = 'getFile'
  	cb(err)
  })
}

function writeHttp (path, url, options, cb) {
	var fileTransfer = new FileTransfer()
		, uri = encodeURI(url)
		, error
	fileTransfer.download(
    uri
    , fsRoot + path
    , function (entry) {
			entry.file(function (file) {
				if (file.size !== 0) {
					cb(null, file)
				} else {
					error = new Error("Downloaded file empty")
					error.file = file
					cb(error)
				}
			}, function (err) {
				err.failPoint = 'fileEntry.file'
				cb(err)
			})
    }
    , function (err) {
			cb(err)
    }
    , false
	);
}

exports.exists = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(path
			, { create : false }
			, function () {
				cb(true)
			}
			, function () {
				cb(false)
			})
	})
}

exports.mkdirp = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		var folderParts = path.split('/')

		var createDir = function(rootDir, folders) {
			// Throw out './' or '/' and move on. Prevents: '/foo/.//bar'.
			if (folders[0] == '.' || folders[0] == '') {
				folders = folders.slice(1)
			}
			rootDir.getDirectory(folders[0]
				, { create: true }
				, function (dirEntry) {
					if (dirEntry.isDirectory) {
						if (folders.length && folders.length > 1) {
							createDir(dirEntry, folders.slice(1))
						} else {
							cb(null)
						}
					} else {
						var error = new Error(path + ' is not a directory')
						cb(error)
					}
				}
				, function (err) {
					if (err.code === FileError.INVALID_MODIFICATION_ERR) {
						cb(null)
					} else {
						cb(err)
					}
				})
		}

		createDir(window.fs.root, folderParts)
	})
}

exports.remove = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getDirectory(
	    path
	    , { create : true, exclusive : false }
	    , function (entry) {
	      entry.removeRecursively(
	      	function (status) {
	      		if (status === "OK") {
	      			cb(null)
	      		} else {
	      			cb(status)
	      		}
	      	}
	      	, function (event) {
	      			event.failPoint = "entre.removeRecursively"
	      			cb(event)
	      		})
	    }
	    , function (event) {
		    	event.failPoint = "fs.root.getDirectory"
		    	cb(event)
		    });
	})
}

exports.rename = function (oldPath, newPath, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(oldPath
			, {}
			, function (entry) {
				move(entry
					, window.fs.root
					, newPath
					, cb)

			}
			, function (err) {
				if (err.code === 11) { // TYPE_MISMATCH_ERR
					window.fs.root.getDirectory(oldPath
						, {}
						, function (entry) {
							move(entry
								, window.fs.root
								, newPath
								, cb)
						}
						, function (err) {
							cb(err)
						})
				} else {
					cb(err)
				}
			})
	})
}

exports.copy = function (oldPath, newPath, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(oldPath
			, {}
			, function (entry) {
				var lastSlashIndex = newPath.lastIndexOf('/')
					, newName
				if (lastSlashIndex !== -1) {
					newName = newPath.substring(lastSlashIndex + 1)
					window.fs.root.getDirectory(newPath.substring(0, lastSlashIndex)
						, {}
						, function (dirEntry) {
							finish(dirEntry)
						}
						, function (err) {
							cb(err)
						})
				} else {
					newName = newPath
					finish(window.fs.root)
				}
				function finish (parent) {
					entry.copyTo(parent
						, newName
						, function (entry) {
							cb(null)
						}
						, function (err) {
							cb(err)
						})
				}
			}
			, function (err) {
				cb(err)
			})
	})
}

function move (entry, root, newPath, cb) {
	entry.moveTo(root
		, newPath
		, function () {
			cb(null)
		}
		, function (err) {
			cb(err)
		})
}

exports.getURL = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile(path
			, {}
			, function (entry) {
				cb(null, entry.toURL())
			}
			, function (err) {
				cb(err)
			})
	})
}

exports.getRoot = function (cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getFile("rootReference.txt"
			, { create: true }
			, function (entry) {
				var url = entry.toURL()
					, root = url.slice(0, url.lastIndexOf('/') + 1)
				cb(null, root)
			}
			, function (err) {
				cb(err)
			})
	})
}

exports.readdir = function (path, cb) {
	nativeUtil.whenFsReady(function () {
		window.fs.root.getDirectory(path
			, {}
			, function (dirEntry) {
				var reader = dirEntry.createReader()
				reader.readEntries(function (entries) {
					var names = []
						, l = entries.length
						, i
						, name
					for (i = 0; i < l; i += 1) {
						var name = entries[i].fullPath
						if (name.lastIndexOf('/') === name.length - 1) {
							name = name.slice(0, -1)
						}
						if (name[0] === '/') {
							name = name.slice(1)
						}
						names.push(name)
					}
					cb(null, names)
				}
				, function (err) {
					cb(err)
				})
			}
			, function (err) {
				cb(err)
			})
	})
}<|endoftext|>