<commit_before>//Based almost entirely on "tcpslow" by llambda - https://github.com/llambda/tcpslow
//I just removed the "slow" parts and shoe-horned my code into the loop.
//
//Version History
// v1.0 - First public release
// v1.1 - Added perspective option, changed "-h" for host to "-s" for server to avoid collision wiht "-h" for help.

'use strict';

var net = require('net');
var chalk = require('chalk');
var path = require('path');
var program = require('commander');
var packagejson = require('./package.json');

var MainPlayerPacket = new Buffer(5);
MainPlayerPacket.writeUIntBE(0xf93d808001,0,5);
var PerspectivePacket = new Buffer(5);
PerspectivePacket.writeUIntBE(0xfec854f712,0,5);

var temp = Buffer(0);
var showInstead = 0;
var perspectiveInstead = -1;

program
.version(packagejson.version)
.option('-l, --listen [port]', 'TCP port to listen on', parseInt)
.option('-f, --forward [port]', 'TCP port to forward to (Optional, default is 2010)', parseInt)
.option('-v, --view [0-6]', 'What should the mainscreen show?\n                         0=Fore, 1=Port, 2=Starboard, 3=Aft, 4=Tactical,\n                         5=Long Range Sensors, and 6=Ship Status')
.option('-p, --perspective [1,3]', 'Force mainscreen perspective to 1st or 3rd person.\n                         NOTE: Must manually toggle perspective to force\n                         initial change. (Optional)')
.option('-s, --server [hostname]', 'IP or Hostname of the real Artemis Server.\n                         (Optional, default is \'localhost\')')
.parse(process.argv);

if (!program.listen) {
  console.error('Please specify listening port.');
  program.help();
}

if (!program.forward) {
  program.forward = 2010;
}

if (!program.view) {
  console.error('Please specify the desired view.');
  program.help();
}

function createConnection() {
  var conn;

  if (program.server || program.forward) {
    conn = {};
    conn.port = program.forward;
    if (program.server) {
      conn.host = program.server;
    } else {
      conn.host = 'localhost';
    }
    return net.createConnection(conn);
  }
}

function logSocketStatus(status, socket) {
  if (program.verbose) {
    console.log(new Date () + ' local: ' + socket.localAddress + ':' + socket.localPort
     + ' remote: ' + socket.remoteAddress + ':' + socket.remotePort + ' | ' + status);
  }
}

var server = net.createServer(function(listen) {
  logSocketStatus('(listening) client connected', listen);

  listen.forward = createConnection();
  listen.forward.on('connect', function() {

    logSocketStatus('(forwarding) client connected.', listen.forward);
  });
  listen.forward.on('data', function(data) {
    //MVM Lie Goes here.
    temp = data.slice(20,25);
    //console.log(temp);

    if (temp.equals(MainPlayerPacket)){
      var bufferIndex = unpackBitmap(data.slice(29,34), data);

      if (bufferIndex){
        //console.log('bitmap: ', data.slice(29,34));
        //console.log('Buffer Index: ', bufferIndex);
        console.log('Server Says the mainScreen view is: ', getPrettyView(data.readUInt8(bufferIndex)));
        data.writeUInt8(showInstead, bufferIndex);
        console.log('But we are sending: ', getPrettyView(data.readUInt8(bufferIndex)));
      };//End If bufferIndex
    }; //End if MainPlayerPacket

    //console.log(temp);

    if (temp.equals(PerspectivePacket) && perspectiveInstead != -1) {
        console.log('Server Says the mainScreen perspective is: ', getPrettyPerspective(data.readUInt8(28),1));
        data.writeUInt8(perspectiveInstead, 28);
        //console.log('Contents of Buffer: ', data);
        console.log('But we are sending: ', getPrettyPerspective(data.readUInt8(28),1));
    }; //End if PerspectivePacket

    if (program.packet) console.log(chalk.red(data))
      setTimeout(function() {
        listen.write(data);
      }, program.delay);
  });
  listen.forward.on('error', function(err) {
    // if (program.verbose) console.log(new Date() + ' (forwarding) error ' + err);
    logSocketStatus('(forwarding) error ' + err, listen.forward);
    listen.destroy();
  });
  listen.forward.on('end', function() {
    // if (program.verbose) console.log(new Date() + ' (forwarding) client end.');
    logSocketStatus('(forwarding) end ' , listen.forward);
    listen.end();
  });
  listen.forward.on('close', function(closed) {
    // if (program.verbose) console.log(new Date() + ' (forwarding) client close.');
    logSocketStatus('(forwarding) close ' , listen.forward);
    listen.end();
  })

  listen.on('data', function(data) {
    if (program.sending) {
      setTimeout(function() {
        listen.forward.write(data);
      }, program.delay);
    } else {
      listen.forward.write(data);
    }
    if (program.packet) console.log(chalk.blue(data));
  });
  listen.on('end', function() {
    logSocketStatus(' (listening) end ' , listen);
    listen.forward.end();
    listen.end();
  });
  listen.on('error', function(err) {
    logSocketStatus(' (listening) error ' , listen);
    listen.forward.destroy();
  });
  listen.on('close', function() {
    logSocketStatus(' (listening) close ' , listen);
    listen.forward.end();
  });
});

server.listen(program.listen ? program.listen : program.listenuds, function() {
  console.log('Mainscreen View Manager v' + packagejson.version);

  if (program.listen) {
    console.log('Listening on port ' + program.listen);
  };

  console.log('Relaying to ' + (program.server ? program.server + ' ' : '') + 'port ' + program.forward);

  showInstead = program.view;
  console.log('View will be set to: ', getPrettyView(showInstead));

  if (program.perspective) {
    perspectiveInstead = getPerspective(program.perspective);
    console.log('Perspective will be set to: ', getPrettyPerspective(program.perspective,0));
  };

  console.log('Use Control+C to quit.');
  });

function unpackBitmap(bufferSlice, buffer) { //Returns the number of bytes to skip.

//                0 1 2 3 4 5 6 7 8 9 10111213141516171819202122232425262728293031
var fieldBytes = [4,4,4,4,4,1,1,4,2,4,4,4,4,4,4,4,4,4,2,0,4,4,4,4,4,1,4,0,0,0,0,0]; //As of Artemis 2.1.5
var bitMapped = Array(40);
var bitmap = Array(5);
var runTot = 34; //Running Total of bytes we can skip.
var i = 0;
var byte = 0;
var bit = 0;

  for (i = 0; i < 4 ; i++) {
    bitmap[i] = bufferSlice.readUInt8(i);
  };
  for (byte = 0; byte < 4; byte++) {
    for (bit = 0; bit < 8; bit++) {
      bitMapped[(byte*8)+bit] = (bitmap[byte] >> (0+bit) & 1);
    }; //End For Bit
  }; //End For Byte

  if (!bitMapped[27]) return 0; //We can early exit if the update does not include the Mainscreen view.

  for (i=0;i<28;i++){ //Only need to look until we get to the item we want.
      if (i === 19 && bitMapped[i] === 1) {
        var strLen = (buffer.readUInt32LE(runTot)*2);
        //var str = buffer.toString('utf16le', runTot + 4, runTot + strLen + 2);
        //console.log('str: ', str);
        fieldBytes[i] = strLen + 4;
      };
      if (bitMapped[i]) {
        runTot += fieldBytes[i];
      };
  };
  return runTot;
}; //End Function

function getPrettyView(theView) {
  if (theView == 0) return 'Fore';
  if (theView == 1) return 'Port';
  if (theView == 2) return 'Starboard';
  if (theView == 3) return 'Aft';
  if (theView == 4) return 'Tactical';
  if (theView == 5) return 'LRS';
  if (theView == 6) return 'Status';
  return 'Out of Bounds';
}; //End Function

function getPerspective(thePerspective) {
  if (thePerspective == 1) return 0;
  if (thePerspective == 3) return 1;
}; //End getPerspective

function getPrettyPerspective(thePerspective, altMode) {
  if (thePerspective == 0) return '1st Person';
  if (altMode && thePerspective == 1) return '3rd person';
  if (thePerspective == 1) return '1st person';
  if (thePerspective == 3) return '3rd person';
  return 'Out of Bounds';
}//End getPrettyPerspective
<commit_msg>v1.1.2 Added rotation by 90º increments<commit_after>//Based almost entirely on "tcpslow" by llambda - https://github.com/llambda/tcpslow
//I just removed the "slow" parts and shoe-horned my code into the loop.
//
//Version History
// v1.0 - First public release
// v1.1 - Added perspective option, changed "-h" for host to "-s" for server to avoid collision wiht "-h" for help.
// v1.2 - Added "Dynamic" switching in 90º increments.

'use strict';

var net = require('net');
var chalk = require('chalk');
var path = require('path');
var program = require('commander');
var packagejson = require('./package.json');

var MainPlayerPacket = new Buffer(5);
MainPlayerPacket.writeUIntBE(0xf93d808001,0,5);
var PerspectivePacket = new Buffer(5);
PerspectivePacket.writeUIntBE(0xfec854f712,0,5);

var temp = Buffer(0);
var realMainScreenView = 0;
var viewTemp = 0;
var screenRotation = 0;
var viewArrayFore = [0,2,3,1]; //Because the order of the screens isn't layed out spatially we can't use simple math to determine the rotation. So rather than fuck around with lots of logic, I just pre-built these arrays.
var viewArrayPort = [1,0,2,3];
var viewArrayStar = [2,3,1,0];
var viewArrayAft = [3,1,0,2];
var showInstead = 0;
var perspectiveInstead = -1;

program
.version(packagejson.version)
.option('-l, --listen [port]', 'TCP port to listen on', parseInt)
.option('-f, --forward [port]', 'TCP port to forward to (Optional, default is\n                             2010)', parseInt)
.option('-v, --view [0-6,90,180,270]', 'What should the mainscreen show?\n                             0=Fore, 1=Port, 2=Starboard, 3=Aft, 4=Tactical\n                             5=Long Range Sensors, and 6=Ship Status\n                             90,180,270=Rotate by x Degrees from actual\n                             mainscreen view in 90º increments.')
.option('-p, --perspective [1,3]', 'Force mainscreen perspective to 1st or 3rd\n                             person. NOTE: Must manually toggle perspective\n                             to force initial change. (Optional)')
.option('-s, --server [hostname]', 'IP or Hostname of the real Artemis Server.\n                             (Optional, default is \'localhost\')')
.parse(process.argv);

if (!program.listen) {
  console.error('Please specify listening port.');
  program.help();
}

if (!program.forward) {
  program.forward = 2010;
}

if (!program.view) {
  console.error('Please specify the desired view.');
  program.help();
} else {
  if (program.view > 6) {
    if (program.view % 90 !== 0) {
      console.error('Please specify the view using 0-6 or a degree of rotation in increments of 90º.');
      program.help();
    }; //End If
  }; //End If
} //End If

function createConnection() {
  var conn;

  if (program.server || program.forward) {
    conn = {};
    conn.port = program.forward;
    if (program.server) {
      conn.host = program.server;
    } else {
      conn.host = 'localhost';
    }
    return net.createConnection(conn);
  }
}

function logSocketStatus(status, socket) {
  if (program.verbose) {
    console.log(new Date () + ' local: ' + socket.localAddress + ':' + socket.localPort
     + ' remote: ' + socket.remoteAddress + ':' + socket.remotePort + ' | ' + status);
  }
}

var server = net.createServer(function(listen) {
  logSocketStatus('(listening) client connected', listen);

  listen.forward = createConnection();
  listen.forward.on('connect', function() {

    logSocketStatus('(forwarding) client connected.', listen.forward);
  });
  listen.forward.on('data', function(data) {
    //MVM Lie Goes here.
    temp = data.slice(20,25);
    //console.log(temp);

    if (temp.equals(MainPlayerPacket)){
      var bufferIndex = unpackBitmap(data.slice(29,34), data);

      if (bufferIndex){
        //console.log('bitmap: ', data.slice(29,34));
        //console.log('Buffer Index: ', bufferIndex);
        realMainScreenView = data.readUInt8(bufferIndex);
        if (!screenRotation) {
          console.log('Server Says the mainScreen view is: ', getPrettyView(realMainScreenView));
          data.writeUInt8(showInstead, bufferIndex);
          console.log('But we are sending: ', getPrettyView(data.readUInt8(bufferIndex)));
        } else {
          console.log('Server Says the mainScreen view is: ', getPrettyView(realMainScreenView));
          viewTemp = getViewByDegrees(realMainScreenView, screenRotation);
          if (viewTemp !== -1) showInstead = viewTemp;
          data.writeUInt8(showInstead, bufferIndex);
          console.log('But we are dynamically rotating by', screenRotation, ' degrees and sending: ', getPrettyView(data.readUInt8(bufferIndex)));
        };
      };//End If bufferIndex
    }; //End if MainPlayerPacket

    //console.log(temp);

    if (temp.equals(PerspectivePacket) && perspectiveInstead != -1) {
        console.log('Server Says the mainScreen perspective is: ', getPrettyPerspective(data.readUInt8(28),1));
        data.writeUInt8(perspectiveInstead, 28);
        //console.log('Contents of Buffer: ', data);
        console.log('But we are sending: ', getPrettyPerspective(data.readUInt8(28),1));
    }; //End if PerspectivePacket

    if (program.packet) console.log(chalk.red(data))
      setTimeout(function() {
        listen.write(data);
      }, program.delay);
  });
  listen.forward.on('error', function(err) {
    // if (program.verbose) console.log(new Date() + ' (forwarding) error ' + err);
    logSocketStatus('(forwarding) error ' + err, listen.forward);
    listen.destroy();
  });
  listen.forward.on('end', function() {
    // if (program.verbose) console.log(new Date() + ' (forwarding) client end.');
    logSocketStatus('(forwarding) end ' , listen.forward);
    listen.end();
  });
  listen.forward.on('close', function(closed) {
    // if (program.verbose) console.log(new Date() + ' (forwarding) client close.');
    logSocketStatus('(forwarding) close ' , listen.forward);
    listen.end();
  })

  listen.on('data', function(data) {
    if (program.sending) {
      setTimeout(function() {
        listen.forward.write(data);
      }, program.delay);
    } else {
      listen.forward.write(data);
    }
    if (program.packet) console.log(chalk.blue(data));
  });
  listen.on('end', function() {
    logSocketStatus(' (listening) end ' , listen);
    listen.forward.end();
    listen.end();
  });
  listen.on('error', function(err) {
    logSocketStatus(' (listening) error ' , listen);
    listen.forward.destroy();
  });
  listen.on('close', function() {
    logSocketStatus(' (listening) close ' , listen);
    listen.forward.end();
  });
});

server.listen(program.listen ? program.listen : program.listenuds, function() {
  console.log('Mainscreen View Manager v' + packagejson.version);

  if (program.listen) {
    console.log('Listening on port ' + program.listen);
  };

  console.log('Relaying to ' + (program.server ? program.server + ' ' : '') + 'port ' + program.forward);

  if (program.view < 7) {
    showInstead = program.view;
    console.log('View will be set to: ', getPrettyView(showInstead));
  } else {
    screenRotation = program.view;
    showInstead = getViewByDegrees(0,screenRotation);//Default
    console.log('View will dynamically change to be', screenRotation, 'degrees clockwise from actual Mainscreen.');
  }

  if (program.perspective) {
    perspectiveInstead = getPerspective(program.perspective);
    console.log('Perspective will be set to: ', getPrettyPerspective(program.perspective,0));
  };

  console.log('Use Control+C to quit.');
  });

function unpackBitmap(bufferSlice, buffer) { //Returns the number of bytes to skip.

//                0 1 2 3 4 5 6 7 8 9 10111213141516171819202122232425262728293031
var fieldBytes = [4,4,4,4,4,1,1,4,2,4,4,4,4,4,4,4,4,4,2,0,4,4,4,4,4,1,4,0,0,0,0,0]; //As of Artemis 2.1.5
var bitMapped = Array(40);
var bitmap = Array(5);
var runTot = 34; //Running Total of bytes we can skip.
var i = 0;
var byte = 0;
var bit = 0;

  for (i = 0; i < 4 ; i++) {
    bitmap[i] = bufferSlice.readUInt8(i);
  };
  for (byte = 0; byte < 4; byte++) {
    for (bit = 0; bit < 8; bit++) {
      bitMapped[(byte*8)+bit] = (bitmap[byte] >> (0+bit) & 1);
    }; //End For Bit
  }; //End For Byte

  if (!bitMapped[27]) return 0; //We can early exit if the update does not include the Mainscreen view.

  for (i=0;i<28;i++){ //Only need to look until we get to the item we want.
      if (i === 19 && bitMapped[i] === 1) {
        var strLen = (buffer.readUInt32LE(runTot)*2);
        //var str = buffer.toString('utf16le', runTot + 4, runTot + strLen + 2);
        //console.log('str: ', str);
        fieldBytes[i] = strLen + 4;
      };
      if (bitMapped[i]) {
        runTot += fieldBytes[i];
      };
  };
  return runTot;
}; //End Function

function getPrettyView(theView) {
  if (theView == 0) return 'Fore';
  if (theView == 1) return 'Port';
  if (theView == 2) return 'Starboard';
  if (theView == 3) return 'Aft';
  if (theView == 4) return 'Tactical';
  if (theView == 5) return 'LRS';
  if (theView == 6) return 'Status';
  return 'Out of Bounds';
}; //End Function

function getPerspective(thePerspective) {
  if (thePerspective == 1) return 0;
  if (thePerspective == 3) return 1;
}; //End getPerspective

function getPrettyPerspective(thePerspective, altMode) {
  if (thePerspective == 0) return '1st Person';
  if (altMode && thePerspective == 1) return '3rd person';
  if (thePerspective == 1) return '1st person';
  if (thePerspective == 3) return '3rd person';
  return 'Out of Bounds';
}//End getPrettyPerspective

function getViewByDegrees(theRealView, theDegrees) {
  if (theRealView < 4) {
    switch(theRealView) {

      case 0: //Fore
        return viewArrayFore[theDegrees / 90];
        break;

      case 1: //Port
        return viewArrayPort[theDegrees / 90];
        break;

      case 2: //Starboard
        return viewArrayStar[theDegrees / 90];
        break;

      case 3: //Aft
        return viewArrayAft[theDegrees / 90];
        break;

      default:
        console.error('Somehow we didn\'t switch right in getViewByDegrees.');
        return -1;
        break;
    }//End Switch
  } else {
    return -1; //
  };
}//End getViewByDegrees
<|endoftext|>


<commit_before>module.exports = function(app, auth) {
  var moment = require('moment')
    , Location = require('../models/location')
    , Layer = require('../models/layer')
    , User = require('../models/user')
    , Feature = require('../models/feature')
    , access = require('../access')
    , generate_kml = require('../utilities/generate_kml')
    , async = require('async')
    , fs = require('fs-extra')
    , sys = require('sys')
    , exec = require('child_process').exec
    , toGeoJson = require('../utilities/togeojson')
    , DOMParser = require('xmldom').DOMParser;
  var p***REMOVED***port = auth.p***REMOVED***port;

// export locations into KML
  app.get(
    '/api/export',
    function(req, res) {

      var userLocations;
      var layerLookup = {};
      var featuresLookup = {};
      var usersLookup = {};

      var filterTime = req.query.time_filter;
      var filterExportLayers = req.query.export_layers;
      var filterFft = req.query.fft_layer;

      var currentDate = new Date();
      var currentTmpDir = "/tmp/mage-export-" + currentDate.getTime();

      if(!filterExportLayers && !filterFft) {
        return res.send(400, "Error.  Please Select Layer for Export.");
      }

      ////////////////////////////////////////////////////////////////////
      //DEFINE SERIES FUNCTIONS///////////////////////////////////////////
      ////////////////////////////////////////////////////////////////////
      var getLayers = function(done) {
        //get layers for lookup
        Layer.getLayers(function (err, layers) {
          if(err) {
            console.log(err);
            return done(err);
          }
          for (var i in layers) {
            //layerLookup[layers[i].id] = layers[i];
            var layer = layers[i];
            layerLookup[layer.id] = layer;
          }
          done();
        });
      }

      var getUsers = function(done) {
        //get users for lookup
        User.getUsers(function (users){
          for (var i in users) {
            var user = users[i];
            usersLookup[user._id] = user;
          }
          done();
        });
      }

      var getFeatures = function(done) {
        if(!filterExportLayers) {
          return done();
        }

        var exportLayerIds = filterExportLayers.split(',');
        async.each(exportLayerIds, function(id, done){
          layer = layerLookup[id];
          Feature.getFeatures(layer, {}, function(featureResponse) {
            if(featureResponse) {
              featuresLookup[id] = featureResponse;
              done();
            }
          });
        },
        function(){
          done();
        });
      }

      var getLocations = function(done) {
        Location.getLocationsWithFilters(req.user, filterTime, 100000, function(err, locationResponse) {
          if(err) {
            console.log(err);
            return done(err);
          }
          userLocations = locationResponse;
          done();
        });
      }

      var createStagingDirectory = function(done) {
        child = exec("mkdir -p " + currentTmpDir + "/icons", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var copyKmlIconsToStagingDirectory = function(done) {
        child = exec("cp -r public/img/kml-icons/*  " + currentTmpDir + "/icons", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var copyFeatureMediaAttachmentsToStagingDirectory = function(done) {

        console.log('Features Lookup: \n');

        Object.keys(featuresLookup).forEach(function(key) {

          var features = featuresLookup[key];

          for(var i = 0; i < features.length; i++) {
            var feature = features[i];
            var attachments = feature.attachments;
            if(attachments) {
              for(var j = 0; j < attachments.length; j++) {
                var attachment = attachments[j];

                //create the directories if needed
                child = exec('mkdir -p ' + currentTmpDir + '/files/' + attachment.relativePath, function (error, stdout, stderr) {
                  sys.print('stdout: ' + stdout);
                  sys.print('stderr: ' + stderr);
                  if (error !== null) {
                    console.log('exec error: ' + error);
                  }

                  //copy the file!
                  var srcFile = '/var/lib/mage/attachments' + attachment.relativePath;
                  var destFile = currentTmpDir + '/files/' + attachment.relativePath + '/' + attachment.name;
                  fs.copy(srcFile, destFile, function(err){
                    if(err) {
                      console.log('Unable to copy attachment. ' + err);
                    }
                  });

                });
              }
            }
          }
        });
        done();
      }

      var writeKmlFile = function(done) {
        var filename = "mage-export-" + currentDate.getTime() + ".kml"
        var stream = fs.createWriteStream(currentTmpDir + "/" + filename);
        stream.once('open', function(fd) {

          stream.write(generate_kml.generateKMLHeader());
          stream.write(generate_kml.generateKMLDocument());

          //writing requested feature layers
          if(filterExportLayers) {

            var exportLayerIds = filterExportLayers.split(',');
            for(var i in exportLayerIds) {

              var layerId = exportLayerIds[i];
              var layer = layerLookup[layerId];
              var features = featuresLookup[layerId];

              if(layer) {
                stream.write(generate_kml.generateKMLFolderStart(layer.name));
                for(var j in features) {
                  feature = features[j];
                  lon = feature.geometry.coordinates[0];
                  lat = feature.geometry.coordinates[1];
                  desc = feature.properties.TYPE;
                  attachments = feature.attachments;
                  stream.write(generate_kml.generatePlacemark(feature._id, feature.properties.TYPE, lon ,lat ,0, feature.properties, attachments));
                }
                stream.write(generate_kml.generateKMLFolderClose());
              }
            }
          }

          //writing requested FFT locations
          if(filterFft) {
            for(var i in userLocations) {
              var userLocation = userLocations[i];
              var user = usersLookup[userLocation.user];
              stream.write(generate_kml.generateKMLFolderStart('user: ' + user.username));
              for(var j in userLocation.locations) {
                var location = userLocation.locations[j];
                if(location) {
                  lon = location.geometry.coordinates[0];
                  lat = location.geometry.coordinates[1];
                  stream.write(generate_kml.generatePlacemark(user.username + "-p" + j, 'FFT' , lon ,lat ,0, location.properties));
                }
              }
              stream.write(generate_kml.generateKMLFolderClose());
            }
          }
          stream.write(generate_kml.generateKMLDocumentClose());
          stream.end(generate_kml.generateKMLClose(), function(err) {
            if(err) {
              console.log(err);
            }
            done();
          });
        });
      }

      //Known bug in Google Earth makes embedded images from a kmz file not render properly.  Treating
      //it as a zip file for now.
      var createKmz = function(done) {
        child = exec("zip -r " +
                     currentTmpDir + "/mage-export-" + currentDate.getTime() + ".zip " +
                     currentTmpDir + "/*", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var streamKmzFileToClient = function(err) {

        var filename = currentTmpDir + "/mage-export-" + currentDate.getTime() + ".zip";

        fs.exists(filename, function(exists) {
          if(!exists) {
            res.writeHead(404, {"Content-Type": "text/plain"});
            res.write("404 Not Found\n");
            res.close();
            return;
          }

          fs.readFile(filename, "binary", function(err, file) {
            if(err) {
              res.writeHead(500, {"Content-Type": "text/plain"});
              res.write(err + "\n");
              res.close();
              return;
            }

            res.writeHead(200,{"Content-Type": "application/octet-stream" ,
                               "Content-Disposition": "attachment; filename=mage-export-" + currentDate.getTime() + ".zip"});
            res.write(file,"binary");
            res.end();
          });
        });
      }
      ////////////////////////////////////////////////////////////////////
      //END DEFINE SERIES FUNCTIONS///////////////////////////////////////
      ////////////////////////////////////////////////////////////////////

      var seriesFunctions = [getLayers,
                             getUsers,
                             getFeatures,
                             getLocations,
                             createStagingDirectory,
                             copyKmlIconsToStagingDirectory,
                             copyFeatureMediaAttachmentsToStagingDirectory,
                             writeKmlFile,
                             createKmz];

      async.series(seriesFunctions,streamKmzFileToClient);

    }

  );

  app.get(
    '/api/import',
    function(req, res, next) {
      fs.readFile('/Users/newmanw/Downloads/sochi/doc.kml', 'utf8', function(err, data) {
        if (err) return next(err);

        var featureCollections = toGeoJson.kml(data);
        // TODO use async here to get rid of nested callbacks
        featureCollections.forEach(function(featureCollection) {
          var layer = {
            name: featureCollection.name,
            type: 'External'
          };
          Layer.create(layer, function(err, newLayer) {
            if (err) {
              console.log('error creating layer', err);
              return;
            }

            featureCollection.featureCollection.features.forEach(function(feature) {
              Feature.createGeoJsonFeature(newLayer, feature, function(err, newFeature) {
                if (err) next(err);
              });
            });
          });
        });

        fs.writeFileSync('/tmp/sochi.json', JSON.stringify(featureCollections, null, 4));
        // console.log("done wrinting");
        res.send(200);
      });
    }
  );

}<commit_msg>fixed bug where media attachments were not being copied to the correct mapping directory.<commit_after>module.exports = function(app, auth) {
  var moment = require('moment')
    , Location = require('../models/location')
    , Layer = require('../models/layer')
    , User = require('../models/user')
    , Feature = require('../models/feature')
    , access = require('../access')
    , generate_kml = require('../utilities/generate_kml')
    , async = require('async')
    , fs = require('fs-extra')
    , sys = require('sys')
    , exec = require('child_process').exec
    , toGeoJson = require('../utilities/togeojson')
    , DOMParser = require('xmldom').DOMParser;
  var p***REMOVED***port = auth.p***REMOVED***port;

// export locations into KML
  app.get(
    '/api/export',
    function(req, res) {

      var userLocations;
      var layerLookup = {};
      var featuresLookup = {};
      var usersLookup = {};

      var filterTime = req.query.time_filter;
      var filterExportLayers = req.query.export_layers;
      var filterFft = req.query.fft_layer;

      var currentDate = new Date();
      var currentTmpDir = "/tmp/mage-export-" + currentDate.getTime();

      if(!filterExportLayers && !filterFft) {
        return res.send(400, "Error.  Please Select Layer for Export.");
      }

      ////////////////////////////////////////////////////////////////////
      //DEFINE SERIES FUNCTIONS///////////////////////////////////////////
      ////////////////////////////////////////////////////////////////////
      var getLayers = function(done) {
        //get layers for lookup
        Layer.getLayers(function (err, layers) {
          if(err) {
            console.log(err);
            return done(err);
          }
          for (var i in layers) {
            //layerLookup[layers[i].id] = layers[i];
            var layer = layers[i];
            layerLookup[layer.id] = layer;
          }
          done();
        });
      }

      var getUsers = function(done) {
        //get users for lookup
        User.getUsers(function (users){
          for (var i in users) {
            var user = users[i];
            usersLookup[user._id] = user;
          }
          done();
        });
      }

      var getFeatures = function(done) {
        if(!filterExportLayers) {
          return done();
        }

        var exportLayerIds = filterExportLayers.split(',');
        async.each(exportLayerIds, function(id, done){
          layer = layerLookup[id];
          Feature.getFeatures(layer, {}, function(featureResponse) {
            if(featureResponse) {
              featuresLookup[id] = featureResponse;
              done();
            }
          });
        },
        function(){
          done();
        });
      }

      var getLocations = function(done) {
        Location.getLocationsWithFilters(req.user, filterTime, 100000, function(err, locationResponse) {
          if(err) {
            console.log(err);
            return done(err);
          }
          userLocations = locationResponse;
          done();
        });
      }

      var createStagingDirectory = function(done) {
        child = exec("mkdir -p " + currentTmpDir + "/icons", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var copyKmlIconsToStagingDirectory = function(done) {
        child = exec("cp -r public/img/kml-icons/*  " + currentTmpDir + "/icons", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var copyFeatureMediaAttachmentsToStagingDirectory = function(done) {

        console.log('Features Lookup: \n');

        Object.keys(featuresLookup).forEach(function(key) {

          var features = featuresLookup[key];

          for(var i = 0; i < features.length; i++) {
            var feature = features[i];
            var attachments = feature.attachments;
            if(attachments) {
              for(var j = 0; j < attachments.length; j++) {
                var attachment = attachments[j];

                //create the directories if needed
                child = exec('mkdir -p ' + currentTmpDir + '/files/' + attachment.relativePath, function (error, stdout, stderr) {
                  sys.print('stdout: ' + stdout);
                  sys.print('stderr: ' + stderr);
                  if (error !== null) {
                    console.log('exec error: ' + error);
                  }

                  //copy the file!
                  var srcFile = '/var/lib/mage/attachments/' + attachment.relativePath;
                  var destFile = currentTmpDir + '/files/' + attachment.relativePath + '/' + attachment.name;
                  fs.copy(srcFile, destFile, function(err){
                    if(err) {
                      console.log('Unable to copy attachment. ' + err);
                    }
                  });

                });
              }
            }
          }
        });
        done();
      }

      var writeKmlFile = function(done) {
        var filename = "mage-export-" + currentDate.getTime() + ".kml"
        var stream = fs.createWriteStream(currentTmpDir + "/" + filename);
        stream.once('open', function(fd) {

          stream.write(generate_kml.generateKMLHeader());
          stream.write(generate_kml.generateKMLDocument());

          //writing requested feature layers
          if(filterExportLayers) {

            var exportLayerIds = filterExportLayers.split(',');
            for(var i in exportLayerIds) {

              var layerId = exportLayerIds[i];
              var layer = layerLookup[layerId];
              var features = featuresLookup[layerId];

              if(layer) {
                stream.write(generate_kml.generateKMLFolderStart(layer.name));
                for(var j in features) {
                  feature = features[j];
                  lon = feature.geometry.coordinates[0];
                  lat = feature.geometry.coordinates[1];
                  desc = feature.properties.TYPE;
                  attachments = feature.attachments;
                  stream.write(generate_kml.generatePlacemark(feature._id, feature.properties.TYPE, lon ,lat ,0, feature.properties, attachments));
                }
                stream.write(generate_kml.generateKMLFolderClose());
              }
            }
          }

          //writing requested FFT locations
          if(filterFft) {
            for(var i in userLocations) {
              var userLocation = userLocations[i];
              var user = usersLookup[userLocation.user];
              stream.write(generate_kml.generateKMLFolderStart('user: ' + user.username));
              for(var j in userLocation.locations) {
                var location = userLocation.locations[j];
                if(location) {
                  lon = location.geometry.coordinates[0];
                  lat = location.geometry.coordinates[1];
                  stream.write(generate_kml.generatePlacemark(user.username + "-p" + j, 'FFT' , lon ,lat ,0, location.properties));
                }
              }
              stream.write(generate_kml.generateKMLFolderClose());
            }
          }
          stream.write(generate_kml.generateKMLDocumentClose());
          stream.end(generate_kml.generateKMLClose(), function(err) {
            if(err) {
              console.log(err);
            }
            done();
          });
        });
      }

      //Known bug in Google Earth makes embedded images from a kmz file not render properly.  Treating
      //it as a zip file for now.
      var createKmz = function(done) {
        child = exec("zip -r " +
                     currentTmpDir + "/mage-export-" + currentDate.getTime() + ".zip " +
                     currentTmpDir + "/*", function (error, stdout, stderr) {
          sys.print('stdout: ' + stdout);
          sys.print('stderr: ' + stderr);
          if (error !== null) {
            console.log('exec error: ' + error);
          }
          done();
        });
      }

      var streamKmzFileToClient = function(err) {

        var filename = currentTmpDir + "/mage-export-" + currentDate.getTime() + ".zip";

        fs.exists(filename, function(exists) {
          if(!exists) {
            res.writeHead(404, {"Content-Type": "text/plain"});
            res.write("404 Not Found\n");
            res.close();
            return;
          }

          fs.readFile(filename, "binary", function(err, file) {
            if(err) {
              res.writeHead(500, {"Content-Type": "text/plain"});
              res.write(err + "\n");
              res.close();
              return;
            }

            res.writeHead(200,{"Content-Type": "application/octet-stream" ,
                               "Content-Disposition": "attachment; filename=mage-export-" + currentDate.getTime() + ".zip"});
            res.write(file,"binary");
            res.end();
          });
        });
      }
      ////////////////////////////////////////////////////////////////////
      //END DEFINE SERIES FUNCTIONS///////////////////////////////////////
      ////////////////////////////////////////////////////////////////////

      var seriesFunctions = [getLayers,
                             getUsers,
                             getFeatures,
                             getLocations,
                             createStagingDirectory,
                             copyKmlIconsToStagingDirectory,
                             copyFeatureMediaAttachmentsToStagingDirectory,
                             writeKmlFile,
                             createKmz];

      async.series(seriesFunctions,streamKmzFileToClient);

    }

  );

  app.get(
    '/api/import',
    function(req, res, next) {
      fs.readFile('/Users/newmanw/Downloads/sochi/doc.kml', 'utf8', function(err, data) {
        if (err) return next(err);

        var featureCollections = toGeoJson.kml(data);
        // TODO use async here to get rid of nested callbacks
        featureCollections.forEach(function(featureCollection) {
          var layer = {
            name: featureCollection.name,
            type: 'External'
          };
          Layer.create(layer, function(err, newLayer) {
            if (err) {
              console.log('error creating layer', err);
              return;
            }

            featureCollection.featureCollection.features.forEach(function(feature) {
              Feature.createGeoJsonFeature(newLayer, feature, function(err, newFeature) {
                if (err) next(err);
              });
            });
          });
        });

        fs.writeFileSync('/tmp/sochi.json', JSON.stringify(featureCollections, null, 4));
        // console.log("done wrinting");
        res.send(200);
      });
    }
  );

}<|endoftext|>


<commit_before>var models = require('../models');

exports.login = function(req, res) {

  var fb_id = req.query.fb_id;
    if(fb_id != null){
      models.User.find({"fb_id": fb_id},
            function (err, user) {
              console.log(user);
              var first_name = req.query.fb_fname;
              var last_name = req.query.fb_lname;

              req.session.fb_id = fb_id;
              req.session.fname = first_name;
              req.session.lname = last_name;

              if(user.length == 0){

                var user = new models.User({
                      "fb_id": fb_id,
                      "email": "FB"+fb_id,
                      "password": "",
                      "first_name": first_name,
                      "last_name": last_name,
                      "school": "Stanford",
                      "year": "",
                      "major": "",
                      "dorm": "",
                      "gender": "N",
                      "courses": []
                });

                user.save(function (err, user) {
                    var input = {
                        "courses": []
                    }
                    res.render('home', input);
                })
                return;
              }

              console.log("FB Authentication Successful!");
              var dept_nums = user[0]["courses"]; //array of course dept_num

              all_courses = [];
              for (var i = 0; i < dept_nums.length; i++) {
                models.Course.find({"dept_num": dept_nums[i]},
                  function (err, course) {
                    all_courses.push(course[0]);
                  }
                );
              }

              var input = {
                "courses": all_courses
              };
              res.render('home', input);
            });
    }
}<commit_msg>fb.10<commit_after>var models = require('../models');

exports.login = function(req, res) {

  var fb_id = req.query.fb_id;
    if(fb_id != null){
      models.User.find({"fb_id": fb_id},
            function (err, user) {
              console.log(user);
              var first_name = req.query.fb_fname;
              var last_name = req.query.fb_lname;

              req.session.fb_id = fb_id;
              req.session.fname = first_name;
              req.session.lname = last_name;
              req.session.email = "FB" + fb_id;

              if(user.length == 0){

                var user = new models.User({
                      "fb_id": fb_id,
                      "email": "FB"+fb_id,
                      "password": "",
                      "first_name": first_name,
                      "last_name": last_name,
                      "school": "Stanford",
                      "year": "",
                      "major": "",
                      "dorm": "",
                      "gender": "N",
                      "courses": []
                });

                user.save(function (err, user) {
                    var input = {
                        "courses": []
                    }
                    res.render('home', input);
                })
                return;
              }

              console.log("FB Authentication Successful!");
              var dept_nums = user[0]["courses"]; //array of course dept_num

              all_courses = [];
              for (var i = 0; i < dept_nums.length; i++) {
                models.Course.find({"dept_num": dept_nums[i]},
                  function (err, course) {
                    all_courses.push(course[0]);
                  }
                );
              }

              var input = {
                "courses": all_courses
              };
              res.render('home', input);
            });
    }
}<|endoftext|>


<commit_before>function Map(tt, MapConfig) {
  var SELF = this;

  /** @type ThunderTanks */
  this.tt = tt;

  /** @type JSGameSoup */
  this.game = tt.game;

  // cached, fully rendered map
  var background_img = new Image();

  this.draw = function(c,gs) {
    c.drawImage(background_img, 0, 0);
  }

  this.init = function() {
    // add boundary boxes for collision detection
    this.tt.addObstacle(new Block(tt, -5, -100, this.game.width + 5, 100)); // top
    this.tt.addObstacle(new Block(tt, -5, this.game.height, this.game.width + 5, 100)); // bottom
    this.tt.addObstacle(new Block(tt, -100, -5, 100, this.game.height + 5)); // left
    this.tt.addObstacle(new Block(tt, this.game.width, -5, 100, this.game.height + 5)); // right

    // textures
    for(var i=0; i<MapConfig.Textures.length; i++) {
      this.tt.addObstacle(
        new Texture(tt,
                  MapConfig.Textures[i][0],
                  MapConfig.Textures[i][1],
                  MapConfig.Textures[i][2],
                  MapConfig.Textures[i][3],
                  MapConfig.Textures[i][4])
      );
    }

    // blocks
    for(var i=0; i<MapConfig.Blocks.length; i++) {
      this.tt.addObstacle(
        new Block(tt,
                  MapConfig.Blocks[i][0],
                  MapConfig.Blocks[i][1],
                  MapConfig.Blocks[i][2],
                  MapConfig.Blocks[i][3],
                  MapConfig.Blocks[i][4])
      );
    }

    // polygons
    for(var i=0; i<MapConfig.Polys.length; i++) {
      this.tt.addObstacle(
        new Poly(tt,MapConfig.Polys[i])
      );
    }

    // render full map in memory and store as an image
    var canvasCache = document.createElement('canvas');
    canvasCache.setAttribute('width',SELF.game.width);
    canvasCache.setAttribute('height',SELF.game.height);
    var ccCtx = canvasCache.getContext('2d');

    var mapGraphics = tt.getObstacles();
    for (var i = 0; i<mapGraphics.length; i++) {
      mapGraphics[i]._draw(ccCtx);
    }
    background_img.src = canvasCache.toDataURL("image/png");

  }
}

function Texture(tt, x, y, w, h, img) {

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.fillStyle = c.createPattern(img,'repeat');
    c.fillRect(x,y,w,h);
  }
}

function Block(tt, x, y, w, h, img) {
  var SELF = this;

  var _private = {
      leftX: x,
      topY: y,
      width: w,
      height: h,
      poly: [
        [x,y],
        [x+w,y],
        [x+w,y+h],
        [x,y+h]
      ],
      imgCache: new Image()
  }

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.drawImage(_private.imgCache, _private.leftX, _private.topY);
  }

  /** @returns {Array}  A rectangle of the boundaries of the entity with the form [x, y, w, h] */
  this.get_collision_aabb = function() {
    return [_private.leftX,_private.topY,_private.width,_private.height];
  }

  /** @returns {Array}  The center of the circle and the radius like this: return [[x, y], r] */
  this.get_collision_circle = function() {
    var aSqrd = (_private.length*_private.height)/4;
    var bSqrd = (_private.width*_private.width)/4;
    // equals c squared
    var radius = Math.sqrt(aSqrd+bSqrd);
    return [[_private.leftx,_private.topY], radius];
  }

  /** @returns {Array}  An array of lines of the form [[x1, y1], [x2, y2], ... [xn, yn]] */
  this.get_collision_poly = function() {
    return _private.poly;
  };

  (function() {
    // render full map in memory and store as an image
    var canvasCache = document.createElement('canvas');
    canvasCache.setAttribute('width',_private.width);
    canvasCache.setAttribute('height',_private.height);
    var ccCtx = canvasCache.getContext('2d');

    // draw block
    ccCtx.fillStyle = img ? ccCtx.createPattern(img,'repeat') : 'rgba(200, 200, 200, 1.0)';
    ccCtx.fillRect(0,0,_private.width,_private.height);

    _private.imgCache.src = canvasCache.toDataURL("image/png");
  })();
}

function Poly(tt, points) {
  var SELF = this;

  var minX = points[0][0];
  var minY = points[0][1];
  var maxX = points[0][0];
  var maxY = points[0][1];

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.strokeStyle = '#000000';
    c.fillStyle = c.createPattern(grey1,'repeat');

    c.beginPath();
    c.moveTo(points[0][0],points[0][1]);
    for(var p = 1; p < points.length; p++) {
      c.lineTo(points[p][0],points[p][1]);
    }
    c.closePath();
    c.stroke();
    c.fill();
  }

  /** @returns {Array}  A rectangle of the boundaries of the entity with the form [x, y, w, h] */
  this.get_collision_aabb = function() {
    return [minX, minY, maxX - minX, maxY - minY];
  }

  /** @returns {Array}  The center of the circle and the radius like this: return [[x, y], r] */
  this.get_collision_circle = function() {
    console.log('Poly get_collision_circle not implemented yet');
  }

  /** @returns {Array}  An array of lines of the form [[x1, y1], [x2, y2], ... [xn, yn]] */
  this.get_collision_poly = function() {
    return points;
  };

  (function() {
    for(var p = 1; p < points.length; p++) {
      minX = Math.min(minX, points[p][0]);
      minY = Math.min(minY, points[p][1]);
      maxX = Math.max(maxX, points[p][0]);
      maxY = Math.max(maxY, points[p][1]);
    }
  })();
}<commit_msg>added Line entity (for debugging stuff)<commit_after>function Map(tt, MapConfig) {
  var SELF = this;

  /** @type ThunderTanks */
  this.tt = tt;

  /** @type JSGameSoup */
  this.game = tt.game;

  // cached, fully rendered map
  var background_img = new Image();

  this.draw = function(c,gs) {
    c.drawImage(background_img, 0, 0);
  }

  this.init = function() {
    // add boundary boxes for collision detection
    this.tt.addObstacle(new Block(tt, -5, -100, this.game.width + 5, 100)); // top
    this.tt.addObstacle(new Block(tt, -5, this.game.height, this.game.width + 5, 100)); // bottom
    this.tt.addObstacle(new Block(tt, -100, -5, 100, this.game.height + 5)); // left
    this.tt.addObstacle(new Block(tt, this.game.width, -5, 100, this.game.height + 5)); // right

    // textures
    for(var i=0; i<MapConfig.Textures.length; i++) {
      this.tt.addObstacle(
        new Texture(tt,
                  MapConfig.Textures[i][0],
                  MapConfig.Textures[i][1],
                  MapConfig.Textures[i][2],
                  MapConfig.Textures[i][3],
                  MapConfig.Textures[i][4])
      );
    }

    // blocks
    for(var i=0; i<MapConfig.Blocks.length; i++) {
      this.tt.addObstacle(
        new Block(tt,
                  MapConfig.Blocks[i][0],
                  MapConfig.Blocks[i][1],
                  MapConfig.Blocks[i][2],
                  MapConfig.Blocks[i][3],
                  MapConfig.Blocks[i][4])
      );
    }

    // polygons
    for(var i=0; i<MapConfig.Polys.length; i++) {
      this.tt.addObstacle(
        new Poly(tt,MapConfig.Polys[i])
      );
    }

    // render full map in memory and store as an image
    var canvasCache = document.createElement('canvas');
    canvasCache.setAttribute('width',SELF.game.width);
    canvasCache.setAttribute('height',SELF.game.height);
    var ccCtx = canvasCache.getContext('2d');

    var mapGraphics = tt.getObstacles();
    for (var i = 0; i<mapGraphics.length; i++) {
      mapGraphics[i]._draw(ccCtx);
    }
    background_img.src = canvasCache.toDataURL("image/png");

  }
}

function Texture(tt, x, y, w, h, img) {

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.fillStyle = c.createPattern(img,'repeat');
    c.fillRect(x,y,w,h);
  }
}

/** used for debugging */
function Line(point1, point2) {

  this.draw = function(c, gs) {
    this._draw(c);
  }

  this._draw = function(c) {
    c.strokeStyle = '#ff00ff';
    c.beginPath();
    c.moveTo(point1[0],point1[1]);
    c.lineTo(point2[0],point2[1]);
    c.stroke();

    // p1 circle
    c.beginPath();
    c.strokeStyle = "#000000";
    c.arc(point1[0], point1[1], 10, 0, 2 * Math.PI, false);
    c.stroke();

    //// p2 circle
    //c.beginPath();
    //c.strokeStyle = "#ffffff";
    //c.arc(point2[0], point2[1], 10, 0, 2 * Math.PI, false);
    //c.stroke();
  }
}

function Block(tt, x, y, w, h, img) {
  var SELF = this;

  var _private = {
      leftX: x,
      topY: y,
      width: w,
      height: h,
      poly: [
        [x,y],
        [x+w,y],
        [x+w,y+h],
        [x,y+h]
      ],
      imgCache: new Image()
  }

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.drawImage(_private.imgCache, _private.leftX, _private.topY);
  }

  /** @returns {Array}  A rectangle of the boundaries of the entity with the form [x, y, w, h] */
  this.get_collision_aabb = function() {
    return [_private.leftX,_private.topY,_private.width,_private.height];
  }

  /** @returns {Array}  The center of the circle and the radius like this: return [[x, y], r] */
  this.get_collision_circle = function() {
    var aSqrd = (_private.length*_private.height)/4;
    var bSqrd = (_private.width*_private.width)/4;
    // equals c squared
    var radius = Math.sqrt(aSqrd+bSqrd);
    return [[_private.leftx,_private.topY], radius];
  }

  /** @returns {Array}  An array of lines of the form [[x1, y1], [x2, y2], ... [xn, yn]] */
  this.get_collision_poly = function() {
    return _private.poly;
  };

  (function() {
    // render full map in memory and store as an image
    var canvasCache = document.createElement('canvas');
    canvasCache.setAttribute('width',_private.width);
    canvasCache.setAttribute('height',_private.height);
    var ccCtx = canvasCache.getContext('2d');

    // draw block
    ccCtx.fillStyle = img ? ccCtx.createPattern(img,'repeat') : 'rgba(200, 200, 200, 1.0)';
    ccCtx.fillRect(0,0,_private.width,_private.height);

    _private.imgCache.src = canvasCache.toDataURL("image/png");
  })();
}

function Poly(tt, points) {
  var SELF = this;

  var minX = points[0][0];
  var minY = points[0][1];
  var maxX = points[0][0];
  var maxY = points[0][1];

  //this.draw = function(c, gs) {
  //  this._draw(c);
  //}

  this._draw = function(c) {
    c.strokeStyle = '#000000';
    c.fillStyle = c.createPattern(grey1,'repeat');

    c.beginPath();
    c.moveTo(points[0][0],points[0][1]);
    for(var p = 1; p < points.length; p++) {
      c.lineTo(points[p][0],points[p][1]);
    }
    c.closePath();
    c.stroke();
    c.fill();
  }

  /** @returns {Array}  A rectangle of the boundaries of the entity with the form [x, y, w, h] */
  this.get_collision_aabb = function() {
    return [minX, minY, maxX - minX, maxY - minY];
  }

  /** @returns {Array}  The center of the circle and the radius like this: return [[x, y], r] */
  this.get_collision_circle = function() {
    console.log('Poly get_collision_circle not implemented yet');
  }

  /** @returns {Array}  An array of lines of the form [[x1, y1], [x2, y2], ... [xn, yn]] */
  this.get_collision_poly = function() {
    return points;
  };

  (function() {
    for(var p = 1; p < points.length; p++) {
      minX = Math.min(minX, points[p][0]);
      minY = Math.min(minY, points[p][1]);
      maxX = Math.max(maxX, points[p][0]);
      maxY = Math.max(maxY, points[p][1]);
    }
  })();
}<|endoftext|>


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

var Votes = require('../models/Votes');
var Subscriber = require('../models/Subscriber');

// Handle SMS submissions
module.exports = function(request, response) {

    var phone = request.body.From;

    // respond with message TwiML content
    function respond(message) {
        var twiml = new twilio.TwimlResponse();
        twiml.message(message);
        response.type('text/xml');
        response.send(twiml.toString());
    }

    function addVote(teamNumber) {

        console.log('adding a vote for team ' + teamNumber);

        Votes.findOne({
            teamNumber: teamNumber
        }, function(err, team) {
            if (err) return respond('Derp! Technical issue updating vote count');

            if (!team) {
                // We're signed up but not subscribed - prompt to subscribe
                respond('Team ' + teamNumber + ' does not exist');
            } else {
                team.votes = team.votes + 1;
                team.save(function(err) {
                    if (err)
                        return respond('Derp! Technical issue updating vote count');
                });

            }
        });
    }

    function subtractVote(teamNumber, tt, cb) {

        console.log('subtracting a vote from team ' + teamNumber);

        Votes.findOne({
            teamNumber: teamNumber
        }, function(err, team) {
            if (err) return respond('Derp! Technical issue updating vote count');

            if (!team) {
                // We're signed up but not subscribed - prompt to subscribe
                respond('Team ' + teamNumber + ' does not exist');
            } else {
                team.votes = team.votes - 1;
                team.save(function(err) {
                    if (err)
                        return respond('Derp! Technical issue updating vote count');

                    cb(tt);
                });
            }
        });
    }

    // Try to find a subscriber with the given phone number
    Subscriber.findOne({
        phone: phone
    }, function(err, sub) {
        if (err) return respond('Derp! Please text back again later.');

        if (!sub) {

            var teamNumber = getTeamNumber();

            if (teamNumber === 0) {
                return respond('Please tell us which team number you liked the most');
            }

            if (teamNumber > 10) {
                return respond('Try again! Team number ' + teamNumber + ' is not valid');
            }

            // If there's no subscriber associated with this phone number,
            // create one
            var newSubscriber = new Subscriber({
                phone: phone,
                vote: teamNumber,
                body: request.body.Body
            });

            newSubscriber.save(function(err, newSub) {
                if (err || !newSub)
                    return respond('We couldn\'t sign you up - try again.');

                addVote(teamNumber);
                var responseMessage = 'Team ' + teamNumber + ' thanks you for voting!';
                respond(responseMessage);
            });
        } else {
            // repeat vote from the same number
            processMessage(sub);
        }
    });

    // Process any message the user sent to us
    function processMessage(subscriber) {

        var currentVote = subscriber.vote;
        console.log('currentVote = ' + currentVote);

        var teamNumber = getTeamNumber();
        console.log('processMessage: teamNumber = ' + teamNumber);

        if (teamNumber == 0) {
            var responseMessage = 'Try again - please tell us the team number you want to vote for';
            return respond(responseMessage);
        }

        // save the entire message body for later use
        subscriber.body = request.body.Body;
        subscriber.vote = teamNumber;
        subscriber.save(function(err) {
            if (err)
                return respond('We could not cast your vote - please try again');

            // TODO: Update the team collection
            if (currentVote != teamNumber) {
                subtractVote(currentVote, teamNumber, addVote);
                // subtractVote(currentVote);
                // addVote(teamNumber);
            }

            // Otherwise, our subscription has been updated
            var responseMessage = 'Team ' + teamNumber + ' thanks you for voting!';
            respond(responseMessage);
        });
    }

    function getTeamNumber() {
        // get the text message command sent by the user
        var msg = request.body.Body || '';
        msg = msg.toLowerCase().trim();

        var allTheNumbers;
        var temp = msg.match(/^\d+|\d+\b|\d+(?=\w)/g);
        // console.log('temp = ' + temp);

        if (temp === null && typeof temp === "object") {
            return 0;
        } else {
            allTheNumbers = temp.map(function (v) {return +v;});
            // console.log('allTheNumbers = ' + allTheNumbers);
        }

        // console.log('first number found was ' + allTheNumbers[0]);
        return allTheNumbers[0];
    }

};<commit_msg>better logic on when to do nothing<commit_after>var twilio = require('twilio');

var Votes = require('../models/Votes');
var Subscriber = require('../models/Subscriber');

// Handle SMS submissions
module.exports = function(request, response) {

    var phone = request.body.From;

    // respond with message TwiML content
    function respond(message) {
        var twiml = new twilio.TwimlResponse();
        twiml.message(message);
        response.type('text/xml');
        response.send(twiml.toString());
    }

    function addVote(teamNumber) {

        console.log('adding a vote for team ' + teamNumber);

        Votes.findOne({
            teamNumber: teamNumber
        }, function(err, team) {
            if (err) return respond('Derp! Technical issue updating vote count');

            if (!team) {
                // We're signed up but not subscribed - prompt to subscribe
                respond('Team ' + teamNumber + ' does not exist');
            } else {
                team.votes = team.votes + 1;
                team.save(function(err) {
                    if (err)
                        return respond('Derp! Technical issue updating vote count');
                });

            }
        });
    }

    function subtractVote(teamNumber, tt, cb) {

        console.log('subtracting a vote from team ' + teamNumber);

        Votes.findOne({
            teamNumber: teamNumber
        }, function(err, team) {
            if (err) return respond('Derp! Technical issue updating vote count');

            if (!team) {
                // We're signed up but not subscribed - prompt to subscribe
                respond('Team ' + teamNumber + ' does not exist');
            } else {
                team.votes = team.votes - 1;
                team.save(function(err) {
                    if (err)
                        return respond('Derp! Technical issue updating vote count');

                    cb(tt);
                });
            }
        });
    }

    // Try to find a subscriber with the given phone number
    Subscriber.findOne({
        phone: phone
    }, function(err, sub) {
        if (err) return respond('Derp! Please text back again later.');

        // Parse the team number from the message body (the first number we find)
        var teamNumber = getTeamNumber();

        if (teamNumber === 0) {
            return respond('Please tell us which team number you liked the most');
        }

        if (teamNumber > 10) {
            return respond('Try again! Team number ' + teamNumber + ' is not valid');
        }

        if (!sub) {

            // If there's no subscriber associated with this phone number,
            // create one
            var newSubscriber = new Subscriber({
                phone: phone,
                vote: teamNumber,
                body: request.body.Body
            });

            newSubscriber.save(function(err, newSub) {
                if (err || !newSub)
                    return respond('We couldn\'t sign you up - try again.');

                addVote(teamNumber);
                var responseMessage = 'Team ' + teamNumber + ' thanks you for voting!';
                respond(responseMessage);
            });
        } else {
            // repeat vote from the same number
            processMessage(sub);
        }
    });

    // Process any message the user sent to us
    function processMessage(subscriber) {

        var currentVote = subscriber.vote;
        console.log('processMessage: currentVote = ' + currentVote);

        var teamNumber = getTeamNumber();
        console.log('processMessage:     newVote = ' + teamNumber);

        // save the entire message body for later use
        subscriber.body = request.body.Body;
        subscriber.vote = teamNumber;
        subscriber.save(function(err) {
            if (err)
                return respond('We could not cast your vote - please try again');

            // TODO: Update the team collection
            if (currentVote != teamNumber) {
                subtractVote(currentVote, teamNumber, addVote);
                // subtractVote(currentVote);
                // addVote(teamNumber);
            }

            // Otherwise, our subscription has been updated
            var responseMessage = 'Team ' + teamNumber + ' thanks you for voting!';
            respond(responseMessage);
        });
    }

    function getTeamNumber() {
        // get the text message command sent by the user
        var msg = request.body.Body || '';
        msg = msg.toLowerCase().trim();

        var allTheNumbers;
        var temp = msg.match(/^\d+|\d+\b|\d+(?=\w)/g);
        // console.log('temp = ' + temp);

        if (temp === null && typeof temp === "object") {
            return 0;
        } else {
            allTheNumbers = temp.map(function (v) {return +v;});
            // console.log('allTheNumbers = ' + allTheNumbers);
        }

        // console.log('first number found was ' + allTheNumbers[0]);
        return allTheNumbers[0];
    }

};<|endoftext|>


<commit_before>/*
  bkjs: Ben Kinsey's Javascript Framework
  Copyright (C) 2011 Ben Kinsey
  AGPLv3 (or higher) License.  Other licenses available for a small fee.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
var Nav = Class.extend({
  init : function( nav_object, home_url ) {
    this.nav_object = nav_object;
    this.home_url = '';
    if (home_url) this.home_url = home_url;
    if (! this.browser_supports_pushState() && ! location.hash) {
      window.location = this.home_url + '/#!' + location.pathname;
    }
    this.previous_href = window.location.href;
    this.set_pathname();
    document.title = this.get_title();

    var self = this;
    window.onpopstate = function() { self.set_previous_and_update_to_url(); };
    window.onpushstate = function() { self.set_previous_and_update_to_url(); };
    $(window).hashchange( function() { self.detect_href_change(); } );
  },
  set_previous_and_update_to_url : function() {
    this.previous_href = window.location.href;
    this.update_to_url();
  },
  detect_href_change : function () {
    if (window.location.href != this.previous_href) {
      this.set_previous_and_update_to_url();
    }
  },
  update_to_url : function( url ) {
    this.set_pathname( this.strip_home_url( url ) );
    document.title = this.get_title();
    if (this.update_callback) {
      this.update_callback();
    }
  },
  set_update_callback : function( update_callback ) {
    this.update_callback = update_callback;
  },
  set_pathname : function( url ) {
    if (url) {
      this.pathname = url;
      return;
    }
    if (location.hash && location.pathname == this.home_url + '/') {
      this.pathname = location.hash.substring( 2 );
    } else {
      this.pathname = this.strip_home_url( location.pathname );
    }
  },
  strip_home_url : function( url ) {
    if (! url) return;

    if (url.indexOf( this.home_url ) == 0) {
      return url.substring( this.home_url.length );
    }
    return url;
  },
  get_title : function() {
    return this.get_title_by_url( this.pathname );
  },
  get_title_by_url : function ( url ) {
    if (!url) return this.nav_object['/'];
    if (this.nav_object[url]) return this.nav_object[url];
    var level = this.get_level_by_url( url );
    if (level < 1) return this.nav_object['/'];
    url = this.get_url_by_level( level - 1 );
    return this.get_title_by_url( url );
  },
  get_level : function() {
    return this.get_level_by_url( this.pathname );
  },
  get_level_by_url : function( url ) {
    if (url == '/') return 0;
    return url.split('/').length - 1;
  },
  get_url_by_level : function ( level ) {
    if ( level == 0 ) return '/';
    var pathname_array = this.pathname.split('/');
    var url = '';
    level++;

    if (level > pathname_array.length) level = pathname_array.length;
    for (var i = 0; i < level; i++) {
      if (i != 0) url += '/';
      url += pathname_array[i];
    }
    return url;
  },
  get_title_by_level : function ( level ) {
    var url = this.get_url_by_level( level );
    return this.get_title_by_url( url );
  },
  url_exists : function( url ) {
    if (this.nav_object[url]) return true;
    return false;
  },
  get_urls_by_level : function( level ) {
    var urls_at_level = {};

    for (var url in this.nav_object) {
      if (this.get_level_by_url( url ) == level) {
        urls_at_level[url] = this.nav_object[url];
      }
    }
    return urls_at_level;
  },
  url_in_url : function( needle_url, haystack_url ) {
    if (needle_url == '/') return true;
    var needle_url_array = needle_url.split('/');
    var needle_url_array_length = needle_url_array.length;
    var haystack_url_array = haystack_url.split('/');
    var haystack_url_array_length = haystack_url_array.length;
    if (needle_url_array_length > haystack_url_array_length) return false;

    for (var i = 0; i < needle_url_array_length; i++) {
      if (needle_url_array[i] != haystack_url_array[i]) return false;
    }
    return true;
  },
  get_url_children : function( url ) {
    var url_children = {};
    var url_array = url.split('/');
    var url_level = this.get_level_by_url( url );

    for (var nav_url in this.nav_object) {
      var nav_url_array = nav_url.split('/');
      var nav_url_level = this.get_level_by_url( nav_url );
      if (nav_url_level != url_level + 1) continue;
      if (! this.url_in_url( url, nav_url )) continue;
      url_children[nav_url] = this.nav_object[nav_url];
    }

    return url_children;
  },
  change_url : function( url ) {
    var stateObj = { foo: "bar" };
    if (! url) url = '/';
    var new_url = this.home_url + url;
    var new_href = location.protocol + "//" + location.hostname + new_url;
    if (location.href == new_href) return;

    if (this.browser_supports_pushState()) {
      this.previous_href = window.location.href;
      history.pushState( stateObj, null, new_url );
      if (this.previous_href != window.location.href) {
	this.update_to_url( new_url );
      }
    } else {
      window.location.href = this.home_url + '/#!' + url;
    }
    return;
  },
  browser_supports_pushState : function() {
    return !(typeof history.pushState === 'undefined');
  }
});<commit_msg>trust that hashchange event actually works<commit_after>/*
  bkjs: Ben Kinsey's Javascript Framework
  Copyright (C) 2011 Ben Kinsey
  AGPLv3 (or higher) License.  Other licenses available for a small fee.

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU Affero General Public License as
  published by the Free Software Foundation, either version 3 of the
  License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
var Nav = Class.extend({
  init : function( nav_object, home_url ) {
    this.nav_object = nav_object;
    this.home_url = '';
    if (home_url) this.home_url = home_url;
    if (! this.browser_supports_pushState() && ! location.hash) {
      window.location = this.home_url + '/#!' + location.pathname;
    }
    this.previous_href = window.location.href;
    this.set_pathname();
    document.title = this.get_title();

    var self = this;
    window.onpopstate = function() { self.set_prev_and_update_to_url(); };
    window.onpushstate = function() { self.set_prev_and_update_to_url(); };
    $(window).hashchange( function() { self.set_prev_and_update_to_url() } );
  },
  set_prev_and_update_to_url : function() {
    this.previous_href = window.location.href;
    this.update_to_url();
  },
  update_to_url : function( url ) {
    this.set_pathname( this.strip_home_url( url ) );
    document.title = this.get_title();
    if (this.update_callback) {
      this.update_callback();
    }
  },
  set_update_callback : function( update_callback ) {
    this.update_callback = update_callback;
  },
  set_pathname : function( url ) {
    if (url) {
      this.pathname = url;
      return;
    }
    if (location.hash && location.pathname == this.home_url + '/') {
      this.pathname = location.hash.substring( 2 );
    } else {
      this.pathname = this.strip_home_url( location.pathname );
    }
  },
  strip_home_url : function( url ) {
    if (! url) return;

    if (url.indexOf( this.home_url ) == 0) {
      return url.substring( this.home_url.length );
    }
    return url;
  },
  get_title : function() {
    return this.get_title_by_url( this.pathname );
  },
  get_title_by_url : function ( url ) {
    if (!url) return this.nav_object['/'];
    if (this.nav_object[url]) return this.nav_object[url];
    var level = this.get_level_by_url( url );
    if (level < 1) return this.nav_object['/'];
    url = this.get_url_by_level( level - 1 );
    return this.get_title_by_url( url );
  },
  get_level : function() {
    return this.get_level_by_url( this.pathname );
  },
  get_level_by_url : function( url ) {
    if (url == '/') return 0;
    return url.split('/').length - 1;
  },
  get_url_by_level : function ( level ) {
    if ( level == 0 ) return '/';
    var pathname_array = this.pathname.split('/');
    var url = '';
    level++;

    if (level > pathname_array.length) level = pathname_array.length;
    for (var i = 0; i < level; i++) {
      if (i != 0) url += '/';
      url += pathname_array[i];
    }
    return url;
  },
  get_title_by_level : function ( level ) {
    var url = this.get_url_by_level( level );
    return this.get_title_by_url( url );
  },
  url_exists : function( url ) {
    if (this.nav_object[url]) return true;
    return false;
  },
  get_urls_by_level : function( level ) {
    var urls_at_level = {};

    for (var url in this.nav_object) {
      if (this.get_level_by_url( url ) == level) {
        urls_at_level[url] = this.nav_object[url];
      }
    }
    return urls_at_level;
  },
  url_in_url : function( needle_url, haystack_url ) {
    if (needle_url == '/') return true;
    var needle_url_array = needle_url.split('/');
    var needle_url_array_length = needle_url_array.length;
    var haystack_url_array = haystack_url.split('/');
    var haystack_url_array_length = haystack_url_array.length;
    if (needle_url_array_length > haystack_url_array_length) return false;

    for (var i = 0; i < needle_url_array_length; i++) {
      if (needle_url_array[i] != haystack_url_array[i]) return false;
    }
    return true;
  },
  get_url_children : function( url ) {
    var url_children = {};
    var url_array = url.split('/');
    var url_level = this.get_level_by_url( url );

    for (var nav_url in this.nav_object) {
      var nav_url_array = nav_url.split('/');
      var nav_url_level = this.get_level_by_url( nav_url );
      if (nav_url_level != url_level + 1) continue;
      if (! this.url_in_url( url, nav_url )) continue;
      url_children[nav_url] = this.nav_object[nav_url];
    }

    return url_children;
  },
  change_url : function( url ) {
    var stateObj = { foo: "bar" };
    if (! url) url = '/';
    var new_url = this.home_url + url;
    var new_href = location.protocol + "//" + location.hostname + new_url;
    if (location.href == new_href) return;

    if (this.browser_supports_pushState()) {
      this.previous_href = window.location.href;
      history.pushState( stateObj, null, new_url );
      if (this.previous_href != window.location.href) {
	this.update_to_url( new_url );
      }
    } else {
      window.location.href = this.home_url + '/#!' + url;
    }
    return;
  },
  browser_supports_pushState : function() {
    return !(typeof history.pushState === 'undefined');
  }
});<|endoftext|>


<commit_before>var models = require('../models.js');

exports.view = function(req, res){
  var momentsID = req.params.id;

  models.Moments
    .find()
    .exec(renderMoments);

  function renderMoments(err, moments){
    res.render('moments', {'moments': moments });
  }
};

exports.glyphChange = function(req, res) {

  var momentID = req.params.id;
  var momentGlyph = req.params.glyph;

  // query for the specific project and
  // call the following callback
  var curMoment = models.Moments.find({ _id : momentID });

  // see if it has an empty heart or not
  if(curMoment['heart'] = "-empty"){
    curMoment.update({heart: ""}, saveIcon);
  } else {
    curMoment.update({heart: "-empty"}, saveIcon);
  }

  function saveIcon(err, moments) {
    if(err) {
      console.log(err);
      res.send(500);
    }

    res.redirect('/moments');
    res.send();
  }
}

// exports.addProject = function(req, res) {
//   var form_data = req.body;
//   console.log(form_data);
//   console.log(form_data.project_title);
//   console.log(form_data.date);
//   console.log(form_data.summary);
//   console.log(form_data.image_url);

//   // make a new Project and save it to the DB
//   // YOU MUST send an OK response w/ res.send();
//   var newProject = new models.Project({
//     "title": form_data.project_title,
//     "date": new Date(form_data.date),
//     "summary": form_data.summary,
//     "image": form_data.image_url
//   });
//   newProject.save(afterSaving);

//   function afterSaving(err) {
//     if(err) {
//       console.log(err);
//       res.send(500);
//     }
//     res.redirect('/');
//     res.send();
//   }

// }

// exports.deleteProject = function(req, res) {
//   var projectID = req.params.id;

//   // find the project and remove it
//   // YOU MUST send an OK response w/ res.send();
//   models.Project
//     .find({ _id : projectID })
//     .remove()
//     .exec(function (err) {
//       if(err) {
//         console.log(err);
//         res.send(500);
//       }
//       res.send();
//     });

// }<commit_msg>major typo<commit_after>var models = require('../models.js');

exports.view = function(req, res){
  var momentsID = req.params.id;

  models.Moments
    .find()
    .exec(renderMoments);

  function renderMoments(err, moments){
    res.render('moments', {'moments': moments });
  }
};

exports.glyphChange = function(req, res) {

  var momentID = req.params.id;
  var momentGlyph = req.params.glyph;

  // query for the specific project and
  // call the following callback
  var curMoment = models.Moments.find({ _id : momentID });

  // see if it has an empty heart or not
  if(momentGlyph == "-empty"){
    curMoment.update({heart: ""}, saveIcon);
  } else {
    curMoment.update({heart: "-empty"}, saveIcon);
  }

  function saveIcon(err, moments) {
    if(err) {
      console.log(err);
      res.send(500);
    }

    res.redirect('/moments');
    res.send();
  }
}

// exports.addProject = function(req, res) {
//   var form_data = req.body;
//   console.log(form_data);
//   console.log(form_data.project_title);
//   console.log(form_data.date);
//   console.log(form_data.summary);
//   console.log(form_data.image_url);

//   // make a new Project and save it to the DB
//   // YOU MUST send an OK response w/ res.send();
//   var newProject = new models.Project({
//     "title": form_data.project_title,
//     "date": new Date(form_data.date),
//     "summary": form_data.summary,
//     "image": form_data.image_url
//   });
//   newProject.save(afterSaving);

//   function afterSaving(err) {
//     if(err) {
//       console.log(err);
//       res.send(500);
//     }
//     res.redirect('/');
//     res.send();
//   }

// }

// exports.deleteProject = function(req, res) {
//   var projectID = req.params.id;

//   // find the project and remove it
//   // YOU MUST send an OK response w/ res.send();
//   models.Project
//     .find({ _id : projectID })
//     .remove()
//     .exec(function (err) {
//       if(err) {
//         console.log(err);
//         res.send(500);
//       }
//       res.send();
//     });

// }<|endoftext|>