<commit_before>'use strict';
var superagent = require('superagent');
var config = require('../../config');
var _ = require("lodash");
var moment = require('moment');

exports.index = function(req, res) {
  res.send({data: req.params.fromCountry});
};

exports.searchAirport = function(req, res) {
  superagent.get(config.api + '/picker/en/' + req.params.airport)
    .set('Accept', 'application/json')
    .end(function(err, response) {
      if (err) {
        return res.status(500).send('Something went wrong :(');
      }
      res.send(JSON.parse(response.text));
    });
};

exports.findCheapestFlight = function(travelingInfo, socket) {

   //UPDATE THE TRAVELING INFO FOR THE FIRST FLIGHT
   travelingInfo = initFirstFlight(travelingInfo);
   flyNormal(travelingInfo, socket);

};

// Returns the optimal distance from home at current time in trip
function optimalDfh(currentDay, tripLength, dfhMax) {
  var maxDfh = 20000 * dfhMax;
  var optimalDfh;

  if (currentDay <= tripLength / 2) {
    optimalDfh = (maxDfh * currentDay) / (tripLength / 2);
  }
  else {
    optimalDfh = (maxDfh * (tripLength - currentDay)) / (tripLength / 2);
  }
  return optimalDfh;
}

function initFirstFlight(travelingInfo){

    var duration = createStopDuration(travelingInfo.tripDuration.start, travelingInfo.tripDuration.end);
    travelingInfo.firstFlight = true;
    travelingInfo.tripDuration.stopDuration = duration;

    return travelingInfo;
   }

function goHome(travelingInfo,currentLocation){
    //total amount of days where you should be thinking about going home
    var dayAmount = 5;
    if ((travelingInfo.tripDuration.stopDuration.totalDays - dayAmount) < moment(travelingInfo.startingPoint.selectedAirport.start).diff(moment(currentLocation.from), 'days')) {
    //MABY  travelingInfo.departure.to = moment(travelingInfo.departure.to).add(100,'days').format('YYYY-MM-DD')
      console.log("GOHOME");
      return true;
    }

    return false;
}

//
function modifyFlightPath(flightPath){

  if(flightPath.length === 0){

    console.log("there is no world trip for youur airport");
    return flightPath;

  }

  //if there are still items in the array
  if(flightPath[flightPath.length-1].length > 1){

    flightPath[flightPath.length-1].shift();

    return flightPath;

  }

  else{

    flightPath[flightPath.length-1].pop();

    return modifyFlightPath(flightPath);
  }
}

function flyNormal(travelingInfo, socket) {
  //FIND AWAY HOME BROTHER

  //maby change departur.to here so we deffently get home
    console.log(travelingInfo);

  if(travelingInfo.firstFlight){
      var url = [
      config.api,
      'livestore',
      'en',
      travelingInfo.startingPoint.selectedAirport.country_code,
      'per-country',
      travelingInfo.startingPoint.selectedAirport.airportCode,
      travelingInfo.tripDuration.start,
      travelingInfo.tripDuration.start
    ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';
  }

  else{
    var currentLocation = travelingInfo.flightPath[travelingInfo.flightPath.length-1][travelingInfo.flightPath[travelingInfo.flightPath.length-1].length-1]
    var shouldGoHome = goHome(travelingInfo,currentLocation);

    if (shouldGoHome){
      var currentLocation = travelingInfo.flightPath[travelingInfo.flightPath.length-1][travelingInfo.flightPath[travelingInfo.flightPath.length-1].length-1]

      var url = [
        config.api,
        'livestore',
        'en',
        currentLocation.country,
        'per-airport',
        currentLocation.airportCode,
        travelingInfo.startingPoint.selectedAirport.airportCode,
        currentLocation.from,
        currentLocation.to,
      ].join('/') + '?currency=USD&stay=1-365&include_split=true&airport-format=full&fare-format=full&id=H4cK3r';
    }

     else{
      var url = [
          config.api,
          'livestore',
          'en',
          currentLocation.country,
          'per-country',
          currentLocation.airportCode,
          currentLocation.from,
          currentLocation.to
        ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';
      }
    }

  //DO THE REQUEST
  superagent.get(url)
   .end(function(err, response) {
    if (err) {
      socket.emit('error', 'something went wrong in the socket');
      return;
    }

    //HANDLE THE RESULT----------------------------------------------------------

    var responseData = JSON.parse(response.text);
    var fares = responseData.fares;
    var airports = responseData.airports;

    console.log(responseData);
    //DEADZONE
    //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    if(fares.length === 0){
      var newFlightPath = modifyFlightPath(travelingInfo.flightPath);

      if (newFlightPath.length < 1){
        travelingInfo.tripDuration.start
        console.log("there is no trip for this airport");
        //send to the socket and end the connection

        //try to lengthen the first
      }
      travelingInfo.flightPath = newFlightPath;

      //send the array to the socket

      flyNormal(travelingInfo,socket);
      socket.emit('flightPath', travelingInfo.flightPath);
    }
    //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

    else {
      //insertion inside history array -----------------
      var bestFlights = [];

      //Take the 3 best flights if there are more then 3
      if(fares.length > 3){
        bestFlights = fares.splice(0,3);
      }

      //else just take the ones who are there
      else{
        bestFlights = fares;
      }
      console.log(bestFlights);
      //push it to the end of the history array
      travelingInfo.flightPath.push(bestFlights);

      flyNormal(travelingInfo,socket);
      socket.emit('flightPath', travelingInfo.flightPath);
    }

    //-----------------------------------------------

    //
    //Get the countrys we have allreddy been to
  /*  var countries = _.map(travelingInfo.flights, function(item) {
      return item['departureCountry'].country;
    });
  */

    //var flightIndex = findBestFlight(fares, airports, countries, travelingInfo);

  });
}

function createTravelInfo(cheapestFlight,airports,travelingInfo){

  var travelInfo = {
      fromAirport: cheapestFlight.a,
      destAirport: cheapestFlight.b,
      price: cheapestFlight.conv_fare,
      departure: cheapestFlight.d1,
      departureCountry: travelingInfo.departure,
      stopDuration: travelingInfo.stopDuration,
      endDate:travelingInfo.endDate,
      stateData: 'newDest',
      flightPath : travelingInfo.flightPath,
    };

    if (airports[cheapestFlight.b]) {
      travelInfo.arrivalCountry = {
        airportCode: airports[cheapestFlight.b].a_i,
        airportName: airports[cheapestFlight.b].a_n,
        countryCode: airports[cheapestFlight.b].cc_c,
        countryName: airports[cheapestFlight.b].cc_n,
        city: airports[cheapestFlight.b].ci_n,
        lat: airports[cheapestFlight.b].lat,
        lon: airports[cheapestFlight.b].lon,
        state: airports[cheapestFlight.b].r_n,
        state_short: airports[cheapestFlight.b].r_c,
      };
    }
    return travelInfo;

}

function findBestFlight(fares, airports, countries, travelingInfo){
  var bestFlightIndex = -1;
  var bestFlightDistance = -1;

  var totalDays = travelingInfo.stopDuration.totalDays;
  var stopDuration = travelingInfo.stopDuration.highBound;
  var dfhMax = travelingInfo.stopDuration.dfhMax;

  for (var i = 0; i < fares.length; i++) {

    // Don't travel to same country again
    if (countries.indexOf(airports[fares[i].b].cc_c)  > -1) continue;

    var departureDay = moment(fares[i].d1).diff(moment(travelingInfo.stopDuration.startDate), 'days');
    var flightDist = findDistance(travelingInfo.startingPoint.location.lat, travelingInfo.startingPoint.location.lng, airports[fares[i].b].lat, airports[fares[i].b].lon);
    var diff = Math.abs(optimalDfh(departureDay, totalDays, dfhMax) - flightDist);

    if ( diff < bestFlightDistance || bestFlightIndex === -1) {
        bestFlightIndex = i;
        bestFlightDistance = flightDist;
    }
  }

  // If there is no best flight return first
  if (bestFlightIndex === -1 && fares.length > 0) bestFlightIndex = 0;

  return bestFlightIndex;
}

function isDeadend(flight, cb) {
  var url = [
    config.api,
    'livestore',
    'en',
    flight.arrivalCountry.countryCode,
    'per-country',
    flight.destAirport,
    moment(flight.departureCountry.to).add(flight.stopDuration.lowBound, 'days').format('YYYY-MM-DD'),
    moment(flight.departureCountry.to).add(flight.stopDuration.highBound, 'days').format('YYYY-MM-DD')
  ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';

  superagent.get(url)
   .end(function(err, response) {
    if (err) {
      socket.emit('error', 'something went wrong in the socket');
      return;
    }
    var fares = JSON.parse(response.text).fares;
    console.log(fares.length);
    if(fares.length > 0){
      return cb(false);
    }
    else{
      return cb(true);;
    }
  });
}

function findDistance(lat1, lon1, lat2, lon2){
  var dLat = deg2rad(lat2 - lat1);
  var dLon = deg2rad(lon2 - lon1);
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = config.earthRadius * c; //distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180);
}

//derp
function createStopDuration(startDate, endDate){

  var days = moment(endDate).diff(moment(startDate), 'days');

  var duration = {
    lowBound: '',
    highBound: '',
    dfhMax: 0,
    priceW: 0,
    dfhW: 0,
    totalDays: days,
  };

  if (days >= 24 * 7) {
    duration.lowBound = 7;
    duration.highBound = 21;
    duration.dfhMax = 1;
    duration.priceW = 0.8;
    duration.dfhW = 0.25;
  } else if (days >= 12 * 7) {
    duration.lowBound = 5;
    duration.highBound = 10;
    duration.dfhMax = 0.75;
    duration.priceW = 0.6;
    duration.dfhW = 0.50;
  } else if (days >= 4 * 7) {
    duration.lowBound = 3;
    duration.highBound = 8;
    duration.dfhMax = 0.5;
    duration.priceW = 0.4;
    duration.dfhW = 0.75;
  } else {
    duration.lowBound = 2;
    duration.highBound = 4;
    duration.dfhMax = 0.25;
    duration.priceW = 0;
    duration.dfhW = 1;
  }

  return duration;
}
<commit_msg>minor fix<commit_after>'use strict';
var superagent = require('superagent');
var config = require('../../config');
var _ = require("lodash");
var moment = require('moment');

exports.index = function(req, res) {
  res.send({data: req.params.fromCountry});
};

exports.searchAirport = function(req, res) {
  superagent.get(config.api + '/picker/en/' + req.params.airport)
    .set('Accept', 'application/json')
    .end(function(err, response) {
      if (err) {
        return res.status(500).send('Something went wrong :(');
      }
      res.send(JSON.parse(response.text));
    });
};

exports.findCheapestFlight = function(travelingInfo, socket) {

   //UPDATE THE TRAVELING INFO FOR THE FIRST FLIGHT
   travelingInfo = initFirstFlight(travelingInfo);
   flyNormal(travelingInfo, socket);

};

// Returns the optimal distance from home at current time in trip
function optimalDfh(currentDay, tripLength, dfhMax) {
  var maxDfh = 20000 * dfhMax;
  var optimalDfh;

  if (currentDay <= tripLength / 2) {
    optimalDfh = (maxDfh * currentDay) / (tripLength / 2);
  }
  else {
    optimalDfh = (maxDfh * (tripLength - currentDay)) / (tripLength / 2);
  }
  return optimalDfh;
}

function initFirstFlight(travelingInfo){

    var duration = createStopDuration(travelingInfo.tripDuration.start, travelingInfo.tripDuration.end);
    travelingInfo.firstFlight = true;
    travelingInfo.tripDuration.stopDuration = duration;

    return travelingInfo;
   }

function goHome(travelingInfo,currentLocation){
    //total amount of days where you should be thinking about going home
    var dayAmount = 5;
    if ((travelingInfo.tripDuration.stopDuration.totalDays - dayAmount) < moment(travelingInfo.startingPoint.selectedAirport.start).diff(moment(currentLocation.from), 'days')) {
    //MABY  travelingInfo.departure.to = moment(travelingInfo.departure.to).add(100,'days').format('YYYY-MM-DD')
      console.log("GOHOME");
      return true;
    }

    return false;
}

//
function modifyFlightPath(flightPath){

  if(flightPath.length === 0){

    console.log("there is no world trip for youur airport");
    return flightPath;

  }

  //if there are still items in the array
  if(flightPath[flightPath.length-1].length > 1){

    flightPath[flightPath.length-1].shift();

    return flightPath;

  }

  else{

    flightPath[flightPath.length-1].pop();

    return modifyFlightPath(flightPath);
  }
}

function flyNormal(travelingInfo, socket) {
  //FIND AWAY HOME BROTHER

  //maby change departur.to here so we deffently get home
    console.log(travelingInfo);

  if(travelingInfo.firstFlight){
      var url = [
      config.api,
      'livestore',
      'en',
      travelingInfo.startingPoint.selectedAirport.country_code,
      'per-country',
      travelingInfo.startingPoint.selectedAirport.airportCode,
      travelingInfo.tripDuration.start,
      travelingInfo.tripDuration.start
    ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';
  }

  else{
    var currentLocation = travelingInfo.flightPath[travelingInfo.flightPath.length-1][travelingInfo.flightPath[travelingInfo.flightPath.length-1].length-1]
    var shouldGoHome = goHome(travelingInfo,currentLocation);

    if (shouldGoHome){
      var currentLocation = travelingInfo.flightPath[travelingInfo.flightPath.length-1][travelingInfo.flightPath[travelingInfo.flightPath.length-1].length-1]

      var url = [
        config.api,
        'livestore',
        'en',
        currentLocation.country,
        'per-airport',
        currentLocation.airportCode,
        travelingInfo.startingPoint.selectedAirport.airportCode,
        currentLocation.from,
        currentLocation.to,
      ].join('/') + '?currency=USD&stay=1-365&include_split=true&airport-format=full&fare-format=full&id=H4cK3r';
    }

     else{
      var url = [
          config.api,
          'livestore',
          'en',
          currentLocation.country,
          'per-country',
          currentLocation.airportCode,
          currentLocation.from,
          currentLocation.to
        ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';
      }
    }

  //DO THE REQUEST
  superagent.get(url)
   .end(function(err, response) {
    if (err) {
      socket.emit('error', 'something went wrong in the socket');
      return;
    }

    //HANDLE THE RESULT----------------------------------------------------------

    var responseData = JSON.parse(response.text);
    var fares = responseData.fares;
    var airports = responseData.airports;

    console.log(responseData);
    //DEADZONE
    //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    if(fares.length === 0){
      var newFlightPath = modifyFlightPath(travelingInfo.flightPath);

      if (newFlightPath.length < 1){
        travelingInfo.tripDuration.start
        console.log("there is no trip for this airport");
        return;
        //send to the socket and end the connection

        //try to lengthen the first
      }
      travelingInfo.flightPath = newFlightPath;

      //send the array to the socket

      flyNormal(travelingInfo,socket);
      socket.emit('updateFlightPath', travelingInfo.flightPath);
    }
    //||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||

    else {
      //insertion inside history array -----------------
      var bestFlights = [];

      //Take the 3 best flights if there are more then 3
      if(fares.length > 3){
        bestFlights = fares.splice(0,3);
      }

      //else just take the ones who are there
      else{
        bestFlights = fares;
      }
      console.log(bestFlights);
      //push it to the end of the history array
      travelingInfo.flightPath.push(bestFlights);

      socket.emit('updateFlightPath', travelingInfo.flightPath);

     var newLocation = travelingInfo.flightPath[travelingInfo.flightPath.length-1][travelingInfo.flightPath[travelingInfo.flightPath.length-1].length-1]

      if(newLocation.a_i === startingPoint.selectedAirport.airportCode){
        return;
      }
      else{
        flyNormal(travelingInfo,socket);
      }
    }

    //-----------------------------------------------

    //
    //Get the countrys we have allreddy been to
  /*  var countries = _.map(travelingInfo.flights, function(item) {
      return item['departureCountry'].country;
    });
  */

    //var flightIndex = findBestFlight(fares, airports, countries, travelingInfo);

  });
}

function createTravelInfo(cheapestFlight,airports,travelingInfo){

  var travelInfo = {
      fromAirport: cheapestFlight.a,
      destAirport: cheapestFlight.b,
      price: cheapestFlight.conv_fare,
      departure: cheapestFlight.d1,
      departureCountry: travelingInfo.departure,
      stopDuration: travelingInfo.stopDuration,
      endDate:travelingInfo.endDate,
      stateData: 'newDest',
      flightPath : travelingInfo.flightPath,
    };

    if (airports[cheapestFlight.b]) {
      travelInfo.arrivalCountry = {
        airportCode: airports[cheapestFlight.b].a_i,
        airportName: airports[cheapestFlight.b].a_n,
        countryCode: airports[cheapestFlight.b].cc_c,
        countryName: airports[cheapestFlight.b].cc_n,
        city: airports[cheapestFlight.b].ci_n,
        lat: airports[cheapestFlight.b].lat,
        lon: airports[cheapestFlight.b].lon,
        state: airports[cheapestFlight.b].r_n,
        state_short: airports[cheapestFlight.b].r_c,
      };
    }
    return travelInfo;

}

function findBestFlight(fares, airports, countries, travelingInfo){
  var bestFlightIndex = -1;
  var bestFlightDistance = -1;

  var totalDays = travelingInfo.stopDuration.totalDays;
  var stopDuration = travelingInfo.stopDuration.highBound;
  var dfhMax = travelingInfo.stopDuration.dfhMax;

  for (var i = 0; i < fares.length; i++) {

    // Don't travel to same country again
    if (countries.indexOf(airports[fares[i].b].cc_c)  > -1) continue;

    var departureDay = moment(fares[i].d1).diff(moment(travelingInfo.stopDuration.startDate), 'days');
    var flightDist = findDistance(travelingInfo.startingPoint.location.lat, travelingInfo.startingPoint.location.lng, airports[fares[i].b].lat, airports[fares[i].b].lon);
    var diff = Math.abs(optimalDfh(departureDay, totalDays, dfhMax) - flightDist);

    if ( diff < bestFlightDistance || bestFlightIndex === -1) {
        bestFlightIndex = i;
        bestFlightDistance = flightDist;
    }
  }

  // If there is no best flight return first
  if (bestFlightIndex === -1 && fares.length > 0) bestFlightIndex = 0;

  return bestFlightIndex;
}

function isDeadend(flight, cb) {
  var url = [
    config.api,
    'livestore',
    'en',
    flight.arrivalCountry.countryCode,
    'per-country',
    flight.destAirport,
    moment(flight.departureCountry.to).add(flight.stopDuration.lowBound, 'days').format('YYYY-MM-DD'),
    moment(flight.departureCountry.to).add(flight.stopDuration.highBound, 'days').format('YYYY-MM-DD')
  ].join('/') + '?currency=USD&airport-format=full&fare-format=full&id=H4cK3r';

  superagent.get(url)
   .end(function(err, response) {
    if (err) {
      socket.emit('error', 'something went wrong in the socket');
      return;
    }
    var fares = JSON.parse(response.text).fares;
    console.log(fares.length);
    if(fares.length > 0){
      return cb(false);
    }
    else{
      return cb(true);;
    }
  });
}

function findDistance(lat1, lon1, lat2, lon2){
  var dLat = deg2rad(lat2 - lat1);
  var dLon = deg2rad(lon2 - lon1);
  var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.sin(dLon/2) * Math.sin(dLon/2);
  var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  var d = config.earthRadius * c; //distance in km
  return d;
}

function deg2rad(deg) {
  return deg * (Math.PI/180);
}

//derp
function createStopDuration(startDate, endDate){

  var days = moment(endDate).diff(moment(startDate), 'days');

  var duration = {
    lowBound: '',
    highBound: '',
    dfhMax: 0,
    priceW: 0,
    dfhW: 0,
    totalDays: days,
  };

  if (days >= 24 * 7) {
    duration.lowBound = 7;
    duration.highBound = 21;
    duration.dfhMax = 1;
    duration.priceW = 0.8;
    duration.dfhW = 0.25;
  } else if (days >= 12 * 7) {
    duration.lowBound = 5;
    duration.highBound = 10;
    duration.dfhMax = 0.75;
    duration.priceW = 0.6;
    duration.dfhW = 0.50;
  } else if (days >= 4 * 7) {
    duration.lowBound = 3;
    duration.highBound = 8;
    duration.dfhMax = 0.5;
    duration.priceW = 0.4;
    duration.dfhW = 0.75;
  } else {
    duration.lowBound = 2;
    duration.highBound = 4;
    duration.dfhMax = 0.25;
    duration.priceW = 0;
    duration.dfhW = 1;
  }

  return duration;
}
<|endoftext|>


<commit_before>var request = require('superagent');
var bingUtils = require('./bingUtils');
var commonUtils = require('./commonUtils');
var dbUtils = require('./dbUtils');
var weibo = require('../configs/config').weibo;
var mailUtils = require('./mailUtils');
var cookie = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36' };
var update_url_text = 'https://api.weibo.com/2/statuses/upload_url_text.json';
module.exports = {
    /**
     * 发送微博
     * @callback
     * @isAuto 是否自动发送(true,false)
     */
    update: function(callback, isAuto) {
        var date = new Date();
        var y = date.getFullYear();
        var m = Number(date.getMonth()) + 1 < 10 ? '0' + (Number(date.getMonth()) + 1) : Number(date.getMonth()) + 1;
        var d = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
        var full = y + '-' + m + '-' + d;
        // 查询数据库中是否存在今天的新数据
        dbUtils.get('bing', {
            enddate: full.replace(/\-/g, '')
        }, function(rows) {
            if (rows.length === 0) {
                // 如果不存在则抓取
                bingUtils.fetchPicture({}, function(data) {
                    dbUtils.set('bing', data, function(rows) {
                        data.id = rows.insertId || 0;
                        module.exports.commonSend(data, callback, isAuto);
                    })
                });
            } else {
                // 如果存在，但没有发送微博
                var data = rows[0];
                if (data.weibo == 0) {
                    // 如果少了某个字段
                    if (!data.title || !data.attribute || !data.description || !data.thumbnail_pic) {
                        bingUtils.fetchStory({
                            enddate: data.enddate
                        }, function(body) {
                            data['title'] = body.title;
                            data['attribute'] = body.attribute;
                            data['description'] = body.description;
                            data['country'] = body.country;
                            data['city'] = body.city;
                            data['longitude'] = body.longitude;
                            data['latitude'] = body.latitude;
                            data['continent'] = body.continent;
                            module.exports.commonSend(data, callback, isAuto);
                        });
                    } else {
                        module.exports.commonSend(data, callback, isAuto);
                    }
                } else {
                    // 如果已发送则查询上一条是否已发送
                    dbUtils.get('bing', {
                        weibo: 0
                    }, function(rs) {
                        var d = rs[0];
                        // 如果少了某个字段
                        if (!d.title || !d.attribute || !d.description || !d.thumbnail_pic) {
                            bingUtils.fetchStory({
                                d: d.enddate
                            }, function(body) {
                                d['url'] = !!d.url && d.url || 'http://7xilig.com1.z0.glb.clouddn.com/bing/' + d.qiniu_url + '_1920x1080.jpg';
                                d['title'] = body.title;
                                d['attribute'] = body.attribute;
                                d['description'] = body.description;
                                d['country'] = body.country;
                                d['city'] = body.city;
                                d['longitude'] = body.longitude;
                                d['latitude'] = body.latitude;
                                d['continent'] = body.continent;
                                module.exports.commonSend(d, callback, isAuto);
                            });
                        } else {
                            module.exports.commonSend(d, callback, isAuto);
                        }
                    })

                }
            }
        });

    },
    /**
     * 获取短链
     */
    shorten: function(url, callback) {
        module.exports.checkOauth(function(token) {
            request
                .post('https://api.weibo.com/2/short_url/shorten.json')
                .type('form')
                .set(cookie)
                .send({
                    access_token: token,
                    url_long: url
                })
                .end(function(err, res) {
                    commonUtils.convert(err, res, callback);
                });
        });
    },
    /**
     * 公共发送微博方法
     */
    commonSend: function(data, callback) {
        module.exports.checkOauth(function(token) {
            var date = data.enddate;
            var y = date.substr(0, 4);
            var m = date.substr(4, 2);
            var d = date.substr(6, 2);
            var full = y + '-' + m + '-' + d;
            var status = ('#必应壁纸# ' + full + ' / #' + data.title + '# ' + data.description).slice(0, 138) + '... http://bing.ioliu.cn?id=' + data.id;
            var post = {
                access_token: token,
                status: status,
                url: data.url,
                lat: data.Latitude,
                long: data.Longitude,
                annotations: {
                    place: {
                        title: data.attribute,
                        url: data.copyright,
                        locality: data.city,
                        country_name: data.country,
                        region: data.country,
                        latitude: data.catitude,
                        longitude: data.congitude
                    }
                }
            };
            request
                .post(update_url_text)
                .type('form')
                .set(cookie)
                .send(post)
                .end(function(err, response) {
                    commonUtils.convert(err, response, function(body) {
                        data['weibo'] = 1;
                        data['thumbnail_pic'] = body.thumbnail_pic;
                        data['bmiddle_pic'] = body.bmiddle_pic;
                        data['original_pic'] = body.original_pic;
                        dbUtils.update('bing', {
                            body: {
                                title: data.title,
                                description: data.description,
                                attribute: data.attribute,
                                country: data.country,
                                city: data.city,
                                longitude: data.longitude,
                                latitude: data.latitude,
                                continent: data.continent,
                                weibo: 1,
                                thumbnail_pic: data.thumbnail_pic,
                                bmiddle_pic: data.bmiddle_pic,
                                original_pic: data.original_pic
                            },
                            condition: {
                                id: data.id
                            }
                        }, function(rows) {
                            callback && callback(body);
                        });
                    });
                });
        });

    },
    /**
     * 检查授权
     * @callback
     * @isAuto 是否自动发送(true/false)
     */
    checkOauth: function(callback, isAuto) {
        var uid = !!weibo.USER_UID ? weibo.USER_UID : weibo.MASTER_UID;
        if (isAuto) {
            uid = weibo.MASTER_UID;
        }
        dbUtils.get('bing_session', {
            body: {
                uid: uid
            }
        }, function(rows) {
            if (rows.length === 0) {
                callback && callback(-1);
            } else {
                callback && callback(rows[0].token);
            }
        })
    }
}<commit_msg>fix bad request<commit_after>var request = require('superagent');
var bingUtils = require('./bingUtils');
var commonUtils = require('./commonUtils');
var dbUtils = require('./dbUtils');
var weibo = require('../configs/config').weibo;
var mailUtils = require('./mailUtils');
var cookie = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36' };
var update_url_text = 'https://api.weibo.com/2/statuses/upload_url_text.json';
module.exports = {
    /**
     * 发送微博
     * @callback
     * @isAuto 是否自动发送(true,false)
     */
    update: function(callback, isAuto) {
        var date = new Date();
        var y = date.getFullYear();
        var m = Number(date.getMonth()) + 1 < 10 ? '0' + (Number(date.getMonth()) + 1) : Number(date.getMonth()) + 1;
        var d = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
        var full = y + '-' + m + '-' + d;
        // 查询数据库中是否存在今天的新数据
        dbUtils.get('bing', {
            enddate: full.replace(/\-/g, '')
        }, function(rows) {
            if (rows.length === 0) {
                // 如果不存在则抓取
                bingUtils.fetchPicture({}, function(data) {
                    dbUtils.set('bing', data, function(rows) {
                        data.id = rows.insertId || 0;
                        module.exports.commonSend(data, callback, isAuto);
                    })
                });
            } else {
                // 如果存在，但没有发送微博
                var data = rows[0];
                if (data.weibo == 0) {
                    // 如果少了某个字段
                    if (!data.title || !data.attribute || !data.description || !data.thumbnail_pic) {
                        bingUtils.fetchStory({
                            enddate: data.enddate
                        }, function(body) {
                            data['title'] = body.title;
                            data['attribute'] = body.attribute;
                            data['description'] = body.description;
                            data['country'] = body.country;
                            data['city'] = body.city;
                            data['longitude'] = body.longitude;
                            data['latitude'] = body.latitude;
                            data['continent'] = body.continent;
                            module.exports.commonSend(data, callback, isAuto);
                        });
                    } else {
                        module.exports.commonSend(data, callback, isAuto);
                    }
                } else {
                    // 如果已发送则查询上一条是否已发送
                    dbUtils.get('bing', {
                        weibo: 0
                    }, function(rs) {
                        if (rs.length > 0) {
                            var d = rs[0];
                            // 如果少了某个字段
                            if (!d.title || !d.attribute || !d.description || !d.thumbnail_pic) {
                                bingUtils.fetchStory({
                                    d: d.enddate
                                }, function(body) {
                                    d['url'] = !!d.url && d.url || 'http://7xilig.com1.z0.glb.clouddn.com/bing/' + d.qiniu_url + '_1920x1080.jpg';
                                    d['title'] = body.title;
                                    d['attribute'] = body.attribute;
                                    d['description'] = body.description;
                                    d['country'] = body.country;
                                    d['city'] = body.city;
                                    d['longitude'] = body.longitude;
                                    d['latitude'] = body.latitude;
                                    d['continent'] = body.continent;
                                    module.exports.commonSend(d, callback, isAuto);
                                });
                            } else {
                                module.exports.commonSend(d, callback, isAuto);
                            }
                        }
                    })

                }
            }
        });

    },
    /**
     * 获取短链
     */
    shorten: function(url, callback) {
        module.exports.checkOauth(function(token) {
            request
                .post('https://api.weibo.com/2/short_url/shorten.json')
                .type('form')
                .set(cookie)
                .send({
                    access_token: token,
                    url_long: url
                })
                .end(function(err, res) {
                    commonUtils.convert(err, res, callback);
                });
        });
    },
    /**
     * 公共发送微博方法
     */
    commonSend: function(data, callback) {
        module.exports.checkOauth(function(token) {
            var date = data.enddate;
            var y = date.substr(0, 4);
            var m = date.substr(4, 2);
            var d = date.substr(6, 2);
            var full = y + '-' + m + '-' + d;
            var status = ('#必应壁纸# ' + full + ' / #' + data.title + '# ' + data.description).slice(0, 138) + '... http://bing.ioliu.cn?id=' + data.id;
            var post = {
                access_token: token,
                status: status,
                url: data.url,
                lat: data.Latitude,
                long: data.Longitude,
                annotations: {
                    place: {
                        title: data.attribute,
                        url: data.copyright,
                        locality: data.city,
                        country_name: data.country,
                        region: data.country,
                        latitude: data.catitude,
                        longitude: data.congitude
                    }
                }
            };
            request
                .post(update_url_text)
                .type('form')
                .set(cookie)
                .send(post)
                .end(function(err, response) {
                    commonUtils.convert(err, response, function(body) {
                        data['weibo'] = 1;
                        data['thumbnail_pic'] = body.thumbnail_pic;
                        data['bmiddle_pic'] = body.bmiddle_pic;
                        data['original_pic'] = body.original_pic;
                        dbUtils.update('bing', {
                            body: {
                                title: data.title,
                                description: data.description,
                                attribute: data.attribute,
                                country: data.country,
                                city: data.city,
                                longitude: data.longitude,
                                latitude: data.latitude,
                                continent: data.continent,
                                weibo: 1,
                                thumbnail_pic: data.thumbnail_pic,
                                bmiddle_pic: data.bmiddle_pic,
                                original_pic: data.original_pic
                            },
                            condition: {
                                id: data.id
                            }
                        }, function(rows) {
                            callback && callback(body);
                        });
                    });
                });
        });

    },
    /**
     * 检查授权
     * @callback
     * @isAuto 是否自动发送(true/false)
     */
    checkOauth: function(callback, isAuto) {
        var uid = !!weibo.USER_UID ? weibo.USER_UID : weibo.MASTER_UID;
        if (isAuto) {
            uid = weibo.MASTER_UID;
        }
        dbUtils.get('bing_session', {
            body: {
                uid: uid
            }
        }, function(rows) {
            if (rows.length === 0) {
                callback && callback(-1);
            } else {
                callback && callback(rows[0].token);
            }
        })
    }
}<|endoftext|>


<commit_before><commit_msg>Remove final json output<commit_after><|endoftext|>


<commit_before>import React, { Component } from 'react';

import css from './styles.css';

const PLL_GFYCATS = {
    f: {
        probability: 4 / 72,
        url: 'MarvelousWelllitEthiopianwolf'
    },
    ga: {
        probability: 4 / 72,
        url: 'VapidSilkyAtlanticblackgoby'
    },
    gb: {
        probability: 4 / 72,
        url: 'IdleHollowCusimanse'
    },
    gc: {
        probability: 4 / 72,
        url: 'SomeEsteemedKinglet'
    },
    gd: {
        probability: 4 / 72,
        url: 'UnkemptForthrightChital'
    },
    ja: {
        probability: 4 / 72,
        url: 'CrazyCheerfulAyeaye'
    },
    ua: {
        probability: 4 / 72,
        url: 'SafeEssentialIaerismetalmark',
        alternatives: [
            'MildMarriedGuppy'
        ]
    },
    ub: {
        probability: 4 / 72,
        url: 'MediocreAffectionateGnatcatcher'
    },
    v: {
        probability: 4 / 72,
        url: 'FrightenedUniformHagfish'
    },
    y: {
        probability: 4 / 72,
        url: 'ShimmeringPleasingBabirusa'
    },
};

export default class PermuteLastLayerPage extends Component {
    constructor() {
        super();
    }

    render() {
        return (

                {Object.keys(PLL_GFYCATS).sort().map(pll => {
                    const {
                        url,
                    } = PLL_GFYCATS[pll];
                    return (<img
                        src={`https://thumbs.gfycat.com/${url}.webp`}
                        className={css.picture}
                    />);
                })}

        )
    }
}
<commit_msg>Added N and R perms.<commit_after>import React, { Component } from 'react';

import css from './styles.css';

const PLL_GFYCATS = {
    f: {
        probability: 4 / 72,
        url: 'MarvelousWelllitEthiopianwolf'
    },
    ga: {
        probability: 4 / 72,
        url: 'VapidSilkyAtlanticblackgoby'
    },
    gb: {
        probability: 4 / 72,
        url: 'IdleHollowCusimanse'
    },
    gc: {
        probability: 4 / 72,
        url: 'SomeEsteemedKinglet'
    },
    gd: {
        probability: 4 / 72,
        url: 'UnkemptForthrightChital'
    },
    ja: {
        probability: 4 / 72,
        url: 'CrazyCheerfulAyeaye'
    },
    na: {
        probability: 1 / 72,
        url: 'BriefDeadFlamingo',
    },
    nb: {
        probability: 1 / 72,
        url: 'SafeBarrenElephant',
    },
    ra: {
        probability: 4 / 72,
        url: 'ImportantOldfashionedAsiandamselfly',
    },
    rb: {
        probability: 4 / 72,
        url: 'TotalEntireFlyingfox',
    },
    ua: {
        probability: 4 / 72,
        url: 'SafeEssentialIaerismetalmark',
        alternatives: [
            'MildMarriedGuppy'
        ]
    },
    ub: {
        probability: 4 / 72,
        url: 'MediocreAffectionateGnatcatcher'
    },
    v: {
        probability: 4 / 72,
        url: 'FrightenedUniformHagfish'
    },
    y: {
        probability: 4 / 72,
        url: 'ShimmeringPleasingBabirusa'
    },
};

export default class PermuteLastLayerPage extends Component {
    constructor() {
        super();
    }

    render() {
        return (

PLLs

Original videos Fast PLL Algorithms & Finger Tricks and Alternative PLL Algorithms by J Perm. Generated with gfycat

                    {Object.keys(PLL_GFYCATS).sort().map(pll => {
                        const {
                            url,
                        } = PLL_GFYCATS[pll];
                        return (<img
                            src={`https://thumbs.gfycat.com/${url}.webp`}
                            className={css.picture}
                        />);
                    })}

        )
    }
}
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var ContentRepo = require("matrix-js-sdk").ContentRepo;
var Modal = require('matrix-react-sdk/lib/Modal');
var sdk = require('matrix-react-sdk');
var dis = require('matrix-react-sdk/lib/dispatcher');
var GeminiScrollbar = require('react-gemini-scrollbar');

var linkify = require('linkifyjs');
var linkifyString = require('linkifyjs/string');
var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
var sanitizeHtml = require('sanitize-html');
var q = require('q');

linkifyMatrix(linkify);

module.exports = React.createClass({
    displayName: 'RoomDirectory',

    propTypes: {
        config: React.PropTypes.object,
    },

    getDefaultProps: function() {
        return {
            config: {
                networks: [],
            },
        }
    },

    getInitialState: function() {
        return {
            publicRooms: [],
            loading: true,
            filterByNetwork: null,
        }
    },

    componentWillMount: function() {
        // precompile Regexps
        this.networkPatterns = {};
        if (this.props.config.networkPatterns) {
            for (const network of Object.keys(this.props.config.networkPatterns)) {
                this.networkPatterns[network] = new RegExp(this.props.config.networkPatterns[network]);
            }
        }
        this.nextBatch = null;
        this.filterString = null;
        this.filterTimeout = null;
        this.scrollPanel = null;

        // dis.dispatch({
        //     action: 'ui_opacity',
        //     sideOpacity: 0.3,
        //     middleOpacity: 0.3,
        // });
    },

    componentDidMount: function() {
        this.refreshRoomList();
    },

    componentWillUnmount: function() {
        // dis.dispatch({
        //     action: 'ui_opacity',
        //     sideOpacity: 1.0,
        //     middleOpacity: 1.0,
        // });
    },

    refreshRoomList: function() {
        this.nextBatch = null;
        this.setState({
            publicRooms: [],
            loading: true,
        });
        this.getMoreRooms().done();
    },

    getMoreRooms: function() {
        if (!MatrixClientPeg.get()) return q();

        const my_filter_string = this.filterString;
        const opts = {limit: 20};
        if (this.nextBatch) opts.since = this.nextBatch;
        if (this.filterString) opts.filter = { generic_search_term: my_filter_string } ;
        return MatrixClientPeg.get().publicRooms(opts).then((data) => {
            if (my_filter_string != this.filterString) {
                // if the filter has changed since this request was sent,
                // throw away the result (don't even clear the busy flag
                // since we must still have a request in flight)
                return;
            }

            this.nextBatch = data.next_batch;
            this.setState((s) => {
                s.publicRooms.push(...data.chunk);
                s.loading = false;
                return s;
            });
            return Boolean(data.next_batch);
        }, (err) => {
            if (my_filter_string != this.filterString) {
                // as above: we don't care about errors for old
                // requests either
                return;
            }
            this.setState({ loading: false });
            console.error("Failed to get publicRooms: %s", JSON.stringify(err));
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Failed to get public room list",
                description: err.message
            });
        });
    },

    /**
     * A limited interface for removing rooms from the directory.
     * Will set the room to not be publicly visible and delete the
     * default alias. In the long term, it would be better to allow
     * HS admins to do this through the RoomSettings interface, but
     * this needs SPEC-417.
     */
    removeFromDirectory: function(room) {
        var alias = get_display_alias_for_room(room);
        var name = room.name || alias || "Unnamed room";

        var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
        var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");

        var desc;
        if (alias) {
            desc = `Delete the room alias '${alias}' and remove '${name}' from the directory?`;
        } else {
            desc = `Remove '${name}' from the directory?`;
        }

        Modal.createDialog(QuestionDialog, {
            title: "Remove from Directory",
            description: desc,
            onFinished: (should_delete) => {
                if (!should_delete) return;

                var Loader = sdk.getComponent("elements.Spinner");
                var modal = Modal.createDialog(Loader);
                var step = `remove '${name}' from the directory.`;

                MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => {
                    if (!alias) return;
                    step = 'delete the alias.';
                    return MatrixClientPeg.get().deleteAlias(alias);
                }).done(() => {
                    modal.close();
                    this.refreshRoomList();
                }, function(err) {
                    modal.close();
                    this.refreshRoomList();
                    Modal.createDialog(ErrorDialog, {
                        title: "Failed to "+step,
                        description: err.toString()
                    });
                });
            }
        });
    },

    onRoomClicked: function(room, ev) {
        if (ev.shiftKey) {
            ev.preventDefault();
            this.removeFromDirectory(room);
        } else {
            this.showRoom(room);
        }
    },

    onNetworkChange: function(network) {
        this.setState({
            filterByNetwork: network,
        }, () => {
            // we just filtered out a bunch of rooms, so check to see if
            // we need to fill up the scrollpanel again
            // NB. Because we filter the results, the HS can keep giving
            // us more rooms and we'll keep requesting more if none match
            // the filter, which is pretty terrible. We need a way
            // to filter by network on the server.
            if (this.scrollPanel) this.scrollPanel.checkFillState();
        });
    },

    onFillRequest: function(backwards) {
        if (backwards || !this.nextBatch) return q(false);

        return this.getMoreRooms();
    },

    onFilterChange: function(alias) {
        this.filterString = alias || null;

        // don't send the request for a little bit,
        // no point hammering the server with a
        // request for every keystroke, let the
        // user finish typing.
        if (this.filterTimeout) {
            clearTimeout(this.filterTimeout);
        }
        this.filterTimeout = setTimeout(() => {
            this.filterTimeout = null;
            this.refreshRoomList();
        }, 300);
    },

    onFilterClear: function() {
        this.filterString = null;

        if (this.filterTimeout) {
            clearTimeout(this.filterTimeout);
        }
        // update immediately
        this.refreshRoomList();
    },

    onJoinClick: function(alias) {
        this.showRoomAlias(alias);
    },

    showRoomAlias: function(alias) {
        this.showRoom(null, alias);
    },

    showRoom: function(room, room_alias) {
        var payload = {action: 'view_room'};
        if (room) {
            // Don't let the user view a room they won't be able to either
            // peek or join: fail earlier so they don't have to click back
            // to the directory.
            if (MatrixClientPeg.get().isGuest()) {
                if (!room.world_readable && !room.guest_can_join) {
                    var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
                    Modal.createDialog(NeedToRegisterDialog, {
                        title: "Failed to join the room",
                        description: "This room is inaccessible to guests. You may be able to join if you register."
                    });
                    return;
                }
            }

            if (!room_alias) {
                room_alias = get_display_alias_for_room(room);
            }

            payload.oob_data = {
                avatarUrl: room.avatar_url,
                // XXX: This logic is duplicated from the JS SDK which
                // would normally decide what the name is.
                name: room.name || room_alias || "Unnamed room",
            };
        }
        // It's not really possible to join Matrix rooms by ID because the HS has no way to know
        // which servers to start querying. However, there's no other way to join rooms in
        // this list without aliases at present, so if roomAlias isn't set here we have no
        // choice but to supply the ID.
        if (room_alias) {
            payload.room_alias = room_alias;
        } else {
            payload.room_id = room.room_id;
        }
        dis.dispatch(payload);
    },

    getRows: function() {
        var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');

        if (!this.state.publicRooms) return [];

        var rooms = this.state.publicRooms.filter((a) => {
            if (this.state.filterByNetwork) {
                if (!this._isRoomInNetwork(a, this.state.filterByNetwork)) return false;
            }

            return true;
        });
        var rows = [];
        var self = this;
        var guestRead, guestJoin, perms;
        for (var i = 0; i < rooms.length; i++) {
            var name = rooms[i].name || get_display_alias_for_room(rooms[i]) || "Unnamed room";
            guestRead = null;
            guestJoin = null;

            if (rooms[i].world_readable) {
                guestRead = (

World readable

                );
            }
            if (rooms[i].guest_can_join) {
                guestJoin = (

Guests can join

                );
            }

            perms = null;
            if (guestRead || guestJoin) {
                perms =
{guestRead} {guestJoin}
;
            }

            var topic = rooms[i].topic || '';
            topic = linkifyString(sanitizeHtml(topic));

            rows.push(

 {ev.preventDefault();}}
                >

                        <BaseAvatar width={24} height={24} resizeMethod='crop'
                            name={ name } idName={ name }
                            url={ ContentRepo.getHttpUriForMxc(
                                    MatrixClientPeg.get().getHomeserverUrl(),
                                    rooms[i].avatar_url, 24, 24, "crop") } />

{ name }

                        { perms }

{ get_display_alias_for_room(rooms[i]) }

                        { rooms[i].num_joined_members }

            );
        }
        return rows;
    },

    collectScrollPanel: function(element) {
        this.scrollPanel = element;
    },

    /**
     * Terrible temporary function that guess what network a public room
     * entry is in, until synapse is able to tell us
     */
    _isRoomInNetwork(room, network) {
        if (room.aliases && this.networkPatterns[network]) {
            for (const alias of room.aliases) {
                if (this.networkPatterns[network].test(alias)) return true;
            }
        }

        return false;
    },

    render: function() {
        let content;
        if (this.state.loading) {
            const Loader = sdk.getComponent("elements.Spinner");
            content =

                <Loader />

;
        } else {
            const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
            content = <ScrollPanel ref={this.collectScrollPanel}
                className="mx_RoomDirectory_tableWrapper"
                onFillRequest={ this.onFillRequest }
                stickyBottom={false}
                startAtBottom={false}
                onResize={function(){}}
            >

                        { this.getRows() }

            </ScrollPanel>;
        }

        const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
        const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
        const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
        return (

                <SimpleRoomHeader title="Directory" />

                        <DirectorySearchBox
                            className="mx_RoomDirectory_searchbox" ref={this.collectSearchBox}
                            onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
                        />
                        <NetworkDropdown config={this.props.config} onNetworkChange={this.onNetworkChange} />

                    {content}

        );
    }
});

// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
// but works with the objects we get from the public room list
function get_display_alias_for_room(room) {
    return  room.canonical_alias || (room.aliases ? room.aliases[0] : "");
}
<commit_msg>Oops, missed the ref<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');

var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var ContentRepo = require("matrix-js-sdk").ContentRepo;
var Modal = require('matrix-react-sdk/lib/Modal');
var sdk = require('matrix-react-sdk');
var dis = require('matrix-react-sdk/lib/dispatcher');
var GeminiScrollbar = require('react-gemini-scrollbar');

var linkify = require('linkifyjs');
var linkifyString = require('linkifyjs/string');
var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
var sanitizeHtml = require('sanitize-html');
var q = require('q');

linkifyMatrix(linkify);

module.exports = React.createClass({
    displayName: 'RoomDirectory',

    propTypes: {
        config: React.PropTypes.object,
    },

    getDefaultProps: function() {
        return {
            config: {
                networks: [],
            },
        }
    },

    getInitialState: function() {
        return {
            publicRooms: [],
            loading: true,
            filterByNetwork: null,
        }
    },

    componentWillMount: function() {
        // precompile Regexps
        this.networkPatterns = {};
        if (this.props.config.networkPatterns) {
            for (const network of Object.keys(this.props.config.networkPatterns)) {
                this.networkPatterns[network] = new RegExp(this.props.config.networkPatterns[network]);
            }
        }
        this.nextBatch = null;
        this.filterString = null;
        this.filterTimeout = null;
        this.scrollPanel = null;

        // dis.dispatch({
        //     action: 'ui_opacity',
        //     sideOpacity: 0.3,
        //     middleOpacity: 0.3,
        // });
    },

    componentDidMount: function() {
        this.refreshRoomList();
    },

    componentWillUnmount: function() {
        // dis.dispatch({
        //     action: 'ui_opacity',
        //     sideOpacity: 1.0,
        //     middleOpacity: 1.0,
        // });
    },

    refreshRoomList: function() {
        this.nextBatch = null;
        this.setState({
            publicRooms: [],
            loading: true,
        });
        this.getMoreRooms().done();
    },

    getMoreRooms: function() {
        if (!MatrixClientPeg.get()) return q();

        const my_filter_string = this.filterString;
        const opts = {limit: 20};
        if (this.nextBatch) opts.since = this.nextBatch;
        if (this.filterString) opts.filter = { generic_search_term: my_filter_string } ;
        return MatrixClientPeg.get().publicRooms(opts).then((data) => {
            if (my_filter_string != this.filterString) {
                // if the filter has changed since this request was sent,
                // throw away the result (don't even clear the busy flag
                // since we must still have a request in flight)
                return;
            }

            this.nextBatch = data.next_batch;
            this.setState((s) => {
                s.publicRooms.push(...data.chunk);
                s.loading = false;
                return s;
            });
            return Boolean(data.next_batch);
        }, (err) => {
            if (my_filter_string != this.filterString) {
                // as above: we don't care about errors for old
                // requests either
                return;
            }
            this.setState({ loading: false });
            console.error("Failed to get publicRooms: %s", JSON.stringify(err));
            var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
            Modal.createDialog(ErrorDialog, {
                title: "Failed to get public room list",
                description: err.message
            });
        });
    },

    /**
     * A limited interface for removing rooms from the directory.
     * Will set the room to not be publicly visible and delete the
     * default alias. In the long term, it would be better to allow
     * HS admins to do this through the RoomSettings interface, but
     * this needs SPEC-417.
     */
    removeFromDirectory: function(room) {
        var alias = get_display_alias_for_room(room);
        var name = room.name || alias || "Unnamed room";

        var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
        var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");

        var desc;
        if (alias) {
            desc = `Delete the room alias '${alias}' and remove '${name}' from the directory?`;
        } else {
            desc = `Remove '${name}' from the directory?`;
        }

        Modal.createDialog(QuestionDialog, {
            title: "Remove from Directory",
            description: desc,
            onFinished: (should_delete) => {
                if (!should_delete) return;

                var Loader = sdk.getComponent("elements.Spinner");
                var modal = Modal.createDialog(Loader);
                var step = `remove '${name}' from the directory.`;

                MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => {
                    if (!alias) return;
                    step = 'delete the alias.';
                    return MatrixClientPeg.get().deleteAlias(alias);
                }).done(() => {
                    modal.close();
                    this.refreshRoomList();
                }, function(err) {
                    modal.close();
                    this.refreshRoomList();
                    Modal.createDialog(ErrorDialog, {
                        title: "Failed to "+step,
                        description: err.toString()
                    });
                });
            }
        });
    },

    onRoomClicked: function(room, ev) {
        if (ev.shiftKey) {
            ev.preventDefault();
            this.removeFromDirectory(room);
        } else {
            this.showRoom(room);
        }
    },

    onNetworkChange: function(network) {
        this.setState({
            filterByNetwork: network,
        }, () => {
            // we just filtered out a bunch of rooms, so check to see if
            // we need to fill up the scrollpanel again
            // NB. Because we filter the results, the HS can keep giving
            // us more rooms and we'll keep requesting more if none match
            // the filter, which is pretty terrible. We need a way
            // to filter by network on the server.
            if (this.scrollPanel) this.scrollPanel.checkFillState();
        });
    },

    onFillRequest: function(backwards) {
        if (backwards || !this.nextBatch) return q(false);

        return this.getMoreRooms();
    },

    onFilterChange: function(alias) {
        this.filterString = alias || null;

        // don't send the request for a little bit,
        // no point hammering the server with a
        // request for every keystroke, let the
        // user finish typing.
        if (this.filterTimeout) {
            clearTimeout(this.filterTimeout);
        }
        this.filterTimeout = setTimeout(() => {
            this.filterTimeout = null;
            this.refreshRoomList();
        }, 300);
    },

    onFilterClear: function() {
        this.filterString = null;

        if (this.filterTimeout) {
            clearTimeout(this.filterTimeout);
        }
        // update immediately
        this.refreshRoomList();
    },

    onJoinClick: function(alias) {
        this.showRoomAlias(alias);
    },

    showRoomAlias: function(alias) {
        this.showRoom(null, alias);
    },

    showRoom: function(room, room_alias) {
        var payload = {action: 'view_room'};
        if (room) {
            // Don't let the user view a room they won't be able to either
            // peek or join: fail earlier so they don't have to click back
            // to the directory.
            if (MatrixClientPeg.get().isGuest()) {
                if (!room.world_readable && !room.guest_can_join) {
                    var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
                    Modal.createDialog(NeedToRegisterDialog, {
                        title: "Failed to join the room",
                        description: "This room is inaccessible to guests. You may be able to join if you register."
                    });
                    return;
                }
            }

            if (!room_alias) {
                room_alias = get_display_alias_for_room(room);
            }

            payload.oob_data = {
                avatarUrl: room.avatar_url,
                // XXX: This logic is duplicated from the JS SDK which
                // would normally decide what the name is.
                name: room.name || room_alias || "Unnamed room",
            };
        }
        // It's not really possible to join Matrix rooms by ID because the HS has no way to know
        // which servers to start querying. However, there's no other way to join rooms in
        // this list without aliases at present, so if roomAlias isn't set here we have no
        // choice but to supply the ID.
        if (room_alias) {
            payload.room_alias = room_alias;
        } else {
            payload.room_id = room.room_id;
        }
        dis.dispatch(payload);
    },

    getRows: function() {
        var BaseAvatar = sdk.getComponent('avatars.BaseAvatar');

        if (!this.state.publicRooms) return [];

        var rooms = this.state.publicRooms.filter((a) => {
            if (this.state.filterByNetwork) {
                if (!this._isRoomInNetwork(a, this.state.filterByNetwork)) return false;
            }

            return true;
        });
        var rows = [];
        var self = this;
        var guestRead, guestJoin, perms;
        for (var i = 0; i < rooms.length; i++) {
            var name = rooms[i].name || get_display_alias_for_room(rooms[i]) || "Unnamed room";
            guestRead = null;
            guestJoin = null;

            if (rooms[i].world_readable) {
                guestRead = (

World readable

                );
            }
            if (rooms[i].guest_can_join) {
                guestJoin = (

Guests can join

                );
            }

            perms = null;
            if (guestRead || guestJoin) {
                perms =
{guestRead} {guestJoin}
;
            }

            var topic = rooms[i].topic || '';
            topic = linkifyString(sanitizeHtml(topic));

            rows.push(

 {ev.preventDefault();}}
                >

                        <BaseAvatar width={24} height={24} resizeMethod='crop'
                            name={ name } idName={ name }
                            url={ ContentRepo.getHttpUriForMxc(
                                    MatrixClientPeg.get().getHomeserverUrl(),
                                    rooms[i].avatar_url, 24, 24, "crop") } />

{ name }

                        { perms }

{ get_display_alias_for_room(rooms[i]) }

                        { rooms[i].num_joined_members }

            );
        }
        return rows;
    },

    collectScrollPanel: function(element) {
        this.scrollPanel = element;
    },

    /**
     * Terrible temporary function that guess what network a public room
     * entry is in, until synapse is able to tell us
     */
    _isRoomInNetwork(room, network) {
        if (room.aliases && this.networkPatterns[network]) {
            for (const alias of room.aliases) {
                if (this.networkPatterns[network].test(alias)) return true;
            }
        }

        return false;
    },

    render: function() {
        let content;
        if (this.state.loading) {
            const Loader = sdk.getComponent("elements.Spinner");
            content =

                <Loader />

;
        } else {
            const ScrollPanel = sdk.getComponent("structures.ScrollPanel");
            content = <ScrollPanel ref={this.collectScrollPanel}
                className="mx_RoomDirectory_tableWrapper"
                onFillRequest={ this.onFillRequest }
                stickyBottom={false}
                startAtBottom={false}
                onResize={function(){}}
            >

                        { this.getRows() }

            </ScrollPanel>;
        }

        const SimpleRoomHeader = sdk.getComponent('rooms.SimpleRoomHeader');
        const NetworkDropdown = sdk.getComponent('directory.NetworkDropdown');
        const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
        return (

                <SimpleRoomHeader title="Directory" />

                        <DirectorySearchBox
                            className="mx_RoomDirectory_searchbox"
                            onChange={this.onFilterChange} onClear={this.onFilterClear} onJoinClick={this.onJoinClick}
                        />
                        <NetworkDropdown config={this.props.config} onNetworkChange={this.onNetworkChange} />

                    {content}

        );
    }
});

// Similar to matrix-react-sdk's MatrixTools.getDisplayAliasForRoom
// but works with the objects we get from the public room list
function get_display_alias_for_room(room) {
    return  room.canonical_alias || (room.aliases ? room.aliases[0] : "");
}
<|endoftext|>


<commit_before><commit_msg>Fixed checking for unchanged cookie values<commit_after><|endoftext|>