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

 Contributors:
 Jeff Bryner jbryner@mozilla.com
 Anthony Verez averez@mozilla.com
 Sanchit Kapoor sanchitlucknow@gmail.com
 Yash Mehrotra yashmehrotra95@gmail.com
 Avijit Gupta 526avijit@gmail.com
 */

if (Meteor.isClient) {

  var MESHPROPERTIES = {
    count: 4,
    position: [
      {x: 0, y: 0, z: 0},
      {x: -800, y: -20, z: 0},
      {x: -800, y: -20, z: -800},
      {x: 0 , y: -20, z: -800}
    ],
    rotationY: [
      0,
      0,
      Math.PI/2,
      Math.PI/2
    ]
  };

  // TODO: WHY_NO_UNDERSCORE @avijit
  var RANKCOORDINATES = [
    {x: -286, z: -115},
    {x: -15, z: 11},
    {x: -234, z: 232},
    {x: -69, z: -142},
    {x: 124, z: 293},
    {x: 153, z: -869},
    {x: 124, z: -1122},
    {x: -261, z: -1031},
    {x: 87, z: -583},
    {x: -288, z: -625},
    {x: 265, z: -501},
    {x: -850, z: -134},
    {x: -1094, z: -74},
    {x: -576, z: -190},
    {x: -605, z: 98},
    {x: -964, z: 293},
    {x: -1084, z: -554},
    {x: -899, z: -628},
    {x: -589, z: -716},
    {x: -992, z: -962},
    {x: -754, z: -1087}
  ];
  var ATTACKANIMATIONS = {
    'broxss': Examples.smoke,
    'brosqli': Examples.smoke,
    'brotunnel': Examples.smoke
  };
  var WIDTH  = window.innerWidth;
  var HEIGHT = window.innerHeight;
  var SPEED = 0.01;
  var OPENNAV = 'cbp-spmenu-open';

  var geometry = null;
  var scene = null;
  var camera = null;
  var renderer = null;
  var material = null;
  var json = null;
  var geometry = null;
  var controls = null;
  var clock = null;
  var mesh = null;
  var spotlight = null;
  var loader = null;
  var projector = null;
  var sceneObjects = [];
  var attackedIds = 0;
  var cssRenderer = null;
  var intersectedObject = null;
  var engine = null;
  var enginesList = [];
  var world = {};
  var jsonData = {};

  function init() {
    Meteor.call('getVrJson', function(err, response) {
      jsonData = JSON.parse(response);
      initMeshes();
      setCamera();
      setLights();
      setRenderers();
      setStats();

      document.getElementById("container").appendChild(renderer.domElement);
      document.getElementById("container").appendChild(cssRenderer.domElement);
    });
  }

  function initVariables() {
    clock = new THREE.Clock();
    scene = new THREE.Scene();
    loader = new THREE.JSONLoader();
    camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10000);
    sceneControls = new THREE.TrackballControls(camera);
    spotLight = new THREE.SpotLight(0xffffff, 1);
    renderer = new THREE.WebGLRenderer({ antialias: true });
    projector = new THREE.Projector();
    cssRenderer = new THREE.CSS3DRenderer();
    controls = new THREE.OrbitControls(camera);
    stats = new Stats();
  }

  function restartEngine(parameters, x, z) {
    parameters.positionBase.x=x;
    parameters.positionBase.z=z;

    engine = new ParticleEngine();
    engine.setValues(parameters);
    engine.initialize(scene);

    enginesList.push(engine);
  }

  function setStats() {
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.bottom = '0px';
    stats.domElement.style.zIndex = 100;
  }

  function setCamera() {
    camera.position.set(-39.52908903855581, -4.352138336979161, 40.70626794923796);
    var lookAt = { x: -30.52908903855581, y: -4.352138336979161, z: 37.70626794923796 }
    camera.lookAt(lookAt);
  }

  function setRenderers() {
    renderer.setSize(WIDTH, HEIGHT);
    renderer.shadowMapEnabled = true;  // enable shadows

    cssRenderer.setSize(WIDTH, HEIGHT);
    cssRenderer.domElement.style.position = 'absolute';
    cssRenderer.domElement.style.top = 0;
  }

  function setLights() {
    spotLight.position.set( 100, 10000, 100 );
    scene.add(spotLight);
    spotLight.castShadow = true;
  }

  function initMeshes() {
    json = loader.parse(jsonData);
    geometry = json.geometry;
    material = new THREE.MeshPhongMaterial(json.materials);
    for (var i = 0; i < MESHPROPERTIES.count; i++) {
      mesh = new THREE.Mesh(geometry, material);
      mesh.scale.x = mesh.scale.y = mesh.scale.z = 50.75;
      mesh.translation = THREE.GeometryUtils.center(geometry);
      mesh.castShadow = true;
      mesh.position.copy(MESHPROPERTIES.position[i]);
      mesh.rotation.y = MESHPROPERTIES.rotationY[i];
      scene.add(mesh);
    }
  }

  function update() {
    controls.update();
    stats.update();
    enginesList.forEach(function(engine) {
      engine.update(0.01*0.5);
    });
  }

  function render() {
    requestAnimationFrame(render);
    update();
    renderer.render(scene, camera);
    cssRenderer.render(scene, camera);
  }

  function parsedb() {
    Meteor.subscribe("attackers-summary-yash", onReady = function() {

      attackers.find().forEach(function(element) {
        // TODO: Take care of timestamp
        element.events.forEach(function(evt) {
          var evtHost = evt.documentsource.details.host;
          var doc = evt.documentsource;
          doc.id = evt.documentid;
          if (evtHost == undefined) {
            return;
          }
          if (world[evtHost]) {
            world[evtHost].push(doc);
          } else {
            world[evtHost] = [doc];
            // TODO: Is the below line required
            world[evtHost].rank = attackedIds++;
            // world[evtHost].host = evtHost || 'hard-coded';
          }
        });
      });

      console.log(world);

      var attacks = Object.keys(world).sort(function(prev, current) {
        return world[current].length - world[prev].length;
      });
      console.log('attacks', attacks);
      attacks.forEach(function(host, index) {
        var attackRank = world[host].rank;
        // Create enclosing transparent sphere
        var sphereGeometry = new THREE.SphereGeometry(70);
        var sphereMaterial = new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 });
        // var sphereMaterial = new THREE.MeshBasicMaterial();
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = RANKCOORDINATES[attackRank].x;
        sphere.position.z = RANKCOORDINATES[attackRank].z;
        sphere.name = "EnclosingSphere" + attackRank;
        sphere.rank = attackRank;
        sphere.host = host || 'hard-coded';
        sphere.attacks = [];

        world[host].forEach(function(attack) {
          if (typeof attack === "object") {
            attackType = attack.category;
            console.log("attacks - ", attackType);
            sphere.attacks.push(attack);
            if (Object.keys(ATTACKANIMATIONS).indexOf(attackType) > -1) {
              mappedAttack = ATTACKANIMATIONS[attackType];
              restartEngine(mappedAttack, RANKCOORDINATES[index].x, RANKCOORDINATES[index].z);
              console.log(RANKCOORDINATES[index].x, RANKCOORDINATES[index].z);
            }
          }
        });

        sceneObjects.push(sphere);
        scene.add(sphere);
      });

    });
  }

  Template.vr.created = function () {
    initVariables();
  };

  Template.vr.rendered = function () {
    init();
    render();
    parsedb();
  };//end template.attackers.rendered

  Template.vr.helpers({
    hostAttacks: function() {
      var hostAttacks = Session.get('hostAttacks');
      if (hostAttacks) {
        hostAttacks.attacks.forEach(function(attack, index) {
          attack.index = index;
        });
        return hostAttacks;
      }
    },
    attackDetails: function() {
      return Session.get('attackDetails');
    },
    displayIndex: function(index) {
      return index + 1
    }
  });

  Template.vr.events({

    "click #container": function(e) {
      var mouse = {
        x: (e.clientX / WIDTH)*2 - 1,
        y: (e.clientY / HEIGHT)*2 - 1
      };
      var mouseVector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
      projector.unprojectVector(mouseVector, camera);
      var raycaster = new THREE.Raycaster(camera.position, mouseVector.sub( camera.position).normalize() );
      var intersects = raycaster.intersectObjects(sceneObjects, true);
      var sideNav = $('#attack-sidenav');
      console.log(intersects);

      if (intersects.length) {
        intersects.forEach(function(intersect) {
          // console.log(intersect);
          var attackRank = intersect.object.rank;
          var attackRegion = intersect.object.host;
          var attacks = intersect.object.attacks;
          if (typeof attackRank !== "undefined") {
            var sessionAttackObj = {
              host: attackRegion,
              rank: attackRank,
              attacks: attacks
            };
            Session.set('hostAttacks', sessionAttackObj);
            // Open the nav if not already opened
            if (!sideNav.hasClass(OPENNAV)) {
              sideNav.addClass(OPENNAV);
            }
          }
        });
      }
      else if(sideNav.hasClass(OPENNAV)) {
        sideNav.removeClass(OPENNAV);
      }
    },

    "change .cbox": function(event) {
      var isChecked = $('.cbox').is(':checked');
      if (isChecked) {
        // attackers.update()
      }
      else {

      }
    },

    "click .attacks-list-item": function(event) {
      var attackIndex = event.target.getAttribute('data-index');
      var hostName = document.getElementById('attacks-host').innerText;
      var attackDetails = world[hostName][attackIndex];
      console.log(attackDetails);
      Session.set('attackDetails', attackDetails);
      $('#specific-attack-details').slideToggle();
      $('#attacks-list').slideToggle();
    },

    "click .back-button": function() {
      $('#specific-attack-details').slideToggle();
      $('#attacks-list').slideToggle();
    },

    "click .blockip": function(e,t){
      Session.set('blockIPipaddress',($(e.target).attr('data-ipaddress')));
      //disable and hook to re-enable the scene controls so they don't grab the mouse and use it
      sceneControls.enabled = false;
      controls.enabled = false;
      console.log("BLCOK OPPP");
      $('#modalBlockIPWindow').on('hidden', function () {
          sceneControls.enabled=true;
          controls.enabled = true;
      });
      $('#modalBlockIPWindow').modal();
    },

  });

  Template.vr.destroyed = function () {
    container.removeChild(renderer.domElement);
    scene = null;
    camera = null;
    renderer = null;
    WIDTH  = window.innerWidth;
    HEIGHT = window.innerHeight;
    SPEED = 0.01;
  };//end template.attackers.destroyed

}
<commit_msg>get attack id on check/unncheck<commit_after>/*
 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at http://mozilla.org/MPL/2.0/.
 Copyright (c) 2014 Mozilla Corporation

 Contributors:
 Jeff Bryner jbryner@mozilla.com
 Anthony Verez averez@mozilla.com
 Sanchit Kapoor sanchitlucknow@gmail.com
 Yash Mehrotra yashmehrotra95@gmail.com
 Avijit Gupta 526avijit@gmail.com
 */

if (Meteor.isClient) {

  var MESHPROPERTIES = {
    count: 4,
    position: [
      {x: 0, y: 0, z: 0},
      {x: -800, y: -20, z: 0},
      {x: -800, y: -20, z: -800},
      {x: 0 , y: -20, z: -800}
    ],
    rotationY: [
      0,
      0,
      Math.PI/2,
      Math.PI/2
    ]
  };

  // TODO: WHY_NO_UNDERSCORE @avijit
  var RANKCOORDINATES = [
    {x: -286, z: -115},
    {x: -15, z: 11},
    {x: -234, z: 232},
    {x: -69, z: -142},
    {x: 124, z: 293},
    {x: 153, z: -869},
    {x: 124, z: -1122},
    {x: -261, z: -1031},
    {x: 87, z: -583},
    {x: -288, z: -625},
    {x: 265, z: -501},
    {x: -850, z: -134},
    {x: -1094, z: -74},
    {x: -576, z: -190},
    {x: -605, z: 98},
    {x: -964, z: 293},
    {x: -1084, z: -554},
    {x: -899, z: -628},
    {x: -589, z: -716},
    {x: -992, z: -962},
    {x: -754, z: -1087}
  ];
  var ATTACKANIMATIONS = {
    'broxss': Examples.smoke,
    'brosqli': Examples.smoke,
    'brotunnel': Examples.smoke
  };
  var WIDTH  = window.innerWidth;
  var HEIGHT = window.innerHeight;
  var SPEED = 0.01;
  var OPENNAV = 'cbp-spmenu-open';

  var geometry = null;
  var scene = null;
  var camera = null;
  var renderer = null;
  var material = null;
  var json = null;
  var geometry = null;
  var controls = null;
  var clock = null;
  var mesh = null;
  var spotlight = null;
  var loader = null;
  var projector = null;
  var sceneObjects = [];
  var attackedIds = 0;
  var cssRenderer = null;
  var intersectedObject = null;
  var engine = null;
  var enginesList = [];
  var world = {};
  var jsonData = {};

  function init() {
    Meteor.call('getVrJson', function(err, response) {
      jsonData = JSON.parse(response);
      initMeshes();
      setCamera();
      setLights();
      setRenderers();
      setStats();

      document.getElementById("container").appendChild(renderer.domElement);
      document.getElementById("container").appendChild(cssRenderer.domElement);
    });
  }

  function initVariables() {
    clock = new THREE.Clock();
    scene = new THREE.Scene();
    loader = new THREE.JSONLoader();
    camera = new THREE.PerspectiveCamera(70, WIDTH / HEIGHT, 1, 10000);
    sceneControls = new THREE.TrackballControls(camera);
    spotLight = new THREE.SpotLight(0xffffff, 1);
    renderer = new THREE.WebGLRenderer({ antialias: true });
    projector = new THREE.Projector();
    cssRenderer = new THREE.CSS3DRenderer();
    controls = new THREE.OrbitControls(camera);
    stats = new Stats();
  }

  function restartEngine(parameters, x, z) {
    parameters.positionBase.x=x;
    parameters.positionBase.z=z;

    engine = new ParticleEngine();
    engine.setValues(parameters);
    engine.initialize(scene);

    enginesList.push(engine);
  }

  function setStats() {
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.bottom = '0px';
    stats.domElement.style.zIndex = 100;
  }

  function setCamera() {
    camera.position.set(-39.52908903855581, -4.352138336979161, 40.70626794923796);
    var lookAt = { x: -30.52908903855581, y: -4.352138336979161, z: 37.70626794923796 }
    camera.lookAt(lookAt);
  }

  function setRenderers() {
    renderer.setSize(WIDTH, HEIGHT);
    renderer.shadowMapEnabled = true;  // enable shadows

    cssRenderer.setSize(WIDTH, HEIGHT);
    cssRenderer.domElement.style.position = 'absolute';
    cssRenderer.domElement.style.top = 0;
  }

  function setLights() {
    spotLight.position.set( 100, 10000, 100 );
    scene.add(spotLight);
    spotLight.castShadow = true;
  }

  function initMeshes() {
    json = loader.parse(jsonData);
    geometry = json.geometry;
    material = new THREE.MeshPhongMaterial(json.materials);
    for (var i = 0; i < MESHPROPERTIES.count; i++) {
      mesh = new THREE.Mesh(geometry, material);
      mesh.scale.x = mesh.scale.y = mesh.scale.z = 50.75;
      mesh.translation = THREE.GeometryUtils.center(geometry);
      mesh.castShadow = true;
      mesh.position.copy(MESHPROPERTIES.position[i]);
      mesh.rotation.y = MESHPROPERTIES.rotationY[i];
      scene.add(mesh);
    }
  }

  function update() {
    controls.update();
    stats.update();
    enginesList.forEach(function(engine) {
      engine.update(0.01*0.5);
    });
  }

  function render() {
    requestAnimationFrame(render);
    update();
    renderer.render(scene, camera);
    cssRenderer.render(scene, camera);
  }

  function parsedb() {
    Meteor.subscribe("attackers-summary-yash", onReady = function() {

      attackers.find().forEach(function(element) {
        // TODO: Take care of timestamp
        element.events.forEach(function(evt) {
          var evtHost = evt.documentsource.details.host;
          var doc = evt.documentsource;
          doc.id = evt.documentid;
          if (evtHost == undefined) {
            return;
          }
          if (world[evtHost]) {
            world[evtHost].push(doc);
          } else {
            world[evtHost] = [doc];
            // TODO: Is the below line required
            world[evtHost].rank = attackedIds++;
            // world[evtHost].host = evtHost || 'hard-coded';
          }
        });
      });

      console.log(world);

      var attacks = Object.keys(world).sort(function(prev, current) {
        return world[current].length - world[prev].length;
      });
      console.log('attacks', attacks);
      attacks.forEach(function(host, index) {
        var attackRank = world[host].rank;
        // Create enclosing transparent sphere
        var sphereGeometry = new THREE.SphereGeometry(70);
        var sphereMaterial = new THREE.MeshBasicMaterial({ transparent: true, opacity: 0 });
        // var sphereMaterial = new THREE.MeshBasicMaterial();
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
        sphere.position.x = RANKCOORDINATES[attackRank].x;
        sphere.position.z = RANKCOORDINATES[attackRank].z;
        sphere.name = "EnclosingSphere" + attackRank;
        sphere.rank = attackRank;
        sphere.host = host || 'hard-coded';
        sphere.attacks = [];

        world[host].forEach(function(attack) {
          if (typeof attack === "object") {
            attackType = attack.category;
            console.log("attacks - ", attackType);
            sphere.attacks.push(attack);
            if (Object.keys(ATTACKANIMATIONS).indexOf(attackType) > -1) {
              mappedAttack = ATTACKANIMATIONS[attackType];
              restartEngine(mappedAttack, RANKCOORDINATES[index].x, RANKCOORDINATES[index].z);
              console.log(RANKCOORDINATES[index].x, RANKCOORDINATES[index].z);
            }
          }
        });

        sceneObjects.push(sphere);
        scene.add(sphere);
      });

    });
  }

  Template.vr.created = function () {
    initVariables();
  };

  Template.vr.rendered = function () {
    init();
    render();
    parsedb();
  };//end template.attackers.rendered

  Template.vr.helpers({
    hostAttacks: function() {
      var hostAttacks = Session.get('hostAttacks');
      if (hostAttacks) {
        hostAttacks.attacks.forEach(function(attack, index) {
          attack.index = index;
        });
        return hostAttacks;
      }
    },
    attackDetails: function() {
      return Session.get('attackDetails');
    },
    displayIndex: function(index) {
      return index + 1
    }
  });

  Template.vr.events({

    "click #container": function(e) {
      var mouse = {
        x: (e.clientX / WIDTH)*2 - 1,
        y: (e.clientY / HEIGHT)*2 - 1
      };
      var mouseVector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
      projector.unprojectVector(mouseVector, camera);
      var raycaster = new THREE.Raycaster(camera.position, mouseVector.sub( camera.position).normalize() );
      var intersects = raycaster.intersectObjects(sceneObjects, true);
      var sideNav = $('#attack-sidenav');
      console.log(intersects);

      if (intersects.length) {
        intersects.forEach(function(intersect) {
          // console.log(intersect);
          var attackRank = intersect.object.rank;
          var attackRegion = intersect.object.host;
          var attacks = intersect.object.attacks;
          if (typeof attackRank !== "undefined") {
            var sessionAttackObj = {
              host: attackRegion,
              rank: attackRank,
              attacks: attacks
            };
            Session.set('hostAttacks', sessionAttackObj);
            // Open the nav if not already opened
            if (!sideNav.hasClass(OPENNAV)) {
              sideNav.addClass(OPENNAV);
            }
          }
        });
      }
      else if(sideNav.hasClass(OPENNAV)) {
        sideNav.removeClass(OPENNAV);
      }
    },

    "change .cbox": function(event) {
      var isChecked = $('.cbox').is(':checked');
      var attackId = Session.get('attackDetails').id;
      console.log(attackId, isChecked);
      if (isChecked) {
        // attackers.update()
      }
      else {

      }
    },

    "click .attacks-list-item": function(event) {
      var attackIndex = event.target.getAttribute('data-index');
      var hostName = document.getElementById('attacks-host').innerText;
      var attackDetails = world[hostName][attackIndex];
      console.log(attackDetails);
      Session.set('attackDetails', attackDetails);
      $('#specific-attack-details').slideToggle();
      $('#attacks-list').slideToggle();
    },

    "click .back-button": function() {
      $('#specific-attack-details').slideToggle();
      $('#attacks-list').slideToggle();
    },

    "click .blockip": function(e,t){
      Session.set('blockIPipaddress',($(e.target).attr('data-ipaddress')));
      //disable and hook to re-enable the scene controls so they don't grab the mouse and use it
      sceneControls.enabled = false;
      controls.enabled = false;
      console.log("BLCOK OPPP");
      $('#modalBlockIPWindow').on('hidden', function () {
          sceneControls.enabled=true;
          controls.enabled = true;
      });
      $('#modalBlockIPWindow').modal();
    },

  });

  Template.vr.destroyed = function () {
    container.removeChild(renderer.domElement);
    scene = null;
    camera = null;
    renderer = null;
    WIDTH  = window.innerWidth;
    HEIGHT = window.innerHeight;
    SPEED = 0.01;
  };//end template.attackers.destroyed

}
<|endoftext|>


<commit_before>/**
 * @file Entry-point script for the OpenAddresses import pipeline.
 */

'use strict';

var fs = require( 'fs' );
var path = require( 'path' );
var util = require( 'util' );

var peliasConfig = require( 'pelias-config' );
var minimist = require( 'minimist' );
var combinedStream = require( 'combined-stream' );
var logger = require( 'pelias-logger' ).get( 'openaddresses' );
var addressDeduplicatorStream = require( 'pelias-address-deduplicator' );
var peliasAdminLookup = require( 'pelias-admin-lookup' );

var importPipelines = require( './lib/import_pipelines' );

/**
 * Import all OpenAddresses CSV files in a directory into Pelias elasticsearch.
 *
 * @param {string} dirPath The path to a directory. All *.csv files inside of
 *    it will be read and imported (they're assumed to contain OpenAddresses
 *    data).
 * @param {object} opts Options to configure the import. Supports the following
 *    keys:
 *
 *      deduplicate: Pass address object through `address-deduplicator-stream`
 *        to perform deduplication. See the documentation:
 *        https://github.com/pelias/address-deduplicator-stream
 *
 *      admin-values: Add admin values to each address object (since
 *        OpenAddresses doesn't contain any) using `hierarchy-lookup`. See the
 *        documentation: https://github.com/pelias/hierarchy-lookup
 */
function importOpenAddressesDir( dirPath, opts ){
  var recordStream = combinedStream.create();

  logger.info( 'Importing files in the `%s` directory.', dirPath );
  fs.readdirSync( dirPath ).forEach( function forEach( filePath ){
    if( filePath.match( /.csv$/ ) ){
      var fullPath = path.join( dirPath, filePath );
      recordStream.append( function ( next ){
        logger.info( 'Creating read stream for: ' + filePath );
        next( importPipelines.createRecordStream( fullPath ) );
      });
    }
  });

  var esPipeline = importPipelines.createPeliasElasticsearchPipeline();

  if( opts.deduplicate ){
    logger.info( 'Setting up deduplicator.' );
    var deduplicatorStream = addressDeduplicatorStream( 100, 10 );
    recordStream.pipe( deduplicatorStream );
    recordStream = deduplicatorStream;
  }

  if( opts.adminValues ){
    logger.info( 'Setting up admin value lookup stream.' );
    peliasAdminLookup.stream( function ( lookupStream ){
      logger.info( 'Lookup stream created.' );
      recordStream.pipe( lookupStream ).pipe( esPipeline );
    });
  }
  else {
    recordStream.pipe( esPipeline );
  }
}

/**
 * Interprets the command-line arguments passed to the script.
 *
 * @param {array} argv Should be `process.argv.slice( 2 )`.
 * @return {object} If arguments were succesfully parsed, an object that can be
 *    used to call `importOpenAddressesDir`:
 *
 *      {
 *        dirPath: <string>,
 *        adminValues: <boolean>,
 *        deduplicate: <boolean>,
 *      }
 *
 *    Otherwise, an error object.
 *
 *      {
 *        exitCode: <number>,
 *        errMessage: <string>
 *      }
 */
function interpretUserArgs( argv ){
  var usageMessage = [
    'A tool for importing OpenAddresses data into Pelias. Usage:',
    '',
    '\tnode import.js --help | [--deduplicate] [--admin-values] [OPENADDRESSES_DIR]',
    '',
    '',
    '\t--help: Print this help message.',
    '',
    '\tOPENADDRESSES_DIR: A directory containing OpenAddresses CSV files.',
    '\t\tIf none is specified, the path from your PELIAS_CONFIG\'s',
    '\t\t`imports.openaddresses.datapath` will be used.',
    '',
    '\t--deduplicate: (advanced use) Deduplicate addresses using the',
    '\t\tOpenVenues deduplicator: https://github.com/openvenues/address_deduper.',
    '\t\tIt must be running at localhost:5000.',
    '',
    '\t--admin-values: (advanced use) OpenAddresses records lack admin values',
    '\t\t(country, state, city, etc., names), so auto-fill them',
    '\t\tby querying the Quattroshapes types in the Pelias',
    '\t\telasticsearch index. You must have imported these using',
    '\t\thttps://github.com/pelias/quattroshapes-pipeline.'
  ].join( '\n' );

  argv = minimist(
    argv,
    {
      boolean: [ 'deduplicate', 'admin-values' ],
      default: {
        deduplicate: false,
        'admin-values': false,
      }
    }
  );

  var validArgs = [ 'deduplicate', 'admin-values', 'help', '_' ];
  for( var arg in argv ){
    if( validArgs.indexOf( arg ) === -1 ){
      return {
        errMessage: util.format( '`%s` is not a recognized argument.', arg ),
        exitCode: 1
      };
    }
  }

  if( argv.help ){
    return { errMessage: usageMessage, exitCode: 0 };
  }

  var opts = {
    deduplicate: argv.deduplicate,
    adminValues: argv[ 'admin-values' ],
    dirPath: null
  };
  if( argv._.length > 0 ){
    opts.dirPath = argv._[ 0 ];
  }
  else {
    var conf = peliasConfig.generate();
    opts.dirPath = conf.imports.openaddresses.datapath;
  }

  if( !fs.existsSync( opts.dirPath ) ){
    return {
      errMessage: util.format( 'Directory `%s` does not exist.', opts.dirPath ),
      exitCode: 2
    };
  }
  else if( !fs.statSync( opts.dirPath ).isDirectory() ){
    return {
      errMessage: util.format( '`%s` is not a directory.', opts.dirPath ),
      exitCode: 2
    };
  }

  return opts;
}

if( require.main === module ){
  var args = interpretUserArgs( process.argv.slice( 2 ) );

  if( 'exitCode' in args ){
    ((args.exitCode > 0) ? logger.error : logger.info)( args.errMessage );
    process.exit( args.exitCode );
  }
  else {
    importOpenAddressesDir( args.dirPath, args );
  }
}
else {
  module.exports = interpretUserArgs; // for tests
}
<commit_msg>Increase deduper batch size, limit to 1 live req.<commit_after>/**
 * @file Entry-point script for the OpenAddresses import pipeline.
 */

'use strict';

var fs = require( 'fs' );
var path = require( 'path' );
var util = require( 'util' );

var peliasConfig = require( 'pelias-config' );
var minimist = require( 'minimist' );
var combinedStream = require( 'combined-stream' );
var logger = require( 'pelias-logger' ).get( 'openaddresses' );
var addressDeduplicatorStream = require( 'pelias-address-deduplicator' );
var peliasAdminLookup = require( 'pelias-admin-lookup' );

var importPipelines = require( './lib/import_pipelines' );

/**
 * Import all OpenAddresses CSV files in a directory into Pelias elasticsearch.
 *
 * @param {string} dirPath The path to a directory. All *.csv files inside of
 *    it will be read and imported (they're assumed to contain OpenAddresses
 *    data).
 * @param {object} opts Options to configure the import. Supports the following
 *    keys:
 *
 *      deduplicate: Pass address object through `address-deduplicator-stream`
 *        to perform deduplication. See the documentation:
 *        https://github.com/pelias/address-deduplicator-stream
 *
 *      admin-values: Add admin values to each address object (since
 *        OpenAddresses doesn't contain any) using `hierarchy-lookup`. See the
 *        documentation: https://github.com/pelias/hierarchy-lookup
 */
function importOpenAddressesDir( dirPath, opts ){
  var recordStream = combinedStream.create();

  logger.info( 'Importing files in the `%s` directory.', dirPath );
  fs.readdirSync( dirPath ).forEach( function forEach( filePath ){
    if( filePath.match( /.csv$/ ) ){
      var fullPath = path.join( dirPath, filePath );
      recordStream.append( function ( next ){
        logger.info( 'Creating read stream for: ' + filePath );
        next( importPipelines.createRecordStream( fullPath ) );
      });
    }
  });

  var esPipeline = importPipelines.createPeliasElasticsearchPipeline();

  if( opts.deduplicate ){
    logger.info( 'Setting up deduplicator.' );
    var deduplicatorStream = addressDeduplicatorStream( 10000, 1 );
    recordStream.pipe( deduplicatorStream );
    recordStream = deduplicatorStream;
  }

  if( opts.adminValues ){
    logger.info( 'Setting up admin value lookup stream.' );
    peliasAdminLookup.stream( function ( lookupStream ){
      logger.info( 'Lookup stream created.' );
      recordStream.pipe( lookupStream ).pipe( esPipeline );
    });
  }
  else {
    recordStream.pipe( esPipeline );
  }
}

/**
 * Interprets the command-line arguments passed to the script.
 *
 * @param {array} argv Should be `process.argv.slice( 2 )`.
 * @return {object} If arguments were succesfully parsed, an object that can be
 *    used to call `importOpenAddressesDir`:
 *
 *      {
 *        dirPath: <string>,
 *        adminValues: <boolean>,
 *        deduplicate: <boolean>,
 *      }
 *
 *    Otherwise, an error object.
 *
 *      {
 *        exitCode: <number>,
 *        errMessage: <string>
 *      }
 */
function interpretUserArgs( argv ){
  var usageMessage = [
    'A tool for importing OpenAddresses data into Pelias. Usage:',
    '',
    '\tnode import.js --help | [--deduplicate] [--admin-values] [OPENADDRESSES_DIR]',
    '',
    '',
    '\t--help: Print this help message.',
    '',
    '\tOPENADDRESSES_DIR: A directory containing OpenAddresses CSV files.',
    '\t\tIf none is specified, the path from your PELIAS_CONFIG\'s',
    '\t\t`imports.openaddresses.datapath` will be used.',
    '',
    '\t--deduplicate: (advanced use) Deduplicate addresses using the',
    '\t\tOpenVenues deduplicator: https://github.com/openvenues/address_deduper.',
    '\t\tIt must be running at localhost:5000.',
    '',
    '\t--admin-values: (advanced use) OpenAddresses records lack admin values',
    '\t\t(country, state, city, etc., names), so auto-fill them',
    '\t\tby querying the Quattroshapes types in the Pelias',
    '\t\telasticsearch index. You must have imported these using',
    '\t\thttps://github.com/pelias/quattroshapes-pipeline.'
  ].join( '\n' );

  argv = minimist(
    argv,
    {
      boolean: [ 'deduplicate', 'admin-values' ],
      default: {
        deduplicate: false,
        'admin-values': false,
      }
    }
  );

  var validArgs = [ 'deduplicate', 'admin-values', 'help', '_' ];
  for( var arg in argv ){
    if( validArgs.indexOf( arg ) === -1 ){
      return {
        errMessage: util.format( '`%s` is not a recognized argument.', arg ),
        exitCode: 1
      };
    }
  }

  if( argv.help ){
    return { errMessage: usageMessage, exitCode: 0 };
  }

  var opts = {
    deduplicate: argv.deduplicate,
    adminValues: argv[ 'admin-values' ],
    dirPath: null
  };
  if( argv._.length > 0 ){
    opts.dirPath = argv._[ 0 ];
  }
  else {
    var conf = peliasConfig.generate();
    opts.dirPath = conf.imports.openaddresses.datapath;
  }

  if( !fs.existsSync( opts.dirPath ) ){
    return {
      errMessage: util.format( 'Directory `%s` does not exist.', opts.dirPath ),
      exitCode: 2
    };
  }
  else if( !fs.statSync( opts.dirPath ).isDirectory() ){
    return {
      errMessage: util.format( '`%s` is not a directory.', opts.dirPath ),
      exitCode: 2
    };
  }

  return opts;
}

if( require.main === module ){
  var args = interpretUserArgs( process.argv.slice( 2 ) );

  if( 'exitCode' in args ){
    ((args.exitCode > 0) ? logger.error : logger.info)( args.errMessage );
    process.exit( args.exitCode );
  }
  else {
    importOpenAddressesDir( args.dirPath, args );
  }
}
else {
  module.exports = interpretUserArgs; // for tests
}
<|endoftext|>


<commit_before>const manifest = [
  { id: 'monster', src: 'img/monster-sprite.png' },
  { id: 'bird', src: 'img/bird-sprite.png' },
  { id: 'chicken', src: 'img/chicken-sprite.png' },
  { id: 'spike', src: 'img/spike.png' },
  { id: 'sky', src: 'img/bg/sky.png' },
  { id: 'start', src: 'img/bg/start.png' },
  { id: 'mountain', src: 'img/bg/mountain.png' },
  { id: 'ground', src: 'img/bg/ground.png' },
  { id: 'btn', src: 'img/btn-sprite.png' },
  { id: 'icon-btn', src: 'img/icon-btn-sprite.png' },
  { id: 'icon', src: 'img/icon-sprite.png' },
  { id: 'back', src: 'sound/background.ogg' },
  { id: 'flap', src: 'sound/flap.ogg' },
  { id: 'loose', src: 'sound/loose.ogg' },
];

const getHeroSpriteSheetData = name => ({
  images: [name],
  frames: { width: 100, height: 78 },
  animations: {
    fly: 0,
    flap: [1, 3, 'fly'],
    dead: 4,
  },
});

const spriteSheetsData = {
  bird: getHeroSpriteSheetData('bird'),
  monster: getHeroSpriteSheetData('monster'),
  chicken: getHeroSpriteSheetData('chicken'),
  btn: {
    images: ['btn'],
    frames: { width: 210, height: 69, spacing: 2 },
    animations: {
      greenOut: 0,
      greenOver: 2,
      greenDown: 4,
      orangeOut: 6,
      orangeOver: 8,
      orangeDown: 1,
      redOut: 3,
      redOver: 5,
      redDown: 7,
      disable: 9,
    },
  },
  iconBtn: {
    images: ['icon-btn'],
    frames: { width: 69, height: 71, spacing: 2 },
    animations: {
      greenOut: 0,
      greenOver: 1,
      greenDown: 2,
      orangeOut: 3,
      orangeOver: 4,
      orangeDown: 5,
      redOut: 8,
      redOver: 7,
      redDown: 6,
      disable: 9,
    },
  },
  icon: {
    images: ['icon'],
    frames: { width: 40, height: 40 },
    animations: {
      sound: 0,
      soundOff: 1,
    },
  },
};

const spriteSheets = {};

const assetsManager = {
  init() {
    createjs.Sound.alternateExtensions = ['mp3'];
    this.queue = new createjs.LoadQueue();
    this.queue.installPlugin(createjs.Sound);
    this.queue.loadManifest(manifest);

    return new Promise(resolve =>
      this.queue.addEventListener('complete', () => resolve()));
  },
  getResult(name) {
    return this.queue.getResult(name);
  },
  getSpriteSheet(name) {
    if (!spriteSheets[name]) {
      const data = spriteSheetsData[name];

      if (!data) {
        throw new Error('invalid spriteSheet name');
      }

      data.images = data.images.map(img => this.getResult(img));
      spriteSheets[name] = new createjs.SpriteSheet(data);
    }

    return spriteSheets[name];
  },
};

export default assetsManager;
<commit_msg>add reject to assetsManager init method<commit_after>const manifest = [
  { id: 'monster', src: 'img/monster-sprite.png' },
  { id: 'bird', src: 'img/bird-sprite.png' },
  { id: 'chicken', src: 'img/chicken-sprite.png' },
  { id: 'spike', src: 'img/spike.png' },
  { id: 'sky', src: 'img/bg/sky.png' },
  { id: 'start', src: 'img/bg/start.png' },
  { id: 'mountain', src: 'img/bg/mountain.png' },
  { id: 'ground', src: 'img/bg/ground.png' },
  { id: 'btn', src: 'img/btn-sprite.png' },
  { id: 'icon-btn', src: 'img/icon-btn-sprite.png' },
  { id: 'icon', src: 'img/icon-sprite.png' },
  { id: 'back', src: 'sound/background.ogg' },
  { id: 'flap', src: 'sound/flap.ogg' },
  { id: 'loose', src: 'sound/loose.ogg' },
];

const getHeroSpriteSheetData = name => ({
  images: [name],
  frames: { width: 100, height: 78 },
  animations: {
    fly: 0,
    flap: [1, 3, 'fly'],
    dead: 4,
  },
});

const spriteSheetsData = {
  bird: getHeroSpriteSheetData('bird'),
  monster: getHeroSpriteSheetData('monster'),
  chicken: getHeroSpriteSheetData('chicken'),
  btn: {
    images: ['btn'],
    frames: { width: 210, height: 69, spacing: 2 },
    animations: {
      greenOut: 0,
      greenOver: 2,
      greenDown: 4,
      orangeOut: 6,
      orangeOver: 8,
      orangeDown: 1,
      redOut: 3,
      redOver: 5,
      redDown: 7,
      disable: 9,
    },
  },
  iconBtn: {
    images: ['icon-btn'],
    frames: { width: 69, height: 71, spacing: 2 },
    animations: {
      greenOut: 0,
      greenOver: 1,
      greenDown: 2,
      orangeOut: 3,
      orangeOver: 4,
      orangeDown: 5,
      redOut: 8,
      redOver: 7,
      redDown: 6,
      disable: 9,
    },
  },
  icon: {
    images: ['icon'],
    frames: { width: 40, height: 40 },
    animations: {
      sound: 0,
      soundOff: 1,
    },
  },
};

const spriteSheets = {};

const assetsManager = {
  init() {
    createjs.Sound.alternateExtensions = ['mp3'];
    this.queue = new createjs.LoadQueue();
    this.queue.installPlugin(createjs.Sound);
    this.queue.loadManifest(manifest);

    return new Promise((resolve, reject) => {
      this.queue.addEventListener('complete', () => resolve());
      this.queue.addEventListener('error', () => reject());
    });
  },
  getResult(name) {
    return this.queue.getResult(name);
  },
  getSpriteSheet(name) {
    if (!spriteSheets[name]) {
      const data = spriteSheetsData[name];

      if (!data) {
        throw new Error('invalid spriteSheet name');
      }

      data.images = data.images.map(img => this.getResult(img));
      spriteSheets[name] = new createjs.SpriteSheet(data);
    }

    return spriteSheets[name];
  },
};

export default assetsManager;
<|endoftext|>


<commit_before>var NwBuilder = require('../');
var gulp = require('gulp');
var gutil = require('gulp-util');

gulp.task('nw', function () {

    var nw = new NwBuilder({
        version: '0.14.6',
        files: './nwapp/**',
        macIcns: './icons/icon.icns',
        macPlist: {mac_bundle_id: 'myPkg'},
        platforms: ['win32', 'win64', 'osx64']
    });

    // Log stuff you want
    nw.on('log', function (msg) {
        gutil.log('nw-builder', msg);
    });

    // Build returns a promise, return it so the task isn't called in parallel
    return nw.build().catch(function (err) {
        gutil.log('nw-builder', err);
    });
});

gulp.task('default', ['nw']);
<commit_msg>2.2.2 - Fix for cache check of some legacy versions<commit_after>var NwBuilder = require('nw-builder');
var gulp = require('gulp');
var gutil = require('gulp-util');

gulp.task('nw', function () {

    var nw = new NwBuilder({
        version: '0.14.6',
        files: './nwapp/**',
        macIcns: './icons/icon.icns',
        macPlist: {mac_bundle_id: 'myPkg'},
        platforms: ['win32', 'win64', 'osx64']
    });

    // Log stuff you want
    nw.on('log', function (msg) {
        gutil.log('nw-builder', msg);
    });

    // Build returns a promise, return it so the task isn't called in parallel
    return nw.build().catch(function (err) {
        gutil.log('nw-builder', err);
    });
});

gulp.task('default', ['nw']);
<|endoftext|>


<commit_before>var express = require('express');
var path = require('path');
var bodyparser = require('body-parser');
var passport = require('passport');
var index = require('./routes/index');
var users = require('./routes/users');
var mongoose = require('mongoose');
var config = require('./config/database')
var search = require('./routes/search');

var port = process.env.PORT || 8080;
var app = express();
mongoose.connect(config.database )
//view Engine
//app.set('dist', path.join(__dirname, '../dist'));
app.set('dist engine', 'ejs');
app.engine('html', require('ejs').renderFile);

//set static folder
app.use(express.static(path.join(__dirname,'../dist')));

//Body parser midleware
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({extended: false}));

//Passport midleware
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);

//Set static files
app.use(express.static(path.join(__dirname,'dist')));

app.use('/', index);
app.use('/api', users);

app.use('/api', search);

app.listen(port, function(){
    console.log('Server running on port' +port);
});
<commit_msg>second commit<commit_after>var express = require('express');
var path = require('path');
var bodyparser = require('body-parser');
var passport = require('passport');
var index = require('./routes/index');
var users = require('./routes/users');
var mongoose = require('mongoose');
var config = require('./config/database')
var search = require('./routes/search');

var port = process.env.PORT || 8080;
var app = express();
mongoose.connect(config.database )
//view Engine
//app.set('dist', path.join(__dirname, '../dist'));
app.set('dist engine', 'ejs');
app.engine('html', require('ejs').renderFile);

//set static folder
app.use(express.static(path.join(__dirname,'../dist')));

//Body parser midleware
app.use(bodyparser.json());
app.use(bodyparser.urlencoded({extended: false}));

//Passport midleware
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport);

//Set static files
app.use(express.static(path.join(__dirname,'dist')));

app.use('', index);
app.use('api', users);

app.use('api', search);

app.listen(port, function(){
    console.log('Server running on port' +port);
});
<|endoftext|>


<commit_before>/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
try {
  admin.initializeApp();
} catch (e) {}

/**
 * Triggers when a user gets a new follower and sends notifications if the user has enabled them.
 * Also avoids sending multiple notifications for the same user by keeping a timestamp of sent notifications.
 */
exports.default = functions.database.ref('/followers/{followedUid}/{followerUid}').onWrite(
    async (change, context) => {
      const followerUid = context.params.followerUid;
      const followedUid = context.params.followedUid;
      // If un-follow we exit the function.
      if (!change.after.val()) {
        return console.log('User ', followerUid, 'un-followed user', followedUid);
      }
      const followedUserRef = admin.database().ref(`people/${followedUid}`);
      console.log('We have a new follower UID:', followerUid, 'for user:', followerUid);

      // Check if the user has notifications enabled.
      const enabledSnap = await followedUserRef.child('/notificationEnabled').once('value');
      const notificationsEnabled = enabledSnap.val();
      if (!notificationsEnabled) {
        console.log('The user has not enabled notifications.');
        return;
      }
      console.log('User has notifications enabled.');

      // Check if we already sent that notification.
      const snap = followedUserRef.child(`/notificationsSent/${followerUid}`).once('value');
      if (snap.val()) {
        return console.log('Already sent a notification to', followedUid, 'for this follower.');
      }
      console.log('Not yet sent a notification to', followedUid, 'for this follower.');

      // Get the list of device notification tokens.
      const getNotificationTokensPromise = followedUserRef.child('notificationTokens').once('value');

      // Get the follower profile.
      const getFollowerProfilePromise = admin.auth().getUser(followerUid);

      const results = await Promise.all([getNotificationTokensPromise, getFollowerProfilePromise]);
      const tokensSnapshot = results[0];
      const follower = results[1];

      // Check if there are any device tokens.
      if (!tokensSnapshot.hasChildren()) {
        return console.log('There are no notification tokens to send to.');
      }
      console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
      console.log('Fetched follower profile', follower);
      const displayName = follower.displayName;
      const profilePic = follower.photoURL;

      // Notification details.
      const payload = {
        notification: {
          title: 'You have a new follower!',
          body: `${displayName} is now following you.`,
          icon: profilePic || '/images/silhouette.jpg',
          click_action: `https://friendly-pix.com/user/${followerUid}`,
        },
      };

      // Listing all device tokens of the user to notify.
      const tokens = Object.keys(tokensSnapshot.val());

      // Saves the flag that this notification has been sent.
      const setNotificationsSentTask = followedUserRef.child(`/notificationsSent/${followerUid}`)
          .set(admin.database.ServerValue.TIMESTAMP).then(() => {
            console.log('Marked notification as sent.');
          });

      // Send notifications to all tokens.
      const notificationPromise = admin.messaging().sendToDevice(tokens, payload).then(
          (response) => removeBadTokens(response, tokens));

      return Promise.all([notificationPromise, setNotificationsSentTask]);
    });

// Given a response object from the FCM API, remove all invalid tokens.
async function removeBadTokens(response, tokens) {
  // For each message check if there was an error.
  const tokensToRemove = {};
  response.results.forEach((result, index) => {
    const error = result.error;
    if (error) {
      // Cleanup the tokens who are not registered anymore.
      if (error.code === 'messaging/invalid-registration-token' ||
          error.code === 'messaging/registration-token-not-registered') {
        console.log('The following token is not registered anymore', tokens[index]);
        tokensToRemove[`/people/${followedUid}/notificationTokens/${tokens[index]}`] = null;
      } else {
        console.error('Failure sending notification to', tokens[index], error);
      }
    }
  });
  // If there are tokens to cleanup.
  const nbTokensToCleanup = Object.keys(tokensToRemove).length;
  if (nbTokensToCleanup > 0) {
    await admin.database().ref().update(tokensToRemove);
    console.log(`Removed ${nbTokensToCleanup} unregistered tokens.`);
  }
  console.log(`Successfully sent ${tokens.length - nbTokensToCleanup} notifications.`);
}
<commit_msg>Fixed promise in sendfollowerNotification<commit_after>/**
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
'use strict';

const functions = require('firebase-functions');
const admin = require('firebase-admin');
try {
  admin.initializeApp();
} catch (e) {}

/**
 * Triggers when a user gets a new follower and sends notifications if the user has enabled them.
 * Also avoids sending multiple notifications for the same user by keeping a timestamp of sent notifications.
 */
exports.default = functions.database.ref('/followers/{followedUid}/{followerUid}').onWrite(
    async (change, context) => {
      const followerUid = context.params.followerUid;
      const followedUid = context.params.followedUid;
      // If un-follow we exit the function.
      if (!change.after.val()) {
        return console.log('User ', followerUid, 'un-followed user', followedUid);
      }
      const followedUserRef = admin.database().ref(`people/${followedUid}`);
      console.log('We have a new follower UID:', followerUid, 'for user:', followerUid);

      // Check if the user has notifications enabled.
      const enabledSnap = await followedUserRef.child('/notificationEnabled').once('value');
      const notificationsEnabled = enabledSnap.val();
      if (!notificationsEnabled) {
        console.log('The user has not enabled notifications.');
        return;
      }
      console.log('User has notifications enabled.');

      // Check if we already sent that notification.
      const snap = await followedUserRef.child(`/notificationsSent/${followerUid}`).once('value');
      if (snap.val()) {
        return console.log('Already sent a notification to', followedUid, 'for this follower.');
      }
      console.log('Not yet sent a notification to', followedUid, 'for this follower.');

      // Get the list of device notification tokens.
      const getNotificationTokensPromise = followedUserRef.child('notificationTokens').once('value');

      // Get the follower profile.
      const getFollowerProfilePromise = admin.auth().getUser(followerUid);

      const results = await Promise.all([getNotificationTokensPromise, getFollowerProfilePromise]);
      const tokensSnapshot = results[0];
      const follower = results[1];

      // Check if there are any device tokens.
      if (!tokensSnapshot.hasChildren()) {
        return console.log('There are no notification tokens to send to.');
      }
      console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
      console.log('Fetched follower profile', follower);
      const displayName = follower.displayName;
      const profilePic = follower.photoURL;

      // Notification details.
      const payload = {
        notification: {
          title: 'You have a new follower!',
          body: `${displayName} is now following you.`,
          icon: profilePic || '/images/silhouette.jpg',
          click_action: `https://friendly-pix.com/user/${followerUid}`,
        },
      };

      // Listing all device tokens of the user to notify.
      const tokens = Object.keys(tokensSnapshot.val());

      // Saves the flag that this notification has been sent.
      const setNotificationsSentTask = followedUserRef.child(`/notificationsSent/${followerUid}`)
          .set(admin.database.ServerValue.TIMESTAMP).then(() => {
            console.log('Marked notification as sent.');
          });

      // Send notifications to all tokens.
      const notificationPromise = admin.messaging().sendToDevice(tokens, payload).then(
          (response) => removeBadTokens(response, tokens));

      return Promise.all([notificationPromise, setNotificationsSentTask]);
    });

// Given a response object from the FCM API, remove all invalid tokens.
async function removeBadTokens(response, tokens) {
  // For each message check if there was an error.
  const tokensToRemove = {};
  response.results.forEach((result, index) => {
    const error = result.error;
    if (error) {
      // Cleanup the tokens who are not registered anymore.
      if (error.code === 'messaging/invalid-registration-token' ||
          error.code === 'messaging/registration-token-not-registered') {
        console.log('The following token is not registered anymore', tokens[index]);
        tokensToRemove[`/people/${followedUid}/notificationTokens/${tokens[index]}`] = null;
      } else {
        console.error('Failure sending notification to', tokens[index], error);
      }
    }
  });
  // If there are tokens to cleanup.
  const nbTokensToCleanup = Object.keys(tokensToRemove).length;
  if (nbTokensToCleanup > 0) {
    await admin.database().ref().update(tokensToRemove);
    console.log(`Removed ${nbTokensToCleanup} unregistered tokens.`);
  }
  console.log(`Successfully sent ${tokens.length - nbTokensToCleanup} notifications.`);
}
<|endoftext|>


<commit_before>'use strict';

WaveformPlaylist.TrackEditor = {

    init: function(src, start, end, fades, cues, stateConfig) {

        var statesEnabled = {
            'cursor': true,
            'fadein': true,
            'fadeout': true,
            'select': true,
            'shift': true,
            'fileDrop': true
        };

        stateConfig = stateConfig || {};

        //extend enabled states config.
        Object.keys(statesEnabled).forEach(function (key) {
            statesEnabled[key] = (key in stateConfig) ? stateConfig[key] : statesEnabled[key];
        });

        this.enabledStates = statesEnabled;

        WaveformPlaylist.makePublisher(this);

        this.playout = Object.create(WaveformPlaylist.AudioPlayout, {
            config: {
                value: this.config
            }
        });
        this.playout.init();

        this.sampleRate = this.config.getSampleRate();
        this.resolution = this.config.getResolution();

        //value is a float in seconds
        this.startTime = start || 0;
        //value is a float in seconds
        this.endTime = end || 0; //set properly in onTrackLoad.

        this.fades = {};
        if (fades !== undefined && fades.length > 0) {

            for (var i = 0; i < fades.length; i++) {
                this.fades[this.getFadeId()] = fades[i];
            }
        }

        if (cues !== undefined) {
            this.cuein = cues.cuein;
            this.cueout = cues.cueout;
        }

        this.active = false;
        this.gain = 1;
        //selected area stored in seconds relative to entire playlist.
        this.selectedArea = undefined;

        this.drawer = Object.create(WaveformPlaylist.WaveformDrawer, {
            config: {
                value: this.config
            }
        });

        this.container = this.drawer.init();

        return this.container;
    },

    //value leftOffset is measured in samples.
    setLeftOffset: function(offset) {
        this.leftOffset = offset;
        this.drawer.setPixelOffset(offset / this.resolution);

        this.fire('changeshift');
    },

    getFadeId: function() {
        var id = ""+Math.random();

        return id.replace(".", "");
    },

    getBuffer: function() {
        return this.playout.getBuffer();
    },

    /*
    *   Completes track load from a passed in url.
    */
    loadTrack: function(track) {
        var el;

        el = this.init(
            track.src,
            track.start,
            track.end,
            track.fades,
            {
                cuein: track.cuein,
                cueout: track.cueout
            },
            track.states
        );

        if (track.selected !== undefined) {
            this.selectedArea = {
                startTime: track.selected.start,
                endTime: track.selected.end
            };
        }

        this.drawer.drawLoading();
        this.loadBuffer(track.src);

        return el;
    },

    fileProgress: function(e) {
        var percentComplete;

        if (e.lengthComputable) {
            percentComplete = e.loaded / e.total * 100;
            this.drawer.updateLoader(percentComplete);
        }
    },

    fileLoad: function(e) {
        var that = this;
        this.drawer.setLoaderState("decoding");

        this.playout.loadData(
            e.target.response || e.target.result,
            that.onTrackLoad.bind(that)
        );
    },

    /**
     * Loads an audio file via XHR.
     */
    loadBuffer: function(src) {
        var that = this,
            xhr = new XMLHttpRequest();

        this.filename = src.replace(/^.*[\\\/]/, '');
        this.src = src;

        xhr.open('GET', src, true);
        xhr.responseType = 'arraybuffer';

        xhr.addEventListener('progress', this.fileProgress.bind(this));
        xhr.addEventListener('load', this.fileLoad.bind(this));
        xhr.send();
    },

    /*
    * Loads an audio file vie a FileReader
    */
    loadBlob: function(file) {
        if (file.type.match(/audio.*/)) {
            var dr = new FileReader();
            var fr = new FileReader();
            var track = this;

            this.filename = file.name;
            this.drawer.drawLoading();

            dr.addEventListener('load', function() {
                track.src = dr.result;
            });

            fr.addEventListener('progress', this.fileProgress.bind(this));
            fr.addEventListener('load', this.fileLoad.bind(this));

            fr.addEventListener('error', function () {
                console.error('error loading file ' + this.filename);
            });

            dr.readAsDataURL(file);
            fr.readAsArrayBuffer(file);
        }
    },

    drawTrack: function(buffer) {
        this.drawer.drawWaveform(buffer, this.cues, this.fades);
    },

    onTrackLoad: function(buffer, err) {
        var res,
            startTime,
            endTime,
            cuein,
            cueout;

        if (err !== undefined) {
            this.drawer.drawError();
            this.fire('error', this);
            return;
        }

        cuein = (this.cuein && this.secondsToSamples(this.cuein)) || 0;
        cueout = (this.cueout && this.secondsToSamples(this.cueout)) || buffer.length;

        this.setCuePoints(cuein, cueout);

        this.drawer.drawContainer(buffer, this.cues, this.fades, this.filename);
        this.setLeftOffset(this.secondsToSamples(this.startTime));

        if (this.selectedArea !== undefined) {
            startTime = this.selectedArea.startTime;
            endTime = this.selectedArea.endTime;

            this.notifySelectUpdate(startTime, endTime);
        }

        this.setState(this.config.getState());
        this.fire('trackloaded', this);
    },

    activate: function() {
        this.active = true;
        this.drawer.drawActive();
    },

    deactivate: function() {
        this.active = false;
        this.drawer.drawInactive();

        if (this.selectedArea) {
            this.selectedArea = undefined;
        }
    },

    /*
        startTime, endTime in seconds.
    */
    notifySelectUpdate: function(startTime, endTime, shiftKey) {
        this.fire('changecursor', {
            start: startTime,
            end: endTime,
            shiftKey: shiftKey,
            editor: this
        });
    },

    /*
        start, end in seconds
    */
    setSelectedArea: function(start, end, shiftKey) {
        //extending selected area since shift is pressed on a single point click.
        if (shiftKey && (start === end) && (this.prevSelectedArea !== undefined)) {

            if (start >= this.prevSelectedArea.endTime) {
                start = this.prevSelectedArea.startTime;
            }
            else if (start <= this.prevSelectedArea.startTime ) {
                end = this.prevSelectedArea.endTime;
            }

        }

        this.prevSelectedArea = this.selectedArea;
        this.selectedArea = {
            startTime: start,
            endTime: end
        };

        this.config.setCursorPos(start);
        this.showSelection();

        if (start < end) {
            this.activateAudioSelection();
        }
        else {
            this.deactivateAudioSelection();
        }
    },

    activateAudioSelection: function() {

        this.fire("activateSelection");
    },

    deactivateAudioSelection: function() {

        this.fire("deactivateSelection");
    },

    saveFade: function(id, type, shape, start, end) {

        this.fades[id] = {
            type: type,
            shape: shape,
            start: start,
            end: end
        };

        return id;
    },

    removeFade: function(id) {

        delete this.fades[id];
        this.drawer.removeFade(id);
    },

    removeFadeType: function(type) {
        var id,
            fades = this.fades,
            fade;

        for (id in fades) {
            fade = fades[id];

            if (fade.type === type) {
                this.removeFade(id);
            }
        }
    },

    /*
        Cue points are stored internally in the editor as sample indices for highest precision.

        sample at index cueout is not included.
    */
    setCuePoints: function(cuein, cueout) {
        //need the offset for trimming an already trimmed track.
        var offset = this.cues ? this.cues.cuein : 0,
            buffer = this.getBuffer(),
            cutOff = this.cues ? this.cues.cueout : buffer.length;

        if (cuein < 0) {
            cuein = 0;
        }
        //adjust if the length was inaccurate and cueout is set to a higher sample than we actually have.
        if ((offset + cueout) > cutOff) {
            cueout = cutOff - offset;
        }

        this.cues = {
            cuein: offset + cuein,
            cueout: offset + cueout
        };

        this.duration = (cueout - cuein) / this.sampleRate;
        this.endTime = this.duration + this.startTime;
        this.cuein = this.samplesToSeconds(this.cues.cuein);
        this.cueout = this.samplesToSeconds(this.cues.cueout);
    },

    /*
        Will remove all audio samples from the track's buffer except for the currently selected area.
        Used to set cuein / cueout points in the audio.
    */
    trim: function() {
        var selected = this.selectedArea,
            sampleStart,
            sampleEnd;

        if (selected === undefined) {
            return;
        }

        sampleStart = this.secondsToSamples(selected.startTime) - this.leftOffset;
        //add one sample since last one is exclusive.
        sampleEnd = this.secondsToSamples(selected.endTime) - this.leftOffset + 1;

        this.setCuePoints(sampleStart, sampleEnd);
        this.notifySelectUpdate(0, 0);
        this.fades = {};
        this.drawTrack(this.getBuffer());
    },

    onTrackEdit: function(event) {
        var type = event.type,
            method = "on" + type.charAt(0).toUpperCase() + type.slice(1);

        if (this.active === true) {
            this[method].call(this, event.args);
        }
    },

    /*
        start, end are in pixels relative to the track.
    */
    createFade: function(type, shape, start, end) {
        var selected = this.selectedArea,
            startTime = this.pixelsToSeconds(start),
            endTime = this.pixelsToSeconds(end),
            id = this.getFadeId();

        this.notifySelectUpdate(0, 0);
        this.saveFade(id, type, shape, startTime, endTime);
        this.drawer.drawFade(id, type, shape, start, end);
    },

    onCreateFade: function(args) {
        this.createFade(args.type, args.shape);
        this.deactivateAudioSelection();
    },

    onTrimAudio: function() {
        var selected = this.selectedArea;

        this.trim(selected.start, selected.end);
        this.deactivateAudioSelection();
    },

    setState: function(state) {
        //leave the past state if it was enabled
        this.currentState && this.currentState.leave.call(this);

        if (this.enabledStates[state]) {
            this.currentState = WaveformPlaylist.states[state];
            this.currentState.enter.call(this);
        }
    },

    onResolutionChange: function(res) {
        var selected = this.selectedArea;

        this.resolution = res;
        this.drawTrack(this.getBuffer());
        this.drawer.setPixelOffset(this.leftOffset / res);

        if (this.active === true && this.selectedArea !== undefined) {

            this.drawer.drawHighlight(this.secondsToPixels(selected.startTime), this.secondsToPixels(selected.endTime));
        }

        this.fire('changeshift');
    },

    isPlaying: function() {
        return this.playout.isPlaying();
    },

    setGainLevel: function(gain) {
        this.gain = gain;
        this.playout.setGainLevel(gain);
    },

    setMasterGainLevel: function(gain) {
        this.playout.setMasterGainLevel(gain);
    },

    /*
        startTime, endTime in seconds (float).
        segment is for a highlighted section in the UI.

        returns a Promise that will resolve when the AudioBufferSource
        is either stopped or plays out naturally.
    */
    schedulePlay: function(now, startTime, endTime, options) {
        var start,
            duration,
            relPos,
            when = now,
            segment = (endTime) ? (endTime - startTime) : undefined,
            cueOffset = this.cues.cuein / this.sampleRate,
            sourcePromise;

        //1) track has no content to play.
        //2) track does not play in this selection.
        if ((this.endTime <= startTime) || (segment && (startTime + segment) < this.startTime)) {
            //return a resolved promise since this track is technically "stopped".
            return Promise.resolve();
        }

        //track should have something to play if it gets here.

        //the track starts in the future or on the cursor position
        if (this.startTime >= startTime) {
            start = 0;
            when = when + this.startTime - startTime; //schedule additional delay for this audio node.

            if (endTime) {
                segment = segment - (this.startTime - startTime);
                duration = Math.min(segment, this.duration);
            }
            else {
                duration = this.duration;
            }
        }
        else {
            start = startTime - this.startTime;

            if (endTime) {
                duration = Math.min(segment, this.duration - start);
            }
            else {
                duration = this.duration - start;
            }
        }

        start = start + cueOffset;
        relPos = startTime - this.startTime;

        sourcePromise = this.playout.setUpSource();
        this.playout.applyFades(this.fades, relPos, now);
        this.playout.setGainLevel(this.gain);
        this.playout.setMasterGainLevel(options.masterGain);
        this.playout.play(when, start, duration);

        return sourcePromise;
    },

    scheduleStop: function(when) {
        this.playout.stop(when || this.config.getCurrentTime());
    },

    /*
        cursorPos in seconds
    */
    showProgress: function(cursorPos) {
        this.drawer.updateProgress(this.secondsToPixels(cursorPos));
    },

    showSelection: function() {
        var start,
            end;

        start = this.secondsToPixels(this.selectedArea.startTime);
        end = this.secondsToPixels(this.selectedArea.endTime);

        //these pixels are relative to the playlist
        this.drawer.drawHighlight(start, end);
    },

    getTrackDetails: function() {
        var d,
            cues = this.cues,
            fades = [],
            id;

        for (id in this.fades) {
            fades.push(this.fades[id]);
        }

        d = {
            start: this.startTime,
            end: this.endTime,
            fades: fades,
            src: this.src,
            cuein: this.samplesToSeconds(cues.cuein),
            cueout: this.samplesToSeconds(cues.cueout)
        };

        return d;
    },

    destroy: function() {
        //remove events attached to the waveform
        this.currentState && this.currentState.leave.call(this);
    }
};

WaveformPlaylist.mixin(WaveformPlaylist.TrackEditor, WaveformPlaylist.unitConversions);
<commit_msg>Fix for preselected.<commit_after>'use strict';

WaveformPlaylist.TrackEditor = {

    init: function(src, start, end, fades, cues, stateConfig) {

        var statesEnabled = {
            'cursor': true,
            'fadein': true,
            'fadeout': true,
            'select': true,
            'shift': true,
            'fileDrop': true
        };

        stateConfig = stateConfig || {};

        //extend enabled states config.
        Object.keys(statesEnabled).forEach(function (key) {
            statesEnabled[key] = (key in stateConfig) ? stateConfig[key] : statesEnabled[key];
        });

        this.enabledStates = statesEnabled;

        WaveformPlaylist.makePublisher(this);

        this.playout = Object.create(WaveformPlaylist.AudioPlayout, {
            config: {
                value: this.config
            }
        });
        this.playout.init();

        this.sampleRate = this.config.getSampleRate();
        this.resolution = this.config.getResolution();

        //value is a float in seconds
        this.startTime = start || 0;
        //value is a float in seconds
        this.endTime = end || 0; //set properly in onTrackLoad.

        this.fades = {};
        if (fades !== undefined && fades.length > 0) {

            for (var i = 0; i < fades.length; i++) {
                this.fades[this.getFadeId()] = fades[i];
            }
        }

        if (cues !== undefined) {
            this.cuein = cues.cuein;
            this.cueout = cues.cueout;
        }

        this.active = false;
        this.gain = 1;
        //selected area stored in seconds relative to entire playlist.
        this.selectedArea = undefined;

        this.drawer = Object.create(WaveformPlaylist.WaveformDrawer, {
            config: {
                value: this.config
            }
        });

        this.container = this.drawer.init();

        return this.container;
    },

    //value leftOffset is measured in samples.
    setLeftOffset: function(offset) {
        this.leftOffset = offset;
        this.drawer.setPixelOffset(offset / this.resolution);

        this.fire('changeshift');
    },

    getFadeId: function() {
        var id = ""+Math.random();

        return id.replace(".", "");
    },

    getBuffer: function() {
        return this.playout.getBuffer();
    },

    /*
    *   Completes track load from a passed in url.
    */
    loadTrack: function(track) {
        var el;

        el = this.init(
            track.src,
            track.start,
            track.end,
            track.fades,
            {
                cuein: track.cuein,
                cueout: track.cueout
            },
            track.states
        );

        if (track.selected !== undefined) {
            this.selectedArea = {
                startTime: track.selected.start,
                endTime: track.selected.end
            };
        }

        this.drawer.drawLoading();
        this.loadBuffer(track.src);

        return el;
    },

    fileProgress: function(e) {
        var percentComplete;

        if (e.lengthComputable) {
            percentComplete = e.loaded / e.total * 100;
            this.drawer.updateLoader(percentComplete);
        }
    },

    fileLoad: function(e) {
        var that = this;
        this.drawer.setLoaderState("decoding");

        this.playout.loadData(
            e.target.response || e.target.result,
            that.onTrackLoad.bind(that)
        );
    },

    /**
     * Loads an audio file via XHR.
     */
    loadBuffer: function(src) {
        var that = this,
            xhr = new XMLHttpRequest();

        this.filename = src.replace(/^.*[\\\/]/, '');
        this.src = src;

        xhr.open('GET', src, true);
        xhr.responseType = 'arraybuffer';

        xhr.addEventListener('progress', this.fileProgress.bind(this));
        xhr.addEventListener('load', this.fileLoad.bind(this));
        xhr.send();
    },

    /*
    * Loads an audio file vie a FileReader
    */
    loadBlob: function(file) {
        if (file.type.match(/audio.*/)) {
            var dr = new FileReader();
            var fr = new FileReader();
            var track = this;

            this.filename = file.name;
            this.drawer.drawLoading();

            dr.addEventListener('load', function() {
                track.src = dr.result;
            });

            fr.addEventListener('progress', this.fileProgress.bind(this));
            fr.addEventListener('load', this.fileLoad.bind(this));

            fr.addEventListener('error', function () {
                console.error('error loading file ' + this.filename);
            });

            dr.readAsDataURL(file);
            fr.readAsArrayBuffer(file);
        }
    },

    drawTrack: function(buffer) {
        this.drawer.drawWaveform(buffer, this.cues, this.fades);
    },

    onTrackLoad: function(buffer, err) {
        var res,
            startTime,
            endTime,
            cuein,
            cueout;

        if (err !== undefined) {
            this.drawer.drawError();
            this.fire('error', this);
            return;
        }

        this.fire('trackloaded', this);

        cuein = (this.cuein && this.secondsToSamples(this.cuein)) || 0;
        cueout = (this.cueout && this.secondsToSamples(this.cueout)) || buffer.length;

        this.setCuePoints(cuein, cueout);

        this.drawer.drawContainer(buffer, this.cues, this.fades, this.filename);
        this.setLeftOffset(this.secondsToSamples(this.startTime));
        this.setState(this.config.getState());

        if (this.selectedArea !== undefined) {
            startTime = this.selectedArea.startTime;
            endTime = this.selectedArea.endTime;

            this.showSelection();
            this.notifySelectUpdate(startTime, endTime);
        }
    },

    activate: function() {
        this.active = true;
        this.drawer.drawActive();
    },

    deactivate: function() {
        this.active = false;
        this.drawer.drawInactive();

        if (this.selectedArea) {
            this.selectedArea = undefined;
        }
    },

    /*
        startTime, endTime in seconds.
    */
    notifySelectUpdate: function(startTime, endTime, shiftKey) {
        this.fire('changecursor', {
            start: startTime,
            end: endTime,
            shiftKey: shiftKey,
            editor: this
        });
    },

    /*
        start, end in seconds
    */
    setSelectedArea: function(start, end, shiftKey) {
        //extending selected area since shift is pressed on a single point click.
        if (shiftKey && (start === end) && (this.prevSelectedArea !== undefined)) {

            if (start >= this.prevSelectedArea.endTime) {
                start = this.prevSelectedArea.startTime;
            }
            else if (start <= this.prevSelectedArea.startTime ) {
                end = this.prevSelectedArea.endTime;
            }

        }

        this.prevSelectedArea = this.selectedArea;
        this.selectedArea = {
            startTime: start,
            endTime: end
        };

        this.config.setCursorPos(start);
        this.showSelection();

        if (start < end) {
            this.activateAudioSelection();
        }
        else {
            this.deactivateAudioSelection();
        }
    },

    activateAudioSelection: function() {

        this.fire("activateSelection");
    },

    deactivateAudioSelection: function() {

        this.fire("deactivateSelection");
    },

    saveFade: function(id, type, shape, start, end) {

        this.fades[id] = {
            type: type,
            shape: shape,
            start: start,
            end: end
        };

        return id;
    },

    removeFade: function(id) {

        delete this.fades[id];
        this.drawer.removeFade(id);
    },

    removeFadeType: function(type) {
        var id,
            fades = this.fades,
            fade;

        for (id in fades) {
            fade = fades[id];

            if (fade.type === type) {
                this.removeFade(id);
            }
        }
    },

    /*
        Cue points are stored internally in the editor as sample indices for highest precision.

        sample at index cueout is not included.
    */
    setCuePoints: function(cuein, cueout) {
        //need the offset for trimming an already trimmed track.
        var offset = this.cues ? this.cues.cuein : 0,
            buffer = this.getBuffer(),
            cutOff = this.cues ? this.cues.cueout : buffer.length;

        if (cuein < 0) {
            cuein = 0;
        }
        //adjust if the length was inaccurate and cueout is set to a higher sample than we actually have.
        if ((offset + cueout) > cutOff) {
            cueout = cutOff - offset;
        }

        this.cues = {
            cuein: offset + cuein,
            cueout: offset + cueout
        };

        this.duration = (cueout - cuein) / this.sampleRate;
        this.endTime = this.duration + this.startTime;
        this.cuein = this.samplesToSeconds(this.cues.cuein);
        this.cueout = this.samplesToSeconds(this.cues.cueout);
    },

    /*
        Will remove all audio samples from the track's buffer except for the currently selected area.
        Used to set cuein / cueout points in the audio.
    */
    trim: function() {
        var selected = this.selectedArea,
            sampleStart,
            sampleEnd;

        if (selected === undefined) {
            return;
        }

        sampleStart = this.secondsToSamples(selected.startTime) - this.leftOffset;
        //add one sample since last one is exclusive.
        sampleEnd = this.secondsToSamples(selected.endTime) - this.leftOffset + 1;

        this.setCuePoints(sampleStart, sampleEnd);
        this.notifySelectUpdate(0, 0);
        this.fades = {};
        this.drawTrack(this.getBuffer());
    },

    onTrackEdit: function(event) {
        var type = event.type,
            method = "on" + type.charAt(0).toUpperCase() + type.slice(1);

        if (this.active === true) {
            this[method].call(this, event.args);
        }
    },

    /*
        start, end are in pixels relative to the track.
    */
    createFade: function(type, shape, start, end) {
        var selected = this.selectedArea,
            startTime = this.pixelsToSeconds(start),
            endTime = this.pixelsToSeconds(end),
            id = this.getFadeId();

        this.notifySelectUpdate(0, 0);
        this.saveFade(id, type, shape, startTime, endTime);
        this.drawer.drawFade(id, type, shape, start, end);
    },

    onCreateFade: function(args) {
        this.createFade(args.type, args.shape);
        this.deactivateAudioSelection();
    },

    onTrimAudio: function() {
        var selected = this.selectedArea;

        this.trim(selected.start, selected.end);
        this.deactivateAudioSelection();
    },

    setState: function(state) {
        //leave the past state if it was enabled
        this.currentState && this.currentState.leave.call(this);

        if (this.enabledStates[state]) {
            this.currentState = WaveformPlaylist.states[state];
            this.currentState.enter.call(this);
        }
    },

    onResolutionChange: function(res) {
        var selected = this.selectedArea;

        this.resolution = res;
        this.drawTrack(this.getBuffer());
        this.drawer.setPixelOffset(this.leftOffset / res);

        if (this.active === true && this.selectedArea !== undefined) {

            this.drawer.drawHighlight(this.secondsToPixels(selected.startTime), this.secondsToPixels(selected.endTime));
        }

        this.fire('changeshift');
    },

    isPlaying: function() {
        return this.playout.isPlaying();
    },

    setGainLevel: function(gain) {
        this.gain = gain;
        this.playout.setGainLevel(gain);
    },

    setMasterGainLevel: function(gain) {
        this.playout.setMasterGainLevel(gain);
    },

    /*
        startTime, endTime in seconds (float).
        segment is for a highlighted section in the UI.

        returns a Promise that will resolve when the AudioBufferSource
        is either stopped or plays out naturally.
    */
    schedulePlay: function(now, startTime, endTime, options) {
        var start,
            duration,
            relPos,
            when = now,
            segment = (endTime) ? (endTime - startTime) : undefined,
            cueOffset = this.cues.cuein / this.sampleRate,
            sourcePromise;

        //1) track has no content to play.
        //2) track does not play in this selection.
        if ((this.endTime <= startTime) || (segment && (startTime + segment) < this.startTime)) {
            //return a resolved promise since this track is technically "stopped".
            return Promise.resolve();
        }

        //track should have something to play if it gets here.

        //the track starts in the future or on the cursor position
        if (this.startTime >= startTime) {
            start = 0;
            when = when + this.startTime - startTime; //schedule additional delay for this audio node.

            if (endTime) {
                segment = segment - (this.startTime - startTime);
                duration = Math.min(segment, this.duration);
            }
            else {
                duration = this.duration;
            }
        }
        else {
            start = startTime - this.startTime;

            if (endTime) {
                duration = Math.min(segment, this.duration - start);
            }
            else {
                duration = this.duration - start;
            }
        }

        start = start + cueOffset;
        relPos = startTime - this.startTime;

        sourcePromise = this.playout.setUpSource();
        this.playout.applyFades(this.fades, relPos, now);
        this.playout.setGainLevel(this.gain);
        this.playout.setMasterGainLevel(options.masterGain);
        this.playout.play(when, start, duration);

        return sourcePromise;
    },

    scheduleStop: function(when) {
        this.playout.stop(when || this.config.getCurrentTime());
    },

    /*
        cursorPos in seconds
    */
    showProgress: function(cursorPos) {
        this.drawer.updateProgress(this.secondsToPixels(cursorPos));
    },

    showSelection: function() {
        var start,
            end;

        start = this.secondsToPixels(this.selectedArea.startTime);
        end = this.secondsToPixels(this.selectedArea.endTime);

        //these pixels are relative to the playlist
        this.drawer.drawHighlight(start, end);
    },

    getTrackDetails: function() {
        var d,
            cues = this.cues,
            fades = [],
            id;

        for (id in this.fades) {
            fades.push(this.fades[id]);
        }

        d = {
            start: this.startTime,
            end: this.endTime,
            fades: fades,
            src: this.src,
            cuein: this.samplesToSeconds(cues.cuein),
            cueout: this.samplesToSeconds(cues.cueout)
        };

        return d;
    },

    destroy: function() {
        //remove events attached to the waveform
        this.currentState && this.currentState.leave.call(this);
    }
};

WaveformPlaylist.mixin(WaveformPlaylist.TrackEditor, WaveformPlaylist.unitConversions);
<|endoftext|>


<commit_before>var gulp = require('gulp');

// The protractor task
var protractor = require('../').protractor;

// Start a standalone server
var webdriver_standalone = require('../').webdriver_standalone;

// Download and update the selenium driver
var webdriver_update = require('../').webdriver_update;

// Downloads the selenium webdriver
gulp.task('webdriver_update', webdriver_update);

// Start the standalone selenium server
// NOTE: This is not needed if you reference the
// seleniumServerJar in your protractor.conf.js
gulp.task('webdriver_standalone', webdriver_standalone);

// Setting up the test task
gulp.task('protractor', ['webdriver_update'], function() {
    gulp.src(['example_spec.js']).pipe(protractor({
        configFile: 'protractor.conf.js',
    })).on('error', function(e) { throw e });
});
<commit_msg>Update Gulpfile.js<commit_after>var gulp = require('gulp');

// The protractor task
var protractor = require('../').protractor;

// Start a standalone server
var webdriver_standalone = require('../').webdriver_standalone;

// Download and update the selenium driver
var webdriver_update = require('../').webdriver_update;

// Downloads the selenium webdriver
gulp.task('webdriver_update', webdriver_update);

// Start the standalone selenium server
// NOTE: This is not needed if you reference the
// seleniumServerJar in your protractor.conf.js
gulp.task('webdriver_standalone', webdriver_standalone);

// Setting up the test task
gulp.task('protractor', ['webdriver_update'], function(cb) {
    gulp.src(['example_spec.js']).pipe(protractor({
        configFile: 'protractor.conf.js',
    })).on('error', function(e) {
        console.log(e)
    }).on('end', cb);
});
<|endoftext|>


<commit_before>const nodeExternals = require('webpack-node-externals');
const CopyPlugin = require('copy-webpack-plugin');
const version = require('./package.json').version;
// var Visualizer = require('webpack-visualizer-plugin2');

// Custom webpack loaders are generally the same for all webpack bundles, hence
// stored in a separate local variable.
const rules = [
    {
        test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
        type: 'asset/inline',
    },
    {
        test: /\.(glsl|txt)/,
        type: 'asset/source',
    },
    {
        resourceQuery: /raw/,
        type: 'asset/source',
    },
];

const mode = 'development';

const plugins = [];

// plugins.push(new Visualizer({
//     filename: './webpack-statistics.html'
// }));

module.exports = [
    { // Notebook extension
        //
        // This bundle only contains the part of the JavaScript that is run on
        // load of the notebook. This section generally only performs
        // some configuration for requirejs, and provides the legacy
        // "load_ipython_extension" function which is required for any notebook
        // extension.
        //
        entry: './src/extension.js',
        output: {
            filename: 'extension.js',
            path: `${__dirname}/../k3d/static`,
            libraryTarget: 'amd',
        },
        module: {
            rules,
        },
        mode,
        plugins,
    },
    { // Bundle for the notebook containing the custom widget views and models
        //
        // This bundle contains the implementation for the custom widget views and
        // custom widget.
        // It must be an amd module
        //
        entry: './src/index.js',
        output: {
            filename: 'index.js',
            path: `${__dirname}/../k3d/static`,
            libraryTarget: 'amd',
        },
        mode,
        plugins,
        devtool: 'source-map',
        module: {
            rules,
        },
        externals: ['@jupyter-widgets/base'],
    },
    { // Embeddable K3D-jupyter bundle
        //
        // This bundle is generally almost identical to the notebook bundle
        // containing the custom widget views and models.
        //
        // The only difference is in the configuration of the webpack public path
        // for the static assets.
        //
        // It will be automatically distributed by unpkg to work with the static
        // widget embedder.
        //
        // The target bundle is always `dist/index.js`, which is the path required
        // by the custom widget embedder.
        //
        entry: './src/embed.js',
        output: {
            filename: 'index.js',
            path: `${__dirname}/dist/`,
            libraryTarget: 'amd',
            publicPath: `https://unpkg.com/k3d@${version}/dist/`,
        },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins,
        externals: ['@jupyter-widgets/base'],
    },
    {
        entry: './src/standalone.js',
        output:
            {
                filename: 'standalone.js',
                path: `${__dirname}/../k3d/static`,
                library: 'k3d',
                libraryTarget: 'amd',
                publicPath: `https://unpkg.com/k3d@${version}/dist/`,
            },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins: [new CopyPlugin({
            patterns: [
                { from: './src/core/lib/headless.html', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_standalone.txt', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_online.txt', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_inline.txt', to: `${__dirname}/../k3d/static` },
                { from: './node_modules/requirejs/require.js', to: `${__dirname}/../k3d/static` },
                { from: './node_modules/pako/dist/pako_inflate.min.js', to: `${__dirname}/../k3d/static` },
            ],
        })],
    },
    {
        entry: './src/standalone.js',
        output:
            {
                filename: 'standalone.js',
                path: `${__dirname}/dist/`,
                library: 'k3d',
                libraryTarget: 'amd',
                publicPath: `https://unpkg.com/k3d@${version}/dist/`,
            },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins,
    },
    { // Lab extension is just our JS source + shaders
        entry: './src/labplugin.js',
        output: {
            filename: 'labplugin.js',
            path: `${__dirname}/dist/`,
            libraryTarget: 'amd',
        },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        externals: [nodeExternals()],
    },
];
<commit_msg>new labels<commit_after>const nodeExternals = require('webpack-node-externals');
const CopyPlugin = require('copy-webpack-plugin');
const version = require('./package.json').version;
// var Visualizer = require('webpack-visualizer-plugin2');

// Custom webpack loaders are generally the same for all webpack bundles, hence
// stored in a separate local variable.
const rules = [
    {
        test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
        type: 'asset/inline',
    },
    {
        test: /\.(glsl|txt)/,
        type: 'asset/source',
    },
    {
        resourceQuery: /raw/,
        type: 'asset/source',
    },
];

const mode = 'production';

const plugins = [];

// plugins.push(new Visualizer({
//     filename: './webpack-statistics.html'
// }));

module.exports = [
    { // Notebook extension
        //
        // This bundle only contains the part of the JavaScript that is run on
        // load of the notebook. This section generally only performs
        // some configuration for requirejs, and provides the legacy
        // "load_ipython_extension" function which is required for any notebook
        // extension.
        //
        entry: './src/extension.js',
        output: {
            filename: 'extension.js',
            path: `${__dirname}/../k3d/static`,
            libraryTarget: 'amd',
        },
        module: {
            rules,
        },
        mode,
        plugins,
    },
    { // Bundle for the notebook containing the custom widget views and models
        //
        // This bundle contains the implementation for the custom widget views and
        // custom widget.
        // It must be an amd module
        //
        entry: './src/index.js',
        output: {
            filename: 'index.js',
            path: `${__dirname}/../k3d/static`,
            libraryTarget: 'amd',
        },
        mode,
        plugins,
        devtool: 'source-map',
        module: {
            rules,
        },
        externals: ['@jupyter-widgets/base'],
    },
    { // Embeddable K3D-jupyter bundle
        //
        // This bundle is generally almost identical to the notebook bundle
        // containing the custom widget views and models.
        //
        // The only difference is in the configuration of the webpack public path
        // for the static assets.
        //
        // It will be automatically distributed by unpkg to work with the static
        // widget embedder.
        //
        // The target bundle is always `dist/index.js`, which is the path required
        // by the custom widget embedder.
        //
        entry: './src/embed.js',
        output: {
            filename: 'index.js',
            path: `${__dirname}/dist/`,
            libraryTarget: 'amd',
            publicPath: `https://unpkg.com/k3d@${version}/dist/`,
        },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins,
        externals: ['@jupyter-widgets/base'],
    },
    {
        entry: './src/standalone.js',
        output:
            {
                filename: 'standalone.js',
                path: `${__dirname}/../k3d/static`,
                library: 'k3d',
                libraryTarget: 'amd',
                publicPath: `https://unpkg.com/k3d@${version}/dist/`,
            },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins: [new CopyPlugin({
            patterns: [
                { from: './src/core/lib/headless.html', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_standalone.txt', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_online.txt', to: `${__dirname}/../k3d/static` },
                { from: './src/core/lib/snapshot_inline.txt', to: `${__dirname}/../k3d/static` },
                { from: './node_modules/requirejs/require.js', to: `${__dirname}/../k3d/static` },
                { from: './node_modules/pako/dist/pako_inflate.min.js', to: `${__dirname}/../k3d/static` },
            ],
        })],
    },
    {
        entry: './src/standalone.js',
        output:
            {
                filename: 'standalone.js',
                path: `${__dirname}/dist/`,
                library: 'k3d',
                libraryTarget: 'amd',
                publicPath: `https://unpkg.com/k3d@${version}/dist/`,
            },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        plugins,
    },
    { // Lab extension is just our JS source + shaders
        entry: './src/labplugin.js',
        output: {
            filename: 'labplugin.js',
            path: `${__dirname}/dist/`,
            libraryTarget: 'amd',
        },
        mode,
        devtool: 'source-map',
        module: {
            rules,
        },
        externals: [nodeExternals()],
    },
];
<|endoftext|>


<commit_before>var loopback = require('loopback'),
    boot = require('loopback-boot'),
    expressWinston = require('express-winston'),
    logger = require('./logger');

console.info('Starting the application');

// Load the application
var app = module.exports = loopback();

app.use(expressWinston.logger({
  meta: app.get('env') === 'production' ? true : false,
  winstonInstance: logger,
  msg: 'HTTP {{req.method}} {{req.originalUrl}} {{res.statusCode}} {{res.responseTime}}ms',
  colorStatus: true
}));

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname);

app.start = function() {
  // start the web server
  return app.listen(process.env.PORT || 3000, function() {
    app.emit('started');
    console.info('Web server listening at: %s', app.get('url'));
  });
};

// start the server if `$ node server.js`
if (require.main === module || process.env.NODE_ENV === 'production') {
  app.start();
}
<commit_msg>Added a log message for when the server starts. This fixes #7<commit_after>var loopback = require('loopback'),
    boot = require('loopback-boot'),
    expressWinston = require('express-winston'),
    logger = require('./logger');

console.info('Starting the application');

// Load the application
var app = module.exports = loopback();

app.use(expressWinston.logger({
  meta: app.get('env') === 'production' ? true : false,
  winstonInstance: logger,
  msg: 'HTTP {{req.method}} {{req.originalUrl}} {{res.statusCode}} {{res.responseTime}}ms',
  colorStatus: true
}));

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname);

app.start = function() {
  // start the web server
  return app.listen(process.env.PORT || 3000, function() {
    app.emit('started');
    console.info('Application started');
    console.info('Web server listening at: %s', app.get('url'));
  });
};

// start the server if `$ node server.js`
if (require.main === module || process.env.NODE_ENV === 'production') {
  app.start();
}
<|endoftext|>


<commit_before>const express = require('express');
const path = require('path');
const compression = require('compression');
const morgan = require('morgan');
const analytics = require('universal-analytics');
// const expressGeoIP = require('express-geoip');

const app = express();

// Setup gzip
app.use(compression());

// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] :response-time ms ":method :url HTTP/:http-version" :status :res[content-length]'));

// Setup analytics
app.use(analytics.middleware('UA-3628636-11', {https: true}));

// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));

// Setup GEOID
// app.use(expressGeoIP('FI').getCountryCodeMiddleware);

// Always return the main index.html, so react-router render the route in the client
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
  req.visitor.pageview({
    dp: "/",
    dh: "https://kausi.xyz",
    dt: "Kausi",
    uip: req.ip,
    // geoid: req.countryCode,
  }).send();
});

module.exports = app;
<commit_msg>Fixes static resolving issue and geoip for analytics<commit_after>const express = require('express');
const path = require('path');
const compression = require('compression');
const morgan = require('morgan');
const analytics = require('universal-analytics');
const expressGeoIP = require('express-geoip');

const app = express();

// Enable trust
app.enable('trust proxy');

// Setup gzip
app.use(compression());

// Setup logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] :response-time ms ":method :url HTTP/:http-version" :status :res[content-length]'));

// Setup analytics
app.use(analytics.middleware('UA-3628636-11', {https: true}));

// Serve static assets
app.use("/static", express.static(path.resolve(__dirname, '..', 'build/static')));

// Setup GEOID
app.use(expressGeoIP('US').getCountryCodeMiddleware);

// Always return the main index.html, so react-router render the route in the client
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, '..', 'build', 'index.html'));
  req.visitor.pageview({
    dp: req.originalUrl,
    dh: "https://kausi.xyz",
    dt: "Kausi",
    uip: req.ip || undefined,
    geoid: req.countryCode || undefined,
  }).send();
});

module.exports = app;
<|endoftext|>