<commit_before>'use strict';

var async = require('async');
var request = require('request');
//var CronJob = require('cron').CronJob;

var mongoose = require('mongoose'),
  Player = mongoose.model('Player'),
  Tournament = mongoose.model('Tournament'),
  Team = mongoose.model('Team'),
  League = mongoose.model('League');

//helper functions
var sumPlayerScores = function(playerArray){

  var teamScores = {
    modstable: 0,
    stable: 0,
    sc: 0
  };

  playerArray.forEach(function(player){
    if(player){
      teamScores.modstable += player.modstable;
      teamScores.stable += player.stable;
      teamScores.sc += player.sc;
    }
  });

  return teamScores;
};
var flattenObject = function(item){
  if(item){
    item = item._id;
  }
  return item;
};

//setup tournament
exports.setup = function(req, res){

  //clear existing records
  async.parallel([
      function(callback){
        Tournament.find({}).remove(function(err) {
          if(err)
            console.log('deleted tourneys');
          callback(err);
        });
      },
      function(callback){
        Player.find({}).remove(function(err) {
          console.log('deleted players');
          callback(err);
        });
      },
      function(callback){
        //get setupFile
        request({uri: 'http://www.pgatour.com/data/r/current/setup.json', json: true},
          function(err, response, body) {
            console.log('got setup');
            callback(err, body);
          }
        )
      },
      function(callback){
        //get leaderboard
        request({uri: 'http://www.pgatour.com/data/r/current/leaderboard.json', json: true},
          function(err, response, body) {
            console.log('got leaderboard');
            callback(err, body);
          }
        )
      }
    ],
    function(err, results){
      if(err){
        return res.json(500, err);
      }

      //get data from results array
      var setupFile, leaderboard = {};
      setupFile = results[2];
      leaderboard = results[3];

      //check for tournament object
      if(typeof setupFile.trn === "undefined" || typeof leaderboard.lb.c.c === "undefined"){
        //return console.log('tournament setup record retrieved but undefined');
        return res.json(500, 'tournament setup record retrieved but undefined');
      }

      var setupObj = {
        //event: setupFile.trn.event,
        field: setupFile.trn.field,
        rounds: setupFile.trn.rnds,
        courses: leaderboard.lb.c.c,

        name: leaderboard.lb.tn,
        date: leaderboard.lb.lt,
        pgaStatus: leaderboard.lb.rs,
        ballstrikersStatus: 'Editable',
        totalRounds: setupFile.trn.event.totalRnds,
        currentRound: setupFile.trn.event.currentRnd,

        fedex: setupFile.trn.event.cup,
        money: setupFile.trn.event.money,
        history: setupFile.trn.event.hiestory

      };

      //save all players
      if(setupObj.field){
        setupObj.field.forEach(function(player){

          //save
          var fieldPlayer = new Player(player);
          fieldPlayer.save(player, function(err){
            if(err){
              return res.json(500, err);
            }
          })

        });
      }

      Tournament.create(setupObj, function(err, item){
        if(err){

          return res.json(500, 'setup file not saved: ' + err);
          //return console.log('setup file not saved: ' + err);
        }

        return res.send(200, 'setup record saved: ' + item._id);
      });

    });

};

//refresh setup
exports.refreshSetup = function(req, res){

  //clear existing records
  async.parallel([
      function(callback){
        Tournament.find({}).remove(function(err) {
          if(err)
            console.log('deleted tourneys');
          callback(err);
        });
      },
//      function(callback){
//        Player.find({}).remove(function(err) {
//          console.log('deleted players');
//          callback(err);
//        });
//      },
      function(callback){
        //get setupFile
        request({uri: 'http://www.pgatour.com/data/r/current/setup.json', json: true},
          function(err, response, body) {
            console.log('got setup');
            callback(err, body);
          }
        )
      },
      function(callback){
        //get leaderboard
        request({uri: 'http://www.pgatour.com/data/r/current/leaderboard.json', json: true},
          function(err, response, body) {
            console.log('got leaderboard');
            callback(err, body);
          }
        )
      }
    ],
    function(err, results){
      if(err){
        return res.json(500, err);
      }

      //get data from results array
      var setupFile, leaderboard = {};
      setupFile = results[1];
      leaderboard = results[2];

      //check for tournament object
      if(typeof setupFile.trn === "undefined" || typeof leaderboard.lb.c.c === "undefined"){

        //return console.log('tournament setup record retrieved but undefined');
        return res.json(500, 'tournament setup record retrieved but undefined');
      }

      var setupObj = {
        event: setupFile.trn.event,
        field: setupFile.trn.field,
        rounds: setupFile.trn.rnds,
        courses: leaderboard.lb.c.c,

        name: leaderboard.lb.tn,
        date: leaderboard.lb.lt,
        pgaStatus: leaderboard.lb.rs,
        ballstrikersStatus: 'Editable',
        totalRounds: setupFile.trn.event.totalRnds,
        currentRound: setupFile.trn.event.currentRnds,

        fedex: setupFile.trn.event.cup,
        money: setupFile.trn.event.money,
        history: setupFile.trn.event.hiestory

      };

      //save all players
//      if(setupObj.field){
//        setupObj.field.forEach(function(player){
//
//          //save
//          var fieldPlayer = new Player(player);
//          fieldPlayer.save(player, function(err){
//            if(err){
//              return res.json(500, err);
//            }
//          })
//
//        });
//      }

      Tournament.create(setupObj, function(err, item){
        if(err){

          return res.json(500, 'setup file not saved: ' + err);
          //return console.log('setup file not saved: ' + err);
        }

        return res.send(200, 'setup record saved: ' + item._id);
      });

    });

};

//refresh all players
exports.calcPlayers = function(req, res){

    async.parallel([
        function(callback){
          //get par for courses from setup
          Tournament
            .findOne({})
            .exec(function(err, setup){
              console.log('got setup');
              callback(err, setup);
            });
        },
        function(callback){
          Player
            .find({})
            .exec(function(err, players) {
              console.log('got players');
              callback(err, players);
            });
        }
      ],
      function(err, results){

        if(err){
          return console.log(err);
        }

        var setup = results[0];
        var players = results[1];
        if (!players || !setup) {
          return console.log('no players or courses found');
        }

        //get array of holes
        var holes = setup.courses[0].h;

        async.each(players, function(player, callback) {

          //get scorecard
          request({uri: 'http://www.pgatour.com/data/r/current/scorecards/' + player.id + '.json', json: true},
            function(err, response, body) {
              if(err){
                return console.log(err);
              }
              if(typeof body.p.rnds === "undefined"){ return console.log('player record retrieved but undefined'); }
              console.log('player score retrieved: ' + player.id);

              //initialize player obj
              player.rounds = [];
              player.sc = 0;
              player.stable = 0;
              player.modstable = 0;

              //process rounds, push each into player object
              body.p.rnds.forEach(function(round){

                var modStablefordTotal = 0;
                var stablefordTotal = 0;
                var standardTotal = 0;

                //loop through holes
                for(var j = 0 ; j < round.holes.length; j++ ){

                  holes.forEach(function(hole){
                    if(round.holes[j].n ===  hole.n){
                      round.holes[j].par = hole.p;
                    }
                  });

                  var par = round.holes[j].par || 4;

                  var score = '';
                  score = round.holes[j].sc;
                  var modstable = 0;
                  var stable = 0;

                  if(score ===  ''){
                    modstable = '--';
                    stable = '--';}
                  else{

                    var diff = score - par;

                    //modStable
                    if(diff > 1){modstable = -3}
                    else if (diff === 1){modstable = -1}
                    else if (diff === 0){modstable = 0}
                    else if (diff === -1){modstable = 2}
                    else if (diff === -2){modstable = 5}
                    else if (diff < -2 ){modstable = 8}

                    //Stable
                    if(diff > 1){stable = 0}
                    else if (diff === 1 ){stable = 1}
                    else if (diff === 0 ){stable = 2}
                    else if (diff === -1){stable = 3}
                    else if (diff === -2){stable = 4}
                    else if (diff === -3){stable = 5}
                    else if (diff >  -3){stable = 6}

                    standardTotal = standardTotal + Number(score);
                    stablefordTotal =  stablefordTotal + stable;
                    modStablefordTotal = modStablefordTotal + modstable;
                  }

                  round.holes[j].stable =  stable;
                  round.holes[j].modstable =  modstable;
                }

                //round totals
                round.sc =  standardTotal;
                round.stable =  stablefordTotal;
                round.modstable = modStablefordTotal;

                //tournament totals
                player.sc +=  standardTotal;
                player.stable +=  stablefordTotal;
                player.modstable += modStablefordTotal;

                player.rounds.push(round)
              });

              player.save(function(err){
                if (err) {
                  return console.log(err);
                }
                console.log('player score saved: ' + player.id);
                return callback();
              })
            }
          );

        }, function(err){
          // if any of the file processing produced an error, err would equal that error
          if( err ) {
            // One of the iterations produced an error.
            // All processing will now stop.
            res.send(500, err);
          } else {
            res.send(200, 'All players updated');
          }
        });

      }
    );

};

//calc Team scores
exports.calcTeams = function(req, res){

  Team
    .find({})
    .populate('player1')
    .populate('player2')
    .populate('player3')
    .populate('player4')
    .exec(function(err, teams){
      if (err) {return console.log(err);}
      if (!teams) {return console.log('calc: did not load teams');}
      console.log('calc: teams: ' + teams.length);

      //called for each team
      async.each(teams,
        function(team, callback){
          team.modstable = 0;
          team.stable = 0;
          team.sc = 0;

          var teamScores = sumPlayerScores([team.player1, team.player2, team.player3, team.player4]);
          team.modstable = teamScores.modstable;
          team.stable = teamScores.stable;
          team.sc = teamScores.sc;

          team.player1 = flattenObject(team.player1);
          team.player2 = flattenObject(team.player2);
          team.player3 = flattenObject(team.player3);
          team.player3 = flattenObject(team.player4);

          team.save(function(err){
              if (err) {
                console.log(err);
                return res.send(500, err);
              }
              console.log('team saved');
              return callback();
            }
          );
        },

        //after all async ops
        function(err){
          if (err) {return res.send(500,err);}
          return res.send(200, 'teams updated');
        })

    });

};

//calc Team scores
exports.calcLeagues = function(req, res){

  League
    .find({})
    .populate('teams')
    .exec(function(err, leagues){
      if (err) {return console.log(err);}
      if (!leagues) {return console.log('calc: did not load teams');}
      console.log('calc leagues: ' + leagues.length);

      //called for each league
      async.each(leagues,
        function(league, callback){

          //reset
          league.leaderboard = {};

          //add each teamName and score to leaderboard
          league.teams.forEach(function(team){
            league.leaderboard.push({
              teamName: team.teamName,
              teamId: team._id,
              score: team.modstable
            });
          });

          league.save(function(err){
              if (err) {
                console.log(err);
                return res.send(500, err);
              }
              console.log('league saved');
              return callback();
            }
          );
        },

        //after all async ops
        function(err){
          if (err) {return res.send(500,err);}
          return res.send(200, 'leagues updated');
        })

    });

};

<commit_msg>fix refresh functino total rounds<commit_after>'use strict';

var async = require('async');
var request = require('request');
//var CronJob = require('cron').CronJob;

var mongoose = require('mongoose'),
  Player = mongoose.model('Player'),
  Tournament = mongoose.model('Tournament'),
  Team = mongoose.model('Team'),
  League = mongoose.model('League');

//helper functions
var sumPlayerScores = function(playerArray){

  var teamScores = {
    modstable: 0,
    stable: 0,
    sc: 0
  };

  playerArray.forEach(function(player){
    if(player){
      teamScores.modstable += player.modstable;
      teamScores.stable += player.stable;
      teamScores.sc += player.sc;
    }
  });

  return teamScores;
};
var flattenObject = function(item){
  if(item){
    item = item._id;
  }
  return item;
};

//setup tournament
exports.setup = function(req, res){

  //clear existing records
  async.parallel([
      function(callback){
        Tournament.find({}).remove(function(err) {
          if(err)
            console.log('deleted tourneys');
          callback(err);
        });
      },
      function(callback){
        Player.find({}).remove(function(err) {
          console.log('deleted players');
          callback(err);
        });
      },
      function(callback){
        //get setupFile
        request({uri: 'http://www.pgatour.com/data/r/current/setup.json', json: true},
          function(err, response, body) {
            console.log('got setup');
            callback(err, body);
          }
        )
      },
      function(callback){
        //get leaderboard
        request({uri: 'http://www.pgatour.com/data/r/current/leaderboard.json', json: true},
          function(err, response, body) {
            console.log('got leaderboard');
            callback(err, body);
          }
        )
      }
    ],
    function(err, results){
      if(err){
        return res.json(500, err);
      }

      //get data from results array
      var setupFile, leaderboard = {};
      setupFile = results[2];
      leaderboard = results[3];

      //check for tournament object
      if(typeof setupFile.trn === "undefined" || typeof leaderboard.lb.c.c === "undefined"){
        //return console.log('tournament setup record retrieved but undefined');
        return res.json(500, 'tournament setup record retrieved but undefined');
      }

      var setupObj = {
        //event: setupFile.trn.event,
        field: setupFile.trn.field,
        rounds: setupFile.trn.rnds,
        courses: leaderboard.lb.c.c,

        name: leaderboard.lb.tn,
        date: leaderboard.lb.lt,
        pgaStatus: leaderboard.lb.rs,
        ballstrikersStatus: 'Editable',
        totalRounds: setupFile.trn.event.totalRnds,
        currentRound: setupFile.trn.event.currentRnd,

        fedex: setupFile.trn.event.cup,
        money: setupFile.trn.event.money,
        history: setupFile.trn.event.hiestory

      };

      //save all players
      if(setupObj.field){
        setupObj.field.forEach(function(player){

          //save
          var fieldPlayer = new Player(player);
          fieldPlayer.save(player, function(err){
            if(err){
              return res.json(500, err);
            }
          })

        });
      }

      Tournament.create(setupObj, function(err, item){
        if(err){

          return res.json(500, 'setup file not saved: ' + err);
          //return console.log('setup file not saved: ' + err);
        }

        return res.send(200, 'setup record saved: ' + item._id);
      });

    });

};

//refresh setup
exports.refreshSetup = function(req, res){

  //clear existing records
  async.parallel([
      function(callback){
        Tournament.find({}).remove(function(err) {
          if(err)
            console.log('deleted tourneys');
          callback(err);
        });
      },
//      function(callback){
//        Player.find({}).remove(function(err) {
//          console.log('deleted players');
//          callback(err);
//        });
//      },
      function(callback){
        //get setupFile
        request({uri: 'http://www.pgatour.com/data/r/current/setup.json', json: true},
          function(err, response, body) {
            console.log('got setup');
            callback(err, body);
          }
        )
      },
      function(callback){
        //get leaderboard
        request({uri: 'http://www.pgatour.com/data/r/current/leaderboard.json', json: true},
          function(err, response, body) {
            console.log('got leaderboard');
            callback(err, body);
          }
        )
      }
    ],
    function(err, results){
      if(err){
        return res.json(500, err);
      }

      //get data from results array
      var setupFile, leaderboard = {};
      setupFile = results[1];
      leaderboard = results[2];

      //check for tournament object
      if(typeof setupFile.trn === "undefined" || typeof leaderboard.lb.c.c === "undefined"){

        //return console.log('tournament setup record retrieved but undefined');
        return res.json(500, 'tournament setup record retrieved but undefined');
      }

      var setupObj = {
        event: setupFile.trn.event,
        field: setupFile.trn.field,
        rounds: setupFile.trn.rnds,
        courses: leaderboard.lb.c.c,

        name: leaderboard.lb.tn,
        date: leaderboard.lb.lt,
        pgaStatus: leaderboard.lb.rs,
        ballstrikersStatus: 'Editable',
        totalRounds: setupFile.trn.event.totalRnds,
        currentRound: setupFile.trn.event.currentRnd,

        fedex: setupFile.trn.event.cup,
        money: setupFile.trn.event.money,
        history: setupFile.trn.event.hiestory

      };

      //save all players
//      if(setupObj.field){
//        setupObj.field.forEach(function(player){
//
//          //save
//          var fieldPlayer = new Player(player);
//          fieldPlayer.save(player, function(err){
//            if(err){
//              return res.json(500, err);
//            }
//          })
//
//        });
//      }

      Tournament.create(setupObj, function(err, item){
        if(err){

          return res.json(500, 'setup file not saved: ' + err);
          //return console.log('setup file not saved: ' + err);
        }

        return res.send(200, 'setup record saved: ' + item._id);
      });

    });

};

//refresh all players
exports.calcPlayers = function(req, res){

    async.parallel([
        function(callback){
          //get par for courses from setup
          Tournament
            .findOne({})
            .exec(function(err, setup){
              console.log('got setup');
              callback(err, setup);
            });
        },
        function(callback){
          Player
            .find({})
            .exec(function(err, players) {
              console.log('got players');
              callback(err, players);
            });
        }
      ],
      function(err, results){

        if(err){
          return console.log(err);
        }

        var setup = results[0];
        var players = results[1];
        if (!players || !setup) {
          return console.log('no players or courses found');
        }

        //get array of holes
        var holes = setup.courses[0].h;

        async.each(players, function(player, callback) {

          //get scorecard
          request({uri: 'http://www.pgatour.com/data/r/current/scorecards/' + player.id + '.json', json: true},
            function(err, response, body) {
              if(err){
                return console.log(err);
              }
              if(typeof body.p.rnds === "undefined"){ return console.log('player record retrieved but undefined'); }
              console.log('player score retrieved: ' + player.id);

              //initialize player obj
              player.rounds = [];
              player.sc = 0;
              player.stable = 0;
              player.modstable = 0;

              //process rounds, push each into player object
              body.p.rnds.forEach(function(round){

                var modStablefordTotal = 0;
                var stablefordTotal = 0;
                var standardTotal = 0;

                //loop through holes
                for(var j = 0 ; j < round.holes.length; j++ ){

                  holes.forEach(function(hole){
                    if(round.holes[j].n ===  hole.n){
                      round.holes[j].par = hole.p;
                    }
                  });

                  var par = round.holes[j].par || 4;

                  var score = '';
                  score = round.holes[j].sc;
                  var modstable = 0;
                  var stable = 0;

                  if(score ===  ''){
                    modstable = '--';
                    stable = '--';}
                  else{

                    var diff = score - par;

                    //modStable
                    if(diff > 1){modstable = -3}
                    else if (diff === 1){modstable = -1}
                    else if (diff === 0){modstable = 0}
                    else if (diff === -1){modstable = 2}
                    else if (diff === -2){modstable = 5}
                    else if (diff < -2 ){modstable = 8}

                    //Stable
                    if(diff > 1){stable = 0}
                    else if (diff === 1 ){stable = 1}
                    else if (diff === 0 ){stable = 2}
                    else if (diff === -1){stable = 3}
                    else if (diff === -2){stable = 4}
                    else if (diff === -3){stable = 5}
                    else if (diff >  -3){stable = 6}

                    standardTotal = standardTotal + Number(score);
                    stablefordTotal =  stablefordTotal + stable;
                    modStablefordTotal = modStablefordTotal + modstable;
                  }

                  round.holes[j].stable =  stable;
                  round.holes[j].modstable =  modstable;
                }

                //round totals
                round.sc =  standardTotal;
                round.stable =  stablefordTotal;
                round.modstable = modStablefordTotal;

                //tournament totals
                player.sc +=  standardTotal;
                player.stable +=  stablefordTotal;
                player.modstable += modStablefordTotal;

                player.rounds.push(round)
              });

              player.save(function(err){
                if (err) {
                  return console.log(err);
                }
                console.log('player score saved: ' + player.id);
                return callback();
              })
            }
          );

        }, function(err){
          // if any of the file processing produced an error, err would equal that error
          if( err ) {
            // One of the iterations produced an error.
            // All processing will now stop.
            res.send(500, err);
          } else {
            res.send(200, 'All players updated');
          }
        });

      }
    );

};

//calc Team scores
exports.calcTeams = function(req, res){

  Team
    .find({})
    .populate('player1')
    .populate('player2')
    .populate('player3')
    .populate('player4')
    .exec(function(err, teams){
      if (err) {return console.log(err);}
      if (!teams) {return console.log('calc: did not load teams');}
      console.log('calc: teams: ' + teams.length);

      //called for each team
      async.each(teams,
        function(team, callback){
          team.modstable = 0;
          team.stable = 0;
          team.sc = 0;

          var teamScores = sumPlayerScores([team.player1, team.player2, team.player3, team.player4]);
          team.modstable = teamScores.modstable;
          team.stable = teamScores.stable;
          team.sc = teamScores.sc;

          team.player1 = flattenObject(team.player1);
          team.player2 = flattenObject(team.player2);
          team.player3 = flattenObject(team.player3);
          team.player3 = flattenObject(team.player4);

          team.save(function(err){
              if (err) {
                console.log(err);
                return res.send(500, err);
              }
              console.log('team saved');
              return callback();
            }
          );
        },

        //after all async ops
        function(err){
          if (err) {return res.send(500,err);}
          return res.send(200, 'teams updated');
        })

    });

};

//calc Team scores
exports.calcLeagues = function(req, res){

  League
    .find({})
    .populate('teams')
    .exec(function(err, leagues){
      if (err) {return console.log(err);}
      if (!leagues) {return console.log('calc: did not load teams');}
      console.log('calc leagues: ' + leagues.length);

      //called for each league
      async.each(leagues,
        function(league, callback){

          //reset
          league.leaderboard = {};

          //add each teamName and score to leaderboard
          league.teams.forEach(function(team){
            league.leaderboard.push({
              teamName: team.teamName,
              teamId: team._id,
              score: team.modstable
            });
          });

          league.save(function(err){
              if (err) {
                console.log(err);
                return res.send(500, err);
              }
              console.log('league saved');
              return callback();
            }
          );
        },

        //after all async ops
        function(err){
          if (err) {return res.send(500,err);}
          return res.send(200, 'leagues updated');
        })

    });

};

<|endoftext|>


<commit_before>'use strict';
import Dom from 'metal-dom/src/dom';
import MultiMap from 'metal-structs/src/MultiMap'
import Datatable from 'metal-datatable/src/Datatable';
import Modal from 'metal-modal/src/Modal';
import Ajax from 'metal-ajax/src/Ajax';
import TreeView from 'metal-treeview/src/Treeview';

class FgTable {
	constructor(apiUrl = 'https://localhost/apis/v1.0 ',
	        tableIdentifier='#application', token='') {
		this.apiUrl = apiUrl;
		this.tableIdentifier = tableIdentifier;
		this.token = token;
	}

	render (resource, columns, details_callback) {
	    if(this.token.substring(0,4) == 'User' || this.token.substring(0,7) == 'No JSON') {
	        Dom.append(this.tableIdentifier,'
No Token available.
');
	        return;
	    }

        var table_data = [{'col1':'test1', 'col2':'test2'},{'col1':'test3', 'col2':'test4'}];

        var headers = new MultiMap();
        headers.add('Authorization', 'Bearer ' + this.token);
        headers.add('content-type', 'application/json');

        var promise = Ajax.request(this.apiUrl+'/'+resource, 'GET',null, headers, null);
        var tableBlock = this.tableIdentifier;
        promise.then(function(data){
            var tableData = JSON.parse(data.response)[resource];
            tableData.forEach(function(entry){
                Object.keys(entry).forEach(function(keyEntry){
                    if(columns.indexOf(keyEntry) < 0){
                        delete(entry[keyEntry]);
                    }

                });
                columns.forEach(function(keyEntry){
                    if (keyEntry == 'id') {
                        entry[keyEntry] = '' + entry[keyEntry] + '';
                    }
                    entry[keyEntry.capitalize()] = entry[keyEntry];
                    delete(entry[keyEntry]);
                });
            });
            var dt = new Datatable({'data': tableData, displayColumnsType: false, formatColumns: unsortColumns}, tableBlock);
        });
	}

	showDetails(resource, id) {
        if(this.token.substring(0,4) == 'User' || this.token.substring(0,7) == 'No JSON') {
            var modalError = new Modal({
                elementClasses: 'modal-boot',
                header: '
Error
',
                body: 'No token available!',
                footer: '<button type="button" class="btn btn-primary">OK</button>'
            });
            modalError.show();
            return;
        }
        var headers = new MultiMap();
        headers.add('Authorization', 'Bearer ' + this.token);
        headers.add('content-type', 'application/json');

        var promise = Ajax.request(this.apiUrl + '/' + resource + '/' + id, 'GET', null, headers, null);
        promise.then(function(data){
            var date = new Date();
            var resourceId = resource + id + date.getTime();
            var modalTask = new Modal({
                elementClasses: 'modal-boot',
                header: '
Task: ' + id + '
',
                body: '

'
            });

            new TreeView({
                nodes: FgTable.convertToNodes(JSON.parse(data.response))
            }, '#' + resourceId);

            modalTask.show();

        });
	}

	static convertToNodes(json) {
	    var nodes = new Array();
	    var childrenList;
	    Object.keys(json).forEach(function(key){
            if(typeof json[key] !== null && typeof json[key] === 'object'){
                if(Array.isArray(json[key])){
                    childrenList = new Array();
                    var arrayElem = 0;
                    json[key].forEach(function(childElem){
                        if(typeof childElem !== null && typeof childElem === 'object'){
                            childrenList.push({name: arrayElem++, children: FgTable.convertToNodes(childElem)});
                        } else {
                            childrenList.push({name: childElem});
                        }
                    });
                    if(childrenList.length>0){
                        nodes.push({name: key, children: childrenList});
                    } else {
                        nodes.push({name: key, children: [{name: 'N/A'}]});
                    }
                } else {
                    nodes.push({name: key, children: FgTable.convertToNodes(json[key])});
                }
            } else {
                nodes.push({name: key, children: [{name: json[key]}]});
            }
	    });
	    return nodes;
    }
}

function unsortColumns(columns) {
    return columns
}

String.prototype.capitalize = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

export default FgTable;<commit_msg>Fix insert modal details<commit_after>'use strict';
import Dom from 'metal-dom/src/dom';
import MultiMap from 'metal-structs/src/MultiMap'
import Datatable from 'metal-datatable/src/Datatable';
import Modal from 'metal-modal/src/Modal';
import Ajax from 'metal-ajax/src/Ajax';
import TreeView from 'metal-treeview/src/Treeview';

class FgTable {
	constructor(apiUrl = 'https://localhost/apis/v1.0 ',
	        tableIdentifier='#application', token='') {
		this.apiUrl = apiUrl;
		this.tableIdentifier = tableIdentifier;
		this.token = token;
	}

	render (resource, columns, details_callback) {
	    if(this.token.substring(0,4) == 'User' || this.token.substring(0,7) == 'No JSON') {
	        Dom.append(this.tableIdentifier,'
No Token available.
');
	        return;
	    }

        var headers = new MultiMap();
        headers.add('Authorization', 'Bearer ' + this.token);
        headers.add('content-type', 'application/json');

        var promise = Ajax.request(this.apiUrl+'/'+resource, 'GET',null, headers, null);
        var tableBlock = this.tableIdentifier;
        promise.then(function(data){
            var tableData = JSON.parse(data.response)[resource];
            tableData.forEach(function(entry){
                Object.keys(entry).forEach(function(keyEntry){
                    if(columns.indexOf(keyEntry) < 0){
                        delete(entry[keyEntry]);
                    }

                });
                columns.forEach(function(keyEntry){
                    if (keyEntry == 'id') {
                        entry[keyEntry] = '' + entry[keyEntry] + '';
                    }
                    entry[keyEntry.capitalize()] = entry[keyEntry];
                    delete(entry[keyEntry]);
                });
            });
            var dt = new Datatable({'data': tableData, displayColumnsType: false, formatColumns: unsortColumns}, tableBlock);
        });
	}

	showDetails(resource, id) {
        if(this.token.substring(0,4) == 'User' || this.token.substring(0,7) == 'No JSON') {
            var modalError = new Modal({
                elementClasses: 'modal-boot',
                header: '
Error
',
                body: 'No token available!',
                footer: '<button type="button" class="btn btn-primary">OK</button>'
            });
            modalError.show();
            return;
        }
        var headers = new MultiMap();
        headers.add('Authorization', 'Bearer ' + this.token);
        headers.add('content-type', 'application/json');

        var promise = Ajax.request(this.apiUrl + '/' + resource + '/' + id, 'GET', null, headers, null);
        promise.then(function(data){
            var date = new Date();
            var resourceId = resource + id + date.getTime();
            var modalTask = new Modal({
                elementClasses: 'modal-boot',
                header: '
' + resource.substring(0, resource.length - 1).capitalize() + ': ' + id + '
',
                body: '

'
            });

            new TreeView({
                nodes: FgTable.convertToNodes(JSON.parse(data.response))
            }, '#' + resourceId);

            modalTask.show();

        });
	}

	static convertToNodes(json) {
	    var nodes = new Array();
	    var childrenList;
	    Object.keys(json).forEach(function(key){
            if(typeof json[key] !== null && typeof json[key] === 'object'){
                if(Array.isArray(json[key])){
                    childrenList = new Array();
                    var arrayElem = 0;
                    json[key].forEach(function(childElem){
                        if(typeof childElem !== null && typeof childElem === 'object'){
                            childrenList.push({name: arrayElem++, children: FgTable.convertToNodes(childElem)});
                        } else {
                            childrenList.push({name: childElem});
                        }
                    });
                    if(childrenList.length>0){
                        nodes.push({name: key, children: childrenList});
                    } else {
                        nodes.push({name: key, children: [{name: 'N/A'}]});
                    }
                } else {
                    nodes.push({name: key, children: FgTable.convertToNodes(json[key])});
                }
            } else {
                nodes.push({name: key, children: [{name: json[key]}]});
            }
	    });
	    return nodes;
    }
}

function unsortColumns(columns) {
    return columns
}

String.prototype.capitalize = function() {
    return this.charAt(0).toUpperCase() + this.slice(1);
}

export default FgTable;<|endoftext|>


<commit_before>import $ from 'jquery';

import { wrap } from '@girder/core/utilities/PluginUtils';
import { restRequest } from '@girder/core/rest';
import AccessWidget from '@girder/core/views/widgets/AccessWidget';
import HierarchyWidget from '@girder/core/views/widgets/HierarchyWidget';

import AnnotationModel from '../models/AnnotationModel';

wrap(HierarchyWidget, 'render', function (render) {
    render.call(this);

    if (this.parentModel.get('_modelType') === 'folder') {
        ownAnnotation(this, this.parentModel.id);
    }
});

function ownAnnotation(root, folderId) {
    restRequest({
        type: 'GET',
        url: 'annotation/folder/' + folderId + '/present',
        data: {
            recurse: true
        }
    }).done((ownsAnnot) => {
        if (ownsAnnot) {
            addAccessControl(root);
        }
    });
}

function addAccessControl(root) {
    if (root.$('.g-edit-annotation-access').length === 0) {
        if (root.$('.g-folder-actions-menu > .divider').length > 0) {
            root.$('.g-folder-actions-menu > .divider').before(
                '
' +
                    '' +
                        '' +
                        'Annotation access control' +
                    '' +
                '
'
            );
        } else {
            root.$('ul.g-folder-actions-menu').append(
                '
' +
                    '' +
                        '' +
                        'Annotation access control' +
                    '' +
                '
'
            );
        }
        root.events['click .g-edit-annotation-access'] = editAnnotAccess;
        root.delegateEvents();
    }
}

function editAnnotAccess() {
    restRequest({
        type: 'GET',
        url: 'annotation/folder/' + this.parentModel.get('_id'),
        data: {
            recurse: true,
            limit: 1
        }
    }).done((resp) => {
        const model = new AnnotationModel(resp[0]);
        model.get('annotation').name = 'Your Annotations';
        model.save = () => {};
        model.updateAccess = (settings) => {
            const access = {
                access: model.get('access'),
                public: model.get('public'),
                publicFlags: model.get('publicFlags')
            };
            const defaultUpdateModel = new AnnotationModel();
            defaultUpdateModel.id = this.parentModel.get('_id');
            defaultUpdateModel.altUrl = 'annotation/folder';
            defaultUpdateModel.set(access);
            defaultUpdateModel.updateAccess(settings);
            model.trigger('g:accessListSaved');
        };
        model.fetchAccess(true)
            .done(() => {
                new AccessWidget({// eslint-disable-line no-new
                    el: $('#g-dialog-container'),
                    modelType: 'annotation',
                    model,
                    hideRecurseOption: false,
                    parentView: this
                });
            });
    });
}

export default HierarchyWidget;
<commit_msg>Hide access flag in annotation access control<commit_after>import $ from 'jquery';

import { wrap } from '@girder/core/utilities/PluginUtils';
import { restRequest } from '@girder/core/rest';
import AccessWidget from '@girder/core/views/widgets/AccessWidget';
import HierarchyWidget from '@girder/core/views/widgets/HierarchyWidget';

import AnnotationModel from '../models/AnnotationModel';

wrap(HierarchyWidget, 'render', function (render) {
    render.call(this);

    if (this.parentModel.get('_modelType') === 'folder') {
        ownAnnotation(this, this.parentModel.id);
    }
});

function ownAnnotation(root, folderId) {
    restRequest({
        type: 'GET',
        url: 'annotation/folder/' + folderId + '/present',
        data: {
            recurse: true
        }
    }).done((ownsAnnot) => {
        if (ownsAnnot) {
            addAccessControl(root);
        }
    });
}

function addAccessControl(root) {
    if (root.$('.g-edit-annotation-access').length === 0) {
        if (root.$('.g-folder-actions-menu > .divider').length > 0) {
            root.$('.g-folder-actions-menu > .divider').before(
                '
' +
                    '' +
                        '' +
                        'Annotation access control' +
                    '' +
                '
'
            );
        } else {
            root.$('ul.g-folder-actions-menu').append(
                '
' +
                    '' +
                        '' +
                        'Annotation access control' +
                    '' +
                '
'
            );
        }
        root.events['click .g-edit-annotation-access'] = editAnnotAccess;
        root.delegateEvents();
    }
}

function editAnnotAccess() {
    restRequest({
        type: 'GET',
        url: 'annotation/folder/' + this.parentModel.get('_id'),
        data: {
            recurse: true,
            limit: 1
        }
    }).done((resp) => {
        const model = new AnnotationModel(resp[0]);
        model.get('annotation').name = 'Your Annotations';
        model.save = () => {};
        model.updateAccess = (settings) => {
            const access = {
                access: model.get('access'),
                public: model.get('public'),
                publicFlags: model.get('publicFlags')
            };
            const defaultUpdateModel = new AnnotationModel();
            defaultUpdateModel.id = this.parentModel.get('_id');
            defaultUpdateModel.altUrl = 'annotation/folder';
            defaultUpdateModel.set(access);
            defaultUpdateModel.updateAccess(settings);
            model.trigger('g:accessListSaved');
        };
        model.fetchAccess(true)
            .done(() => {
                new AccessWidget({// eslint-disable-line no-new
                    el: $('#g-dialog-container'),
                    modelType: 'annotation',
                    model,
                    hideRecurseOption: false,
                    parentView: this,
                    noAccessFlag: true
                });
            });
    });
}

export default HierarchyWidget;
<|endoftext|>


<commit_before>'use strict';

const { Thing } = require('abstract-things');
const { Light, SwitchablePower, Dimmable, Colorable } = require('abstract-things/lights');
const { color } = require('abstract-things/values');

/**
 * Capability that register the
 */
module.exports = Thing.mixin(Appliance => class extends Appliance {
	initCallback() {
		this.addExtraChild(new GatewayLight(this));

		return super.initCallback();
	}
});

/**
 * Capability that is mixed in if a gateway is also a light.
 */
const GatewayLight = class extends Light.with(SwitchablePower, Dimmable, Colorable) {
	static get types() {
		return [ 'miio:subdevice', 'miio:gateway-light' ];
	}

	constructor(gateway) {
		super();

		this.model = gateway.miioModel + '.light';
		this.internalId = gateway.id.substring(5) + ':light';
		this.id = gateway.id + ':light';
		this.gateway = gateway;

		// Hijack the property updated event to make control easier
		const propertyUpdated = this.gateway.propertyUpdated;
		this.gateway.propertyUpdated = (key, value, oldValue) => {
			propertyUpdated.call(this.gateway, key, value, oldValue);

			this.propertyUpdated(key, value);
		};
	}

	changePower(power) {
		return this.changeBrightness(power ? 50 : 0);
	}

	changeBrightness(brightness, options) {
		const a = brightness / 100 * 255;
		const color = this.gateway.property('rgb');
		const rgb = a << 24 | (color.red << 16) | (color.green << 8) | color.blue;

		return this.gateway.call('set_rgb', [ rgb >>> 0 ], { refresh: [ 'rgb' ] });
	}

	changeColor(color, options) {
		color = color.rgb;
		const a = this.gateway.property('brightness');
		const rgb = a << 24 | (color.red << 16) | (color.green << 8) | color.blue;

		return this.gateway.call('set_rgb', [ rgb >>> 0 ], { refresh: [ 'rgb' ] });
	}

	propertyUpdated(key, value) {
		if(key === 'rgb') {
			this.updateColor(color.rgb(value.red, value.green, value.blue));
		} else if(key === 'brightness') {
			//this.updateBrightness(Math.round(value / 255 * 100));
			this.updateBrightness(value);
			this.updatePower(value > 0);
		}
	}
};
<commit_msg>Fix gateway brightness value<commit_after>'use strict';

const { Thing } = require('abstract-things');
const { Light, SwitchablePower, Dimmable, Colorable } = require('abstract-things/lights');
const { color } = require('abstract-things/values');

/**
 * Capability that register the
 */
module.exports = Thing.mixin(Appliance => class extends Appliance {
	initCallback() {
		this.addExtraChild(new GatewayLight(this));

		return super.initCallback();
	}
});

/**
 * Capability that is mixed in if a gateway is also a light.
 */
const GatewayLight = class extends Light.with(SwitchablePower, Dimmable, Colorable) {
	static get types() {
		return [ 'miio:subdevice', 'miio:gateway-light' ];
	}

	constructor(gateway) {
		super();

		this.model = gateway.miioModel + '.light';
		this.internalId = gateway.id.substring(5) + ':light';
		this.id = gateway.id + ':light';
		this.gateway = gateway;

		// Hijack the property updated event to make control easier
		const propertyUpdated = this.gateway.propertyUpdated;
		this.gateway.propertyUpdated = (key, value, oldValue) => {
			propertyUpdated.call(this.gateway, key, value, oldValue);

			this.propertyUpdated(key, value);
		};
	}

	changePower(power) {
		return this.changeBrightness(power ? 50 : 0);
	}

	changeBrightness(brightness, options) {
		const color = this.gateway.property('rgb');
		const rgb = brightness << 24 | (color.red << 16) | (color.green << 8) | color.blue;

		return this.gateway.call('set_rgb', [ rgb >>> 0 ], { refresh: [ 'rgb' ] });
	}

	changeColor(color, options) {
		color = color.rgb;
		const a = this.gateway.property('brightness');
		const rgb = a << 24 | (color.red << 16) | (color.green << 8) | color.blue;

		return this.gateway.call('set_rgb', [ rgb >>> 0 ], { refresh: [ 'rgb' ] });
	}

	propertyUpdated(key, value) {
		if(key === 'rgb') {
			this.updateColor(color.rgb(value.red, value.green, value.blue));
		} else if(key === 'brightness') {
			//this.updateBrightness(Math.round(value / 255 * 100));
			this.updateBrightness(value);
			this.updatePower(value > 0);
		}
	}
};
<|endoftext|>


<commit_before>/**
 * An Ember Data Adapter written to use Parse REST API
 * @type {DS.RESTAdapter}
 */
EmberParseAdapter.Adapter = DS.RESTAdapter.extend({

  defaultSerializer: '-parse',

  init: function(){
    this._super();
    this.set('headers', {
      "X-Parse-Application-Id": this.get('applicationId'),
      "X-Parse-REST-API-Key": this.get('restApiId')
    });
  },

  host: "https://api.parse.com",
  namespace: '1',
  classesPath: 'classes',

  pathForType: function(type) {
    if ("parseUser" === type) {
      return "users";
    } else if ("login" === type) {
      return "login";
    } else {
      return this.classesPath + '/' + this.parsePathForType(type);
    }
  },

  // Using TitleStyle is recommended by Parse
  // TODO: test
  parsePathForType: function(type) {
    return Ember.String.capitalize(Ember.String.camelize(type));
  },

  /**
   * Because Parse doesn't return a full set of properties on the
   * responses to updates, we want to perform a merge of the response
   * properties onto existing data so that the record maintains
   * latest data.
   */
  createRecord: function(store, type, record) {
    var data = {};
    var serializer = store.serializerFor(type.typeKey);
    serializer.serializeIntoHash(data, type, record, { includeId: true });
    var adapter = this;
    return new Ember.RSVP.Promise(function(resolve, reject){
      adapter.ajax(adapter.buildURL(type.typeKey), "POST", { data: data }).then(
      function(json){
        var completed = Ember.merge(data, json);
        resolve(completed);
      },
      function(reason){
        reject(reason.responseJSON);
      });
    });
  },

  /**
   * Because Parse doesn't return a full set of properties on the
   * responses to updates, we want to perform a merge of the response
   * properties onto existing data so that the record maintains
   * latest data.
   */
  updateRecord: function(store, type, record) {
    var data = {};
    var deleteds = {};
    var sendDeletes = false;
    var serializer = store.serializerFor(type.typeKey);
    serializer.serializeIntoHash(data, type, record);
    var id = record.get('id');
    var adapter = this;

    type.eachRelationship(function(key, relationship){
      if(data[key] && data[key].deleteds){
        deleteds[key] = data[key].deleteds;
        delete data[key].deleteds;
        sendDeletes = true;
      }
    });

    return new Ember.RSVP.Promise(function(resolve, reject) {
      if(sendDeletes){
          adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", {data: deleteds}).then(
            function(json){
              adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", { data: data }).then(
                function(updates){
                  // This is the essential bit - merge response data onto existing data.
                  var completed = Ember.merge(data, updates);
                  resolve(completed);
                },
                function(reason){
                  reject("Failed to save parent in relation: " + reason.response.JSON);
                }
              );
            },
            function(reason){
              reject(reason.responseJSON);
            }
          );
      } else {
        adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", { data: data }).then(function(json){
          // This is the essential bit - merge response data onto existing data.
          var completed = Ember.merge(data, json);
          resolve(completed);
        }, function(reason){
          reject(reason.responseJSON);
        });
      }
    });
  },

  parseClassName: function(key) {
    return Ember.String.capitalize(key);
  },

  /**
   * Implementation of a hasMany that provides a Relation query for Parse
   * objects.
   */
  findHasMany: function(store, record, relatedInfo){
    var query = {
      where: {
        "$relatedTo": {
          "object": {
            "__type": "Pointer",
            "className": this.parseClassName(record.typeKey),
            "objectId": record.get('id')
          },
          key: relatedInfo.key
        }
      }
    };
    // the request is to the related type and not the type for the record.
    // the query is where there is a pointer to this record.
    return this.ajax(this.buildURL(relatedInfo.type.typeKey), "GET", { data: query });
  },

  /**
   * Implementation of findQuery that automatically wraps query in a
   * JSON string.
   *
   * @example
   *     this.store.find('comment', {
   *       where: {
   *         post: {
   *             "__type":  "Pointer",
   *             "className": "Post",
   *             "objectId": post.get('id')
   *         }
   *       }
   *     });
   */
  findQuery: function (store, type, query) {
    if (query.where && Ember.typeOf(query.where) !== 'string') {
      query.where = JSON.stringify(query.where);
    }

    // Pass to _super()
    return this._super(store, type, query);
  },

  sessionToken: Ember.computed('headers.X-Parse-Session-Token', function(key, value){
    if (arguments.length < 2) {
      return this.get('headers.X-Parse-Session-Token');
    } else {
      this.set('headers.X-Parse-Session-Token', value);
      return value;
    }
  })
});
<commit_msg>Account for `parseUser` type in `parseClassName` method<commit_after>/**
 * An Ember Data Adapter written to use Parse REST API
 * @type {DS.RESTAdapter}
 */
EmberParseAdapter.Adapter = DS.RESTAdapter.extend({

  defaultSerializer: '-parse',

  init: function(){
    this._super();
    this.set('headers', {
      "X-Parse-Application-Id": this.get('applicationId'),
      "X-Parse-REST-API-Key": this.get('restApiId')
    });
  },

  host: "https://api.parse.com",
  namespace: '1',
  classesPath: 'classes',

  pathForType: function(type) {
    if ("parseUser" === type) {
      return "users";
    } else if ("login" === type) {
      return "login";
    } else {
      return this.classesPath + '/' + this.parsePathForType(type);
    }
  },

  // Using TitleStyle is recommended by Parse
  // TODO: test
  parsePathForType: function(type) {
    return Ember.String.capitalize(Ember.String.camelize(type));
  },

  /**
   * Because Parse doesn't return a full set of properties on the
   * responses to updates, we want to perform a merge of the response
   * properties onto existing data so that the record maintains
   * latest data.
   */
  createRecord: function(store, type, record) {
    var data = {};
    var serializer = store.serializerFor(type.typeKey);
    serializer.serializeIntoHash(data, type, record, { includeId: true });
    var adapter = this;
    return new Ember.RSVP.Promise(function(resolve, reject){
      adapter.ajax(adapter.buildURL(type.typeKey), "POST", { data: data }).then(
      function(json){
        var completed = Ember.merge(data, json);
        resolve(completed);
      },
      function(reason){
        reject(reason.responseJSON);
      });
    });
  },

  /**
   * Because Parse doesn't return a full set of properties on the
   * responses to updates, we want to perform a merge of the response
   * properties onto existing data so that the record maintains
   * latest data.
   */
  updateRecord: function(store, type, record) {
    var data = {};
    var deleteds = {};
    var sendDeletes = false;
    var serializer = store.serializerFor(type.typeKey);
    serializer.serializeIntoHash(data, type, record);
    var id = record.get('id');
    var adapter = this;

    type.eachRelationship(function(key, relationship){
      if(data[key] && data[key].deleteds){
        deleteds[key] = data[key].deleteds;
        delete data[key].deleteds;
        sendDeletes = true;
      }
    });

    return new Ember.RSVP.Promise(function(resolve, reject) {
      if(sendDeletes){
          adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", {data: deleteds}).then(
            function(json){
              adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", { data: data }).then(
                function(updates){
                  // This is the essential bit - merge response data onto existing data.
                  var completed = Ember.merge(data, updates);
                  resolve(completed);
                },
                function(reason){
                  reject("Failed to save parent in relation: " + reason.response.JSON);
                }
              );
            },
            function(reason){
              reject(reason.responseJSON);
            }
          );
      } else {
        adapter.ajax(adapter.buildURL(type.typeKey, id), "PUT", { data: data }).then(function(json){
          // This is the essential bit - merge response data onto existing data.
          var completed = Ember.merge(data, json);
          resolve(completed);
        }, function(reason){
          reject(reason.responseJSON);
        });
      }
    });
  },

  parseClassName: function(key) {
    if (key === "parseUser") {
      return "_User";
    } else {
      return Ember.String.capitalize(Ember.String.camelize(key));
    }
  },

  /**
   * Implementation of a hasMany that provides a Relation query for Parse
   * objects.
   */
  findHasMany: function(store, record, relatedInfo){
    var query = {
      where: {
        "$relatedTo": {
          "object": {
            "__type": "Pointer",
            "className": this.parseClassName(record.typeKey),
            "objectId": record.get('id')
          },
          key: relatedInfo.key
        }
      }
    };
    // the request is to the related type and not the type for the record.
    // the query is where there is a pointer to this record.
    return this.ajax(this.buildURL(relatedInfo.type.typeKey), "GET", { data: query });
  },

  /**
   * Implementation of findQuery that automatically wraps query in a
   * JSON string.
   *
   * @example
   *     this.store.find('comment', {
   *       where: {
   *         post: {
   *             "__type":  "Pointer",
   *             "className": "Post",
   *             "objectId": post.get('id')
   *         }
   *       }
   *     });
   */
  findQuery: function (store, type, query) {
    if (query.where && Ember.typeOf(query.where) !== 'string') {
      query.where = JSON.stringify(query.where);
    }

    // Pass to _super()
    return this._super(store, type, query);
  },

  sessionToken: Ember.computed('headers.X-Parse-Session-Token', function(key, value){
    if (arguments.length < 2) {
      return this.get('headers.X-Parse-Session-Token');
    } else {
      this.set('headers.X-Parse-Session-Token', value);
      return value;
    }
  })
});
<|endoftext|>


<commit_before>"use strict";

const pako = require("pako");
const BaseSocket = require("./BaseSocket");
const VoiceSocket = require("./VoiceSocket");
const Constants = require("../../Constants");
const DiscordieError = require("../../core/DiscordieError");
const Events = Constants.Events;

require("../../core/SSLCA");

const OPCODE_DISPATCH = 0;
const OPCODE_HEARTBEAT = 1;
const OPCODE_IDENTIFY = 2;
const OPCODE_STATUS_UPDATE = 3;
const OPCODE_VOICE_STATE_UPDATE = 4;
const OPCODE_VOICE_SERVER_PING = 5;
const OPCODE_RESUME = 6;
const OPCODE_REDIRECT = 7;

const VERSION = 3;

const discordie = new WeakMap();

class GatewaySocket {
  constructor(_discordie, compressMessages) {
    discordie.set(this, _discordie);
    this.Dispatcher = _discordie.Dispatcher;
    this.socket = null;

    this.compressed = compressMessages;
    Object.defineProperty(this, 'compressed', {writable: false});

    this.voiceState = {
      guildId: null,
      channelId: null,
      selfMute: false,
      selfDeaf: false,
    };

    this.voiceSocket = null;

    this.userId = null;

    this.sendQueue = [];

    this.resumeTries = 0;
  }
  get connected() {
    return this.socket && this.socket.connected;
  }
  get connecting() {
    return this.socket && this.socket.connecting;
  }
  connect(url) {
    if (this.connected)
      this.disconnect();

    this.gatewayURL = url;
    this.socket = new BaseSocket(url);
    this.socket.on("open", e => {
      this.Dispatcher.emit(Events.GATEWAY_OPEN, {socket: this});

      if (this.seq > 0) {
        this.resumeTries++;
        return this.socket.send(OPCODE_RESUME, {
          session_id: this.sessionId,
          seq: this.seq
        });
      }

      if (!discordie.get(this).token) {
        this.Dispatcher.emit(
          Events.DISCONNECTED,
          {error: new DiscordieError("No token specified")}
        );
        return this.disconnect();
      }

      this.identify(discordie.get(this).token);
    });
    this.socket.on("message", e => {
      if (this.compressed && e instanceof Buffer) {
        e = pako.inflate(e, {to: "string"});
      }
      const msg = JSON.parse(e);
      const op = msg.op;
      const seq = msg.s;
      const type = msg.t;
      const data = msg.d;

      if (seq) this.seq = seq;

      if (op === OPCODE_REDIRECT) {
        connect(data.url);
      }
      if (op === OPCODE_DISPATCH) {
        if (["READY", "RESUME"].indexOf(type) >= 0) {
          if (type === "READY") {
            this.sessionId = data.session_id;
            this.userId = data.user.id;
          }

          let payload;
          while (payload = this.sendQueue.shift()) {
            this.socket.send(payload);
          }

          if (data.heartbeat_interval > 0) {
            this.socket.setHeartbeat(
              OPCODE_HEARTBEAT,
              data.heartbeat_interval
            );
          }
        }

        this.Dispatcher.emit(
          Events.GATEWAY_DISPATCH,
          {socket: this, type: type, data: data}
        );
      }
      if (op === OPCODE_REDIRECT) {
        // todo: implement redirect
      }
    });

    const close = (error) => {
      this.disconnect(true);
      this.Dispatcher.emit(
        Events.GATEWAY_DISCONNECT,
        {socket: this, error: error}
      );

      // todo: check if we need to handle VOICE_STATE_UPDATE for secondary sockets

      const primary = (this === discordie.get(this).gatewaySocket);
      if (primary) {
        this.Dispatcher.emit(
          Events.DISCONNECTED,
          {error: new DiscordieError("Disconnected from primary gateway", error)}
        );
      }
    };
    this.socket.on("close", close);
    this.socket.on("error", close);
  }
  send(op, data) {
    if (!this.connected) {
      this.sendQueue.push(JSON.stringify({op: op, data: data}));
      return;
    }
    this.socket.send(op, data);
  }
  disconnect(causedByEvent) {
    if (!causedByEvent) {
      this.seq = 0;
      delete this.sessionId;
    }

    this.disconnectVoice();

    if (this.connected)
      this.socket.close();

    this.socket.readyState = Constants.ReadyState.CLOSED;
    if (this.resumeTries > 1) {
      this.seq = 0;
      this.resumeTries = 0;
    }
    this.sendQueue.length = 0;
    this.sendQueue = [];
  }
  identify(token) {
    this.socket.send(OPCODE_IDENTIFY, {
      token: token,
      properties: {
        "$os": "",
        "$browser": "Discordie",
        "$device": ""
      },
      v: VERSION,
      compress: this.compressed
    });
  }
  statusUpdate(idleSince, gameId) {
    this.send(OPCODE_STATUS_UPDATE, {
      idle_since: idleSince,
      game_id: gameId
    });
  }
  voiceStateUpdate(guildId, channelId, selfMute, selfDeaf) {
    if (!guildId) guildId = null;
    if (!channelId) channelId = null;
    if (!selfMute) selfMute = false;
    if (!selfDeaf) selfDeaf = false;
    if (guildId && guildId != this.voiceState.guildId) {
      this.disconnectVoice();
    }
    Object.assign(this.voiceState, {
      guildId: guildId,
      channelId: channelId,
      selfMute: selfMute,
      selfDeaf: selfDeaf
    });
    this.send(OPCODE_VOICE_STATE_UPDATE, {
      guild_id: guildId,
      channel_id: channelId,
      self_mute: selfMute,
      self_deaf: selfDeaf
    });
  }
  voiceServerPing() {
    // todo: handle voice reconnects, disconnects and other fun stuff
    this.socket.send(OPCODE_VOICE_SERVER_PING, null);
  }

  createVoiceSocket(endpoint, guildId, userId, sessionId, token) {
    this.disconnectVoice();
    if (!endpoint) return;
    this.voiceSocket = new VoiceSocket(this);
    this.voiceSocket.connect(
      endpoint.split(":")[0],
      guildId, userId, sessionId, token
    );
  }
  disconnectVoice() {
    if (this.voiceSocket) {
      if (this.connected)
        this.voiceStateUpdate(null, null);

      this.voiceSocket.disconnect();
      this.voiceSocket = null;
    }
  }
  toJSON() { return `[GatewaySocket ${this.gatewayURL}]`; }
}

module.exports = GatewaySocket;
<commit_msg>Emit GATEWAY_DISCONNECT<commit_after>"use strict";

const pako = require("pako");
const BaseSocket = require("./BaseSocket");
const VoiceSocket = require("./VoiceSocket");
const Constants = require("../../Constants");
const DiscordieError = require("../../core/DiscordieError");
const Events = Constants.Events;

require("../../core/SSLCA");

const OPCODE_DISPATCH = 0;
const OPCODE_HEARTBEAT = 1;
const OPCODE_IDENTIFY = 2;
const OPCODE_STATUS_UPDATE = 3;
const OPCODE_VOICE_STATE_UPDATE = 4;
const OPCODE_VOICE_SERVER_PING = 5;
const OPCODE_RESUME = 6;
const OPCODE_REDIRECT = 7;

const VERSION = 3;

const discordie = new WeakMap();

class GatewaySocket {
  constructor(_discordie, compressMessages) {
    discordie.set(this, _discordie);
    this.Dispatcher = _discordie.Dispatcher;
    this.socket = null;

    this.compressed = compressMessages;
    Object.defineProperty(this, 'compressed', {writable: false});

    this.voiceState = {
      guildId: null,
      channelId: null,
      selfMute: false,
      selfDeaf: false,
    };

    this.voiceSocket = null;

    this.userId = null;

    this.sendQueue = [];

    this.resumeTries = 0;
  }
  get isPrimary() {
    return (this === discordie.get(this).gatewaySocket);
  }
  get connected() {
    return this.socket && this.socket.connected;
  }
  get connecting() {
    return this.socket && this.socket.connecting;
  }
  connect(url) {
    if (this.connected)
      this.disconnect();

    this.gatewayURL = url;
    this.socket = new BaseSocket(url);
    this.socket.on("open", e => {
      this.Dispatcher.emit(Events.GATEWAY_OPEN, {socket: this});

      if (this.seq > 0) {
        this.resumeTries++;
        return this.socket.send(OPCODE_RESUME, {
          session_id: this.sessionId,
          seq: this.seq
        });
      }

      if (!discordie.get(this).token) {
        this.Dispatcher.emit(
          Events.DISCONNECTED,
          {error: new DiscordieError("No token specified")}
        );
        return this.disconnect();
      }

      this.identify(discordie.get(this).token);
    });
    this.socket.on("message", e => {
      if (this.compressed && e instanceof Buffer) {
        e = pako.inflate(e, {to: "string"});
      }
      const msg = JSON.parse(e);
      const op = msg.op;
      const seq = msg.s;
      const type = msg.t;
      const data = msg.d;

      if (seq) this.seq = seq;

      if (op === OPCODE_REDIRECT) {
        connect(data.url);
      }
      if (op === OPCODE_DISPATCH) {
        if (["READY", "RESUME"].indexOf(type) >= 0) {
          if (type === "READY") {
            this.sessionId = data.session_id;
            this.userId = data.user.id;
          }

          let payload;
          while (payload = this.sendQueue.shift()) {
            this.socket.send(payload);
          }

          if (data.heartbeat_interval > 0) {
            this.socket.setHeartbeat(
              OPCODE_HEARTBEAT,
              data.heartbeat_interval
            );
          }
        }

        this.Dispatcher.emit(
          Events.GATEWAY_DISPATCH,
          {socket: this, type: type, data: data}
        );
      }
      if (op === OPCODE_REDIRECT) {
        // todo: implement redirect
      }
    });

    const close = (error) => {
      this.disconnect(error, true);

      // todo: check if we need to handle VOICE_STATE_UPDATE for secondary sockets

      if (this.isPrimary) {
        this.Dispatcher.emit(
          Events.DISCONNECTED,
          {error: new DiscordieError("Disconnected from primary gateway", error)}
        );
      }
    };
    this.socket.on("close", close);
    this.socket.on("error", close);
  }
  send(op, data) {
    if (!this.connected) {
      this.sendQueue.push(JSON.stringify({op: op, data: data}));
      return;
    }
    this.socket.send(op, data);
  }
  disconnect(error, causedByEvent) {
    if (!causedByEvent) {
      this.seq = 0;
      delete this.sessionId;
    }

    this.disconnectVoice();

    if (this.connected) {
      this.socket.close();

      let msg = {socket: this};
      if (error) msg.error = error;
      this.Dispatcher.emit(Events.GATEWAY_DISCONNECT, msg);
    }

    this.socket.readyState = Constants.ReadyState.CLOSED;
    if (this.resumeTries > 1) {
      this.seq = 0;
      this.resumeTries = 0;
    }
    this.sendQueue.length = 0;
    this.sendQueue = [];
  }
  identify(token) {
    this.socket.send(OPCODE_IDENTIFY, {
      token: token,
      properties: {
        "$os": "",
        "$browser": "Discordie",
        "$device": ""
      },
      v: VERSION,
      compress: this.compressed
    });
  }
  statusUpdate(idleSince, gameId) {
    this.send(OPCODE_STATUS_UPDATE, {
      idle_since: idleSince,
      game_id: gameId
    });
  }
  voiceStateUpdate(guildId, channelId, selfMute, selfDeaf) {
    if (!guildId) guildId = null;
    if (!channelId) channelId = null;
    if (!selfMute) selfMute = false;
    if (!selfDeaf) selfDeaf = false;
    if (guildId && guildId != this.voiceState.guildId) {
      this.disconnectVoice();
    }
    Object.assign(this.voiceState, {
      guildId: guildId,
      channelId: channelId,
      selfMute: selfMute,
      selfDeaf: selfDeaf
    });
    this.send(OPCODE_VOICE_STATE_UPDATE, {
      guild_id: guildId,
      channel_id: channelId,
      self_mute: selfMute,
      self_deaf: selfDeaf
    });
  }
  voiceServerPing() {
    // todo: handle voice reconnects, disconnects and other fun stuff
    this.socket.send(OPCODE_VOICE_SERVER_PING, null);
  }

  createVoiceSocket(endpoint, guildId, userId, sessionId, token) {
    this.disconnectVoice();
    if (!endpoint) return;
    this.voiceSocket = new VoiceSocket(this);
    this.voiceSocket.connect(
      endpoint.split(":")[0],
      guildId, userId, sessionId, token
    );
  }
  disconnectVoice() {
    if (this.voiceSocket) {
      if (this.connected)
        this.voiceStateUpdate(null, null);

      this.voiceSocket.disconnect(null, true);
      this.voiceSocket = null;
    }
  }
  toJSON() { return `[GatewaySocket ${this.gatewayURL}]`; }
}

module.exports = GatewaySocket;
<|endoftext|>


<commit_before>var net = require('net')
var EventEmitter = require('events').EventEmitter;

function VarnishClient(host, port, ready_callback) {

    var self = this;
    var ready = false;
    var cmd_callback = null;
    var client = null;
    var connected = false;
    var connecting = false;

    function log() {
        console.log.apply(console, arguments);
    }

    function connect() {
        if(connecting || connected ) return;
        connecting = true;
        log("VARNISH: connection");
        ready = false;
        if(!client) {
            client = net.createConnection(port, host);
            client.on('connect', function () {
                log("VARNISH: connected");
                connected = true;
                self.emit('connect');
                connecting = false;
            });
        } else {
            client.connect(port, host);
        }
    }
    self.connect = connect;

    connect();

    client.on('data', function (data) {
        data = data.toString();
        lines = data.split('\n', 2);
        if(lines.length == 2) {
            var tk = lines[0].split(' ')
            var code = parseInt(tk[0], 10);
            var body_length = parseInt(tk[1], 10);
            var body = lines[1];
            if(!ready) {
                ready = true;
                ready_callback && ready_callback();
                self.emit('ready');
            } else if(cmd_callback) {
                var c = cmd_callback
                cmd_callback = null;
                c(null, code, body);
                self.emit('response', code, body)
            }
        }

    });

    client.on('error', function(err) {
        log("[ERROR] some problem in varnish connection", err);
        self.emit('error', err);
    });

    client.on('close', function(e) {
        log("[INFO] closed varnish connection");
        self.close();
        connected = false;
        connecting = false;
    });

    // sends the command to the server
    function _send(cmd, callback) {
      cmd_callback = callback;
      if(connected) {
        client.write(cmd + '\n');
      } else {
        connect();
      }
    }

    // run command if there is no peding response
    // fist param of the callback are the error, null
    // if all went ok
    this.run_cmd = function(cmd, callback) {
       if(!connected) {
           connect();
       }
       if(!cmd_callback) {
         _send(cmd, callback);
       } else {
         callback('response pending');
         self.emit('error', {
            code: 'RESPONSE_PENDING',
            message: 'there is a response pending'
         });
       }
    }

    // close the connection
    this.close = function() {
       client.end();
       ready = false;
       self.emit('close');
    }
}
VarnishClient.prototype = new EventEmitter();

module.exports = VarnishClient;
<commit_msg>Fix leak of global "lines" variable (closes #1)<commit_after>var net = require('net')
var EventEmitter = require('events').EventEmitter;

function VarnishClient(host, port, ready_callback) {

    var self = this;
    var ready = false;
    var cmd_callback = null;
    var client = null;
    var connected = false;
    var connecting = false;

    function log() {
        console.log.apply(console, arguments);
    }

    function connect() {
        if(connecting || connected ) return;
        connecting = true;
        log("VARNISH: connection");
        ready = false;
        if(!client) {
            client = net.createConnection(port, host);
            client.on('connect', function () {
                log("VARNISH: connected");
                connected = true;
                self.emit('connect');
                connecting = false;
            });
        } else {
            client.connect(port, host);
        }
    }
    self.connect = connect;

    connect();

    client.on('data', function (data) {
        data = data.toString();
        var lines = data.split('\n', 2);
        if(lines.length == 2) {
            var tk = lines[0].split(' ')
            var code = parseInt(tk[0], 10);
            var body_length = parseInt(tk[1], 10);
            var body = lines[1];
            if(!ready) {
                ready = true;
                ready_callback && ready_callback();
                self.emit('ready');
            } else if(cmd_callback) {
                var c = cmd_callback
                cmd_callback = null;
                c(null, code, body);
                self.emit('response', code, body)
            }
        }

    });

    client.on('error', function(err) {
        log("[ERROR] some problem in varnish connection", err);
        self.emit('error', err);
    });

    client.on('close', function(e) {
        log("[INFO] closed varnish connection");
        self.close();
        connected = false;
        connecting = false;
    });

    // sends the command to the server
    function _send(cmd, callback) {
      cmd_callback = callback;
      if(connected) {
        client.write(cmd + '\n');
      } else {
        connect();
      }
    }

    // run command if there is no peding response
    // fist param of the callback are the error, null
    // if all went ok
    this.run_cmd = function(cmd, callback) {
       if(!connected) {
           connect();
       }
       if(!cmd_callback) {
         _send(cmd, callback);
       } else {
         callback('response pending');
         self.emit('error', {
            code: 'RESPONSE_PENDING',
            message: 'there is a response pending'
         });
       }
    }

    // close the connection
    this.close = function() {
       client.end();
       ready = false;
       self.emit('close');
    }
}
VarnishClient.prototype = new EventEmitter();

module.exports = VarnishClient;
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth').OAuth2Strategy;

/**
 * `Strategy` constructor.
 *
 * The ArmorText authentication strategy authenticates requests by delegating
 * to ArmorText using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      your ArmorText application's client id
 *   - `clientSecret`  your ArmorText application's client secret
 *   - `callbackURL`   URL to which ArmorText will redirect the user after granting authorization
 *
 * Examples:
 *
 *     passport.use(new ArmorTextStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/armortext/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://demo.armortext.com/oauth2/authorize';
  options.tokenURL = options.tokenURL || 'https://demo.armortext.com/oauth2/token';
  this.profileUrl = options.profileUrl || "https://demo.armortext.com/api/v1/users/me/profile";

  OAuth2Strategy.call(this, options, verify);
  this.name = 'armortext';
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from ArmorText.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `armortext`
 *   - `id`               unique identifier for this user.
 *   - `username`         the user's ArmorText username
 *   - `displayName`      the user's auth username
 *   - `name.familyName`  user's last name
 *   - `name.givenName`   user's first name
 *   - `gender`           the user's gender: `male` or `female`
 *   - `emails`           the proxied or contact email address granted by the user
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.useAuthorizationHeaderforGET(true);

  this._oauth2.get(this.profileUrl, accessToken, function (err, body, res) {
    if (err) { return done(err); }

    try {
      var json = JSON.parse(body);

      var profile = { provider: 'armortext' };

      profile.id = json.id;
      profile.username = json.login;
      profile.displayName = json.first_name + ' ' + json.last_name;
      profile.name = {familyName: json.first_name, givenName: last_name};
      profile.gender = json.gender;
      profile.emails = [{ value: json.email }];

      profile._raw = body;
      profile._json = json;
      done(null, profile);
    } catch(e) {
      done(e);
    }
  });
}

/** The default oauth2 strategy puts the access_token into Authorization: header AND query string
  * witch is a violation of the RFC so lets override and not add the header and supply only the token for qs.
  */
Strategy.prototype.get = function(url, access_token, callback) {
  this._oauth2._request("GET", url, {}, "", access_token, callback );
};

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;<commit_msg>updated default url settings<commit_after>/**
 * Module dependencies.
 */
var util = require('util')
  , OAuth2Strategy = require('passport-oauth').OAuth2Strategy;

/**
 * `Strategy` constructor.
 *
 * The ArmorText authentication strategy authenticates requests by delegating
 * to ArmorText using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      your ArmorText application's client id
 *   - `clientSecret`  your ArmorText application's client secret
 *   - `callbackURL`   URL to which ArmorText will redirect the user after granting authorization
 *
 * Examples:
 *
 *     passport.use(new ArmorTextStrategy({
 *         clientID: '123-456-789',
 *         clientSecret: 'shhh-its-a-secret'
 *         callbackURL: 'https://www.example.net/auth/armortext/callback'
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://app.armortext.co/oauth/authorize';
  options.tokenURL = options.tokenURL || 'https://app.armortext.co/oauth/token';
  this.profileUrl = options.profileUrl || "https://app.armortext.co/api/v1/users/me/profile";

  OAuth2Strategy.call(this, options, verify);
  this.name = 'armortext';
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from ArmorText.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `armortext`
 *   - `id`               unique identifier for this user.
 *   - `username`         the user's ArmorText username
 *   - `displayName`      the user's auth username
 *   - `name.familyName`  user's last name
 *   - `name.givenName`   user's first name
 *   - `gender`           the user's gender: `male` or `female`
 *   - `emails`           the proxied or contact email address granted by the user
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
Strategy.prototype.userProfile = function(accessToken, done) {
  this._oauth2.useAuthorizationHeaderforGET(true);

  this._oauth2.get(this.profileUrl, accessToken, function (err, body, res) {
    if (err) { return done(err); }

    try {
      var json = JSON.parse(body);

      var profile = { provider: 'armortext' };

      profile.id = json.id;
      profile.username = json.login;
      profile.displayName = json.first_name + ' ' + json.last_name;
      profile.name = {familyName: json.first_name, givenName: last_name};
      profile.gender = json.gender;
      profile.emails = [{ value: json.email }];

      profile._raw = body;
      profile._json = json;
      done(null, profile);
    } catch(e) {
      done(e);
    }
  });
}

/** The default oauth2 strategy puts the access_token into Authorization: header AND query string
  * witch is a violation of the RFC so lets override and not add the header and supply only the token for qs.
  */
Strategy.prototype.get = function(url, access_token, callback) {
  this._oauth2._request("GET", url, {}, "", access_token, callback );
};

/**
 * Expose `Strategy`.
 */
module.exports = Strategy;<|endoftext|>


<commit_before>import clone from 'clone'
import update from 'immutability-helper'

import queryParams from '../common/query-params'

const defaultConfig = {
  autoPlan: true,
  debouncePlanTimeMs: 0
}

// construct the initial/default query
const defaultQuery = { routingType: 'ITINERARY' }
queryParams.filter(qp => 'default' in qp).forEach(qp => {
  defaultQuery[qp.name] = qp.default
})

// TODO: parse and merge URL query params w/ default query

// TODO: fire planTrip action if default query is complete/error-free

function createOtpReducer (config, initialQuery) {
  defaultQuery.mode = defaultQuery.mode || config.modes[0] || 'TRANSIT,WALK'
  // populate query by merging any provided query params w/ the default params
  const currentQuery = Object.assign(defaultQuery, initialQuery)
  const initialState = {
    config: Object.assign(defaultConfig, config),
    currentQuery,
    location: {
      currentPosition: null,
      sessionSearches: [],
      nearbyStops: []
    },
    searches: {},
    transitIndex: {
      stops: {}
    },
    activeSearchId: 0,
    overlay: {
      bikeRental: {
        stations: []
      }
    }
  }

  return (state = initialState, action) => {
    const searchId = action.payload && action.payload.searchId
    switch (action.type) {
      case 'ROUTING_REQUEST':
        return update(state, {
          searches: { [searchId]: { $set: {
            activeItinerary: 0,
            activeLeg: null,
            activeStep: null,
            pending: true,
            query: clone(state.currentQuery),
            response: null,
            type: action.payload.routingType
          }}}
        })
      case 'ROUTING_ERROR':
        return update(state, {
          searches: {[searchId]: {
            response: {
              $set: {
                error: action.payload.error
              }
            },
            pending: {$set: false}
          }},
          activeSearchId: { $set: searchId }
        })
      case 'ROUTING_RESPONSE':
        return update(state, {
          searches: {[searchId]: {
            response: {$set: action.payload.response},
            pending: {$set: false}
          }},
          activeSearchId: { $set: searchId }
        })
      case 'BIKE_RENTAL_REQUEST':
        return update(state, {
          overlay: {
            bikeRental: {
              pending: {$set: true},
              error: {$set: null}
            }
          }
        })
      case 'BIKE_RENTAL_ERROR':
        return update(state, {
          overlay: {
            bikeRental: {
              pending: {$set: false},
              error: {$set: action.payload}
            }
          }
        })
      case 'BIKE_RENTAL_RESPONSE':
        return update(state, {
          overlay: {
            bikeRental: {
              stations: {$set: action.payload.stations},
              pending: {$set: false}
            }
          }
        })
      case 'SET_ACTIVE_ITINERARY':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: {
            activeItinerary: { $set: action.payload.index },
            activeLeg: { $set: null },
            activeStep: { $set: null }
          } } })
        }
        return state
      case 'SET_ACTIVE_LEG':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: {
            activeLeg: { $set: action.payload.index },
            activeStep: { $set: null }
          } } })
        }
        return state
      case 'SET_ACTIVE_STEP':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: { activeStep: { $set: action.payload.index } } } })
        }
        return state
      case 'SET_LOCATION':
        return update(state, { currentQuery: { [action.payload.type]: { $set: action.payload.location } } })
      case 'CLEAR_LOCATION':
        return update(state, { currentQuery: { [action.payload.type]: { $set: null } } })

      case 'SET_QUERY_PARAM':
        console.log('merging QPs', action.payload)
        return update(state, { currentQuery: { $merge: action.payload } })
      case 'FORM_CHANGED':
        return update(state, { activeSearchId: { $set: null } })

      case 'SET_AUTOPLAN':
        return update(state, { config: { autoPlan: { $set: action.payload.autoPlan } } })
      case 'SET_MAP_CENTER':
        return update(state, { config: { map: {
          initLat: { $set: action.payload.lat },
          initLon: { $set: action.payload.lon }
        } } })

      case 'POSITION_RESPONSE':
        return update(state, { location: { currentPosition: { $set: action.payload.position } } })
      case 'ADD_LOCATION_SEARCH':
        return update(state, { location: { sessionSearches: { $unshift: [action.payload.location] } } })

      case 'NEARBY_STOPS_RESPONSE':
        const stopLookup = {}
        action.payload.stops.forEach(s => { stopLookup[s.id] = s })
        return update(state, {
          location: { nearbyStops: { $set: action.payload.stops.map(s => s.id) } },
          transitIndex: { stops: { $merge: stopLookup } }
        })
      case 'ROUTES_AT_STOP_RESPONSE':
        return update(state, { transitIndex: { stops: { [action.payload.stopId]: { routes: { $set: action.payload.routes } } } } })

      default:
        return state
    }
  }
}

export default createOtpReducer
<commit_msg>fix(api): Store the active searchId in state at beginning of each request<commit_after>import clone from 'clone'
import update from 'immutability-helper'

import queryParams from '../common/query-params'

const defaultConfig = {
  autoPlan: true,
  debouncePlanTimeMs: 0
}

// construct the initial/default query
const defaultQuery = { routingType: 'ITINERARY' }
queryParams.filter(qp => 'default' in qp).forEach(qp => {
  defaultQuery[qp.name] = qp.default
})

// TODO: parse and merge URL query params w/ default query

// TODO: fire planTrip action if default query is complete/error-free

function createOtpReducer (config, initialQuery) {
  defaultQuery.mode = defaultQuery.mode || config.modes[0] || 'TRANSIT,WALK'
  // populate query by merging any provided query params w/ the default params
  const currentQuery = Object.assign(defaultQuery, initialQuery)
  const initialState = {
    config: Object.assign(defaultConfig, config),
    currentQuery,
    location: {
      currentPosition: null,
      sessionSearches: [],
      nearbyStops: []
    },
    searches: {},
    transitIndex: {
      stops: {}
    },
    activeSearchId: 0,
    overlay: {
      bikeRental: {
        stations: []
      }
    }
  }

  return (state = initialState, action) => {
    const searchId = action.payload && action.payload.searchId
    switch (action.type) {
      case 'ROUTING_REQUEST':
        return update(state, {
          searches: { [searchId]: { $set: {
            activeItinerary: 0,
            activeLeg: null,
            activeStep: null,
            pending: true,
            query: clone(state.currentQuery),
            response: null,
            type: action.payload.routingType
          }}},
          activeSearchId: { $set: searchId }
        })
      case 'ROUTING_ERROR':
        return update(state, {
          searches: {[searchId]: {
            response: {
              $set: {
                error: action.payload.error
              }
            },
            pending: {$set: false}
          }}
        })
      case 'ROUTING_RESPONSE':
        return update(state, {
          searches: {[searchId]: {
            response: {$set: action.payload.response},
            pending: {$set: false}
          }}
        })
      case 'BIKE_RENTAL_REQUEST':
        return update(state, {
          overlay: {
            bikeRental: {
              pending: {$set: true},
              error: {$set: null}
            }
          }
        })
      case 'BIKE_RENTAL_ERROR':
        return update(state, {
          overlay: {
            bikeRental: {
              pending: {$set: false},
              error: {$set: action.payload}
            }
          }
        })
      case 'BIKE_RENTAL_RESPONSE':
        return update(state, {
          overlay: {
            bikeRental: {
              stations: {$set: action.payload.stations},
              pending: {$set: false}
            }
          }
        })
      case 'SET_ACTIVE_ITINERARY':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: {
            activeItinerary: { $set: action.payload.index },
            activeLeg: { $set: null },
            activeStep: { $set: null }
          } } })
        }
        return state
      case 'SET_ACTIVE_LEG':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: {
            activeLeg: { $set: action.payload.index },
            activeStep: { $set: null }
          } } })
        }
        return state
      case 'SET_ACTIVE_STEP':
        if (state.activeSearchId !== null) {
          return update(state, { searches: { [state.activeSearchId]: { activeStep: { $set: action.payload.index } } } })
        }
        return state
      case 'SET_LOCATION':
        return update(state, { currentQuery: { [action.payload.type]: { $set: action.payload.location } } })
      case 'CLEAR_LOCATION':
        return update(state, { currentQuery: { [action.payload.type]: { $set: null } } })

      case 'SET_QUERY_PARAM':
        console.log('merging QPs', action.payload)
        return update(state, { currentQuery: { $merge: action.payload } })
      case 'FORM_CHANGED':
        return update(state, { activeSearchId: { $set: null } })

      case 'SET_AUTOPLAN':
        return update(state, { config: { autoPlan: { $set: action.payload.autoPlan } } })
      case 'SET_MAP_CENTER':
        return update(state, { config: { map: {
          initLat: { $set: action.payload.lat },
          initLon: { $set: action.payload.lon }
        } } })

      case 'POSITION_RESPONSE':
        return update(state, { location: { currentPosition: { $set: action.payload.position } } })
      case 'ADD_LOCATION_SEARCH':
        return update(state, { location: { sessionSearches: { $unshift: [action.payload.location] } } })

      case 'NEARBY_STOPS_RESPONSE':
        const stopLookup = {}
        action.payload.stops.forEach(s => { stopLookup[s.id] = s })
        return update(state, {
          location: { nearbyStops: { $set: action.payload.stops.map(s => s.id) } },
          transitIndex: { stops: { $merge: stopLookup } }
        })
      case 'ROUTES_AT_STOP_RESPONSE':
        return update(state, { transitIndex: { stops: { [action.payload.stopId]: { routes: { $set: action.payload.routes } } } } })

      default:
        return state
    }
  }
}

export default createOtpReducer
<|endoftext|>


<commit_before>// import templates
var tpl = require('components/tooltip.html');
var Component = require('components/component');
var component = new Component(tpl, 'tooltip');

var utils = require('utils');
var $ = utils.$;
var ol = require('ol');
var map = require('olMap').get();
map.getViewport().appendChild(component.getTemplate('tooltip'));
var vectors = require('vectors');
var measure = require('measure');

var select = new ol.interaction.Select({
  condition: ol.events.condition.pointerMove,
  layers: vectors.getLayers().getArray()
});

map.addInteraction(select);

select.on('select', function(e) {
  var html, pixel;
  var tooltip = $('#tooltip');
  if (e.selected.length > 0) {
    var feature = e.selected[0];
    pixel = e.mapBrowserEvent.pixel;
    html = feature.getProperties().name || feature.getProperties().title;
    var geom = feature.getGeometry();
    if (geom.getLength) {
      // get length for linestrings
      var lenHav = measure.getLength(geom, map.getView().getProjection());
      html += ' ' + (Math.round(lenHav * 0.1) / 100) + 'km';
    }
  }
  if (html) {
    tooltip.innerHTML = html;
    tooltip.style.left = (pixel[0] + 10) + 'px';
    tooltip.style.top = (pixel[1] + 10) + 'px';
    tooltip.style.display = 'block';
    // change cursor to indicate to users that they can click on this point
    map.getTarget().style.cursor = 'pointer';
  } else {
    tooltip.style.display = 'none';
    map.getTarget().style.cursor = '';
  }
});
<commit_msg>Allow for no title/name on tooltip<commit_after>// import templates
var tpl = require('components/tooltip.html');
var Component = require('components/component');
var component = new Component(tpl, 'tooltip');

var utils = require('utils');
var $ = utils.$;
var ol = require('ol');
var map = require('olMap').get();
map.getViewport().appendChild(component.getTemplate('tooltip'));
var vectors = require('vectors');
var measure = require('measure');

var select = new ol.interaction.Select({
  condition: ol.events.condition.pointerMove,
  layers: vectors.getLayers().getArray()
});

map.addInteraction(select);

select.on('select', function(e) {
  var html, pixel;
  var tooltip = $('#tooltip');
  if (e.selected.length > 0) {
    var feature = e.selected[0];
    pixel = e.mapBrowserEvent.pixel;
    html = feature.getProperties().name || feature.getProperties().title || '';
    var geom = feature.getGeometry();
    if (geom.getLength) {
      // get length for linestrings
      var lenHav = measure.getLength(geom, map.getView().getProjection());
      html += ' ' + (Math.round(lenHav * 0.1) / 100) + 'km';
    }
  }
  if (html) {
    tooltip.innerHTML = html;
    tooltip.style.left = (pixel[0] + 10) + 'px';
    tooltip.style.top = (pixel[1] + 10) + 'px';
    tooltip.style.display = 'block';
    // change cursor to indicate to users that they can click on this point
    map.getTarget().style.cursor = 'pointer';
  } else {
    tooltip.style.display = 'none';
    map.getTarget().style.cursor = '';
  }
});
<|endoftext|>