<commit_before>configuration = {
  node_name: "default",  // ensure this is unique in your cluster
  redis: {
    ip: '127.0.0.1',
    port: 6379,
    db: 1
  },
  servers: [
    { type: 'tcp', ip: '127.0.0.1', port: 8080 },
    { type: 'ws',  ip: '127.0.0.1', port: 8081 }
  ],
  extensions: [
    {
      name: "basic",
      type: "node",
      module: "../lib/ext/basic"
    },
    {
      name: "metadata",
      type: "node",
      module: "../lib/ext/metadata"
    },
    {
      name: "pubsub",
      type: "node",
      module: "../lib/ext/pubsub",
      options: { db: 1 }
    }
  ],
  max_clients: 50000,
  max_request_size: 50240,
  max_queued_requests: 100
};
<commit_msg>Enable nickname extension by default<commit_after>configuration = {
  node_name: "default",  // ensure this is unique in your cluster
  redis: {
    ip: '127.0.0.1',
    port: 6379,
    db: 1
  },
  servers: [
    { type: 'tcp', ip: '127.0.0.1', port: 8080 },
    { type: 'ws',  ip: '127.0.0.1', port: 8081 }
  ],
  extensions: [
    {
      name: "basic",
      type: "node",
      module: "../lib/ext/basic"
    },
    {
      name: "metadata",
      type: "node",
      module: "../lib/ext/metadata"
    },
    {
      name: "pubsub",
      type: "node",
      module: "../lib/ext/pubsub",
      options: { db: 1 }
    },
    {
      name: "nickname",
      type: "node",
      module: "../lib/ext/nickname",
    }
  ],
  max_clients: 50000,
  max_request_size: 50240,
  max_queued_requests: 100
};
<|endoftext|>


<commit_before>"use strict";

// Socket Connections - All sockets connected will be stored in this connections array
const connections = [];
// This is the interface of connections (Just for our reference becos we love typescript so much)
// Connections: []Connection
// Connection {
//     id: string;
//     profileName: string;
//     secretCode: string;
//     ready: boolean
//     userType: string;
// }
const rooms = [];
// room: Room
// Room {
  // name: string;
  // secretCode: string;
  // readySessionEnabled: boolean;
// }
var availableCodeList = ['GROWTH','AMAZE','REFRESH','MAGIC','BOOZE','MASTER', 'HEROIC','HUSTLE','TEQUILA','POLISH','PARADOX','CANVAS','ISLAND','WONDER'];
var usedCodeList = [];

function findConnection(id){
  return connections.filter(function(connection) {return connection.id === id;})[0];
}
function findRoom(secretCode){
  return rooms.filter(function(room) {return room.secretCode === secretCode;})[0];
}
function findNumberOfRoomConnections(secretCode){
  var roomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode})
  return roomConnections.length;
}
function findNumberOfReadyConnections(secretCode){
  var readyConnections = connections.filter(function(connection) {return (connection.ready === true && connection.secretCode === secretCode)})
  return readyConnections.length;
}
function resetAllStatusForRoomConnections(socket,secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    // may not necessarily want to reset profile name in future
    element.profileName = null;
    element.secretCode = null;
    element.ready = null;
    element.userType = null;
    // we need to get all sockets to leave
  })
}
function resetReadyStatusForRoomConnections(socket,secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    // may not necessarily want to reset profile name in future
    element.ready = null;
  })
}
function socketsLeaveRoom(secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    element.socket.leave(secretCode)
  })
}
function secretCodeGenerator(availableList, usedList) {
 //take first element of availableCodeList array,
 //add to end of usedCodeList
 var secretCode = availableList.splice(Math.floor(Math.random() * availableList.length), 1);
 console.log('secret code is ' + secretCode);
 usedList.push(secretCode);
 return secretCode;
}
function returnBackSecretCode(availableList, usedList, secretCode){
  var indexOfRemovedCode = usedList.indexOf(secretCode);
  usedCodeList.splice(indexOfRemovedCode, 1);
  availableList.push(secretCode);
}

// =================================== Socket Controller Functions =================================

function connect(socket){
  //new connection, save the socket to them
  // when a socket first connects, provide all these attributes so that you would not get error when you do a status reset
  connections.push({
    socket: socket,
    id: socket.id,
    profileName: null,
    secretCode: null,
    ready: null,
    userType: null
  });
  console.log(`## New connection (${socket.id}). Total: ${connections.length}.`);
}

function disconnect(socket,io){
  //find the connection and remove  from the collection
  let connection = findConnection(socket.id);
  if (connection){
    if (connection.userType === "instructor") {
      let room = findRoom(connection.secretCode);
      if (room.readySessionEnabled === true) {
        instructorEndsReadySession(socket)
      }
      closeClass(socket,io);
    }
    if (connection.userType === "student") {
      if (connection.ready === true) {
        studentNotReady(socket, io)
      }
      studentLeaveClass(socket,io)
    }
    connections.splice(connections.indexOf(connection), 1);
    console.log(`## Connection (${connection.id}) (${socket.id}) disconnected. Remaining: ${connections.length}.`);
  }
  socket.disconnect();
}
      // =================================== Instructor ===========================

function submitClassName(socket, className){
  // this connection guy does nothing yet (just put here in case)
  var room = {
    name: className,
    // pass in secretcodefunction
    secretCode: secretCodeGenerator(availableCodeList,usedCodeList)
  }
  socket.join(room.secretCode)
  rooms.push(room);
  let connection = findConnection(socket.id);
  if (connection){
    connection.secretCode = room.secretCode;
    connection.userType = "instructor";
    socket.emit('createSecretCode', room)
  }
}

function closeClass(socket,io){
  let connection = findConnection(socket.id);
  if (connection) {
    let room = findRoom(connection.secretCode);
    if (room){
      console.log(`## Room (${room.name}) closed. Remaining: ${rooms.length}.`);
      rooms.splice(rooms.indexOf(room), 1);
      returnBackSecretCode(availableCodeList,usedCodeList,room.secretCode);
      // you want to find all connections in the room with a ready status and set them all to false
      resetAllStatusForRoomConnections(socket,room.secretCode)
      // reset room connection back to 0 for everyone when room is closed so that when you start a new room, the room starts with 0 connection
      io.to(room.secretCode).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(room.secretCode)));
      // this socketsLeaveRoom function must come after the io because if it comes first, we would not be able to emit to all sockets in that room anymore
      socketsLeaveRoom(room.secretCode)
      socket.broadcast.to(room.secretCode).emit('studentsCloseClass')
    }
  }
}

function instructorCallReady(socket){
  // use the classroomService to emit instructorReady() to the server that we are starting are u ready
  // use the server to emit startStudentReady() to all those in the room (excluding instructor) - use broadcast
  // and in the service (listen for an emit)
  // in the emit (reroute the student into student ready)
  let connection = findConnection(socket.id);
  if (connection) {
    let room = findRoom(connection.secretCode);
    if (room) {
      room.readySessionEnabled = true;
      socket.broadcast.to(room.secretCode).emit('startStudentReady')
    }
  }
}

function instructorEndsReadySession(socket){
  let connection = findConnection(socket.id);
  if (connection){
    let room = findRoom(connection.secretCode);
    if (room) {
      // you want to find all connections in the room with a ready status and set them all to false
      room.readySessionEnabled = false;
      resetReadyStatusForRoomConnections(socket,room.secretCode)
      socket.broadcast.to(room.secretCode).emit('studentsEndReadySession')
    }
  }
}
      // =================================== Student ===========================

function submitProfileName(socket, profileName){
  let connection = findConnection(socket.id);
  if (connection){
    connection.profileName = profileName;
  }
}

function submitSecretCode(socket, secretCode, io){
  // this connection guy does nothing yet (just put here in case)
  let room = findRoom(secretCode);
  if (room) {
    let connection = findConnection(socket.id);
    if (connection){
      connection.secretCode = secretCode;
      connection.userType = "student"
      socket.join(room.secretCode)
      // emit something back so that we can route him to the next page
      // =>> added this shit in when we were sleepy
      socket.emit('secretCodeExist', {secretCodeExist: true, room: room})
      // connections should be number of sockets who are joined to the room - 1 (instructor)
      io.to(room.secretCode).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(secretCode)-1));
    }
  } else {
    // emit him some message so that client knows that the secret code is wrong
    socket.emit('secretCodeExist', false)
  }
}

function studentLeaveClass(socket,io){
  let connection = findConnection(socket.id);
  if (connection){
    var secretCodeOfPreviousRoom = connection.secretCode
    connection.secretCode = null;
    if (connection.ready){
      connection.ready = null;
    }
    io.to(secretCodeOfPreviousRoom).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(secretCodeOfPreviousRoom)-1))
    socket.leave(connection.secretCode)
  }
}

function studentReady(socket,io){
  let connection = findConnection(socket.id);
  if (connection){
    // the difference between studentReady and studentNotReady is setting connection.ready true and false
    connection.ready = true;
    // end of difference
    let room = findRoom(connection.secretCode);
    if (room) {
      // this socket emit is for the individual student's ready toggle button
      socket.emit("RecievedYourLovelyReadyResponse")
      // this socket broadcast is for everyone in the room so that everyone knows the number of students who are ready
      io.to(room.secretCode).emit("updateStudentReady", findNumberOfReadyConnections(connection.secretCode))
      // on the client side, it is waiting for updatestudentready
      // it will save a property for the number of studentready
      // display it on both the instructor and student dashboard
      // so we need to use the service reference hack so that both student and instructor ready component will be able to access the updated property
      // 1)Once i receive the emit, i need to save that argument that is passed to me under a property object
      // 2)I need to create a getProperty in the service (just above the constructor)
      // 3)In my two components, i need to make a getPropertyRequest
    }
  }
}

function studentNotReady(socket, io){
  let connection = findConnection(socket.id);
  if (connection){
    connection.ready = false;
    let room = findRoom(connection.secretCode);
    if (room) {
      // this socket emit is for the individual student's ready toggle button
      socket.emit("RecievedYourLovelyNotReadyResponse")
      console.log("server received lovely not ready response")
      // this socket broadcast is for everyone in the room so that everyone knows the number of students who are ready
      io.to(room.secretCode).emit("updateStudentReady", findNumberOfReadyConnections(connection.secretCode))
      console.log("studentNotReady completed run")
    }
  }
}

// Functions we are exporting to (server.js)
module.exports = {
  connect: connect,
  disconnect: disconnect,
  submitClassName: submitClassName,
  closeClass: closeClass,
  instructorEndsReadySession: instructorEndsReadySession,
  submitProfileName: submitProfileName,
  submitSecretCode: submitSecretCode,
  studentLeaveClass: studentLeaveClass,
  instructorCallReady: instructorCallReady,
  studentReady: studentReady,
  studentNotReady: studentNotReady
}
<commit_msg>undo random room generator<commit_after>"use strict";

// Socket Connections - All sockets connected will be stored in this connections array
const connections = [];
// This is the interface of connections (Just for our reference becos we love typescript so much)
// Connections: []Connection
// Connection {
//     id: string;
//     profileName: string;
//     secretCode: string;
//     ready: boolean
//     userType: string;
// }
const rooms = [];
// room: Room
// Room {
  // name: string;
  // secretCode: string;
  // readySessionEnabled: boolean;
// }
var availableCodeList = ['GROWTH','AMAZE','REFRESH','MAGIC','BOOZE','MASTER', 'HEROIC','HUSTLE','TEQUILA','POLISH','PARADOX','CANVAS','ISLAND','WONDER'];
var usedCodeList = [];

function findConnection(id){
  return connections.filter(function(connection) {return connection.id === id;})[0];
}
function findRoom(secretCode){
  return rooms.filter(function(room) {return room.secretCode === secretCode;})[0];
}
function findNumberOfRoomConnections(secretCode){
  var roomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode})
  return roomConnections.length;
}
function findNumberOfReadyConnections(secretCode){
  var readyConnections = connections.filter(function(connection) {return (connection.ready === true && connection.secretCode === secretCode)})
  return readyConnections.length;
}
function resetAllStatusForRoomConnections(socket,secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    // may not necessarily want to reset profile name in future
    element.profileName = null;
    element.secretCode = null;
    element.ready = null;
    element.userType = null;
    // we need to get all sockets to leave
  })
}
function resetReadyStatusForRoomConnections(socket,secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    // may not necessarily want to reset profile name in future
    element.ready = null;
  })
}
function socketsLeaveRoom(secretCode){
  var allRoomConnections = connections.filter(function(connection) {return connection.secretCode === secretCode;});
  allRoomConnections.forEach(function(element){
    element.socket.leave(secretCode)
  })
}
function secretCodeGenerator(availableList, usedList) {
 //take first element of availableCodeList array,
 //add to end of usedCodeList
 var secretCode = availableList.shift();
 console.log('secret code is ' + secretCode);
 usedList.push(secretCode);
 return secretCode;
}
function returnBackSecretCode(availableList, usedList, secretCode){
  var indexOfRemovedCode = usedList.indexOf(secretCode);
  usedCodeList.splice(indexOfRemovedCode, 1);
  availableList.push(secretCode);
}

// =================================== Socket Controller Functions =================================

function connect(socket){
  //new connection, save the socket to them
  // when a socket first connects, provide all these attributes so that you would not get error when you do a status reset
  connections.push({
    socket: socket,
    id: socket.id,
    profileName: null,
    secretCode: null,
    ready: null,
    userType: null
  });
  console.log(`## New connection (${socket.id}). Total: ${connections.length}.`);
}

function disconnect(socket,io){
  //find the connection and remove  from the collection
  let connection = findConnection(socket.id);
  if (connection){
    if (connection.userType === "instructor") {
      let room = findRoom(connection.secretCode);
      if (room.readySessionEnabled === true) {
        instructorEndsReadySession(socket)
      }
      closeClass(socket,io);
    }
    if (connection.userType === "student") {
      if (connection.ready === true) {
        studentNotReady(socket, io)
      }
      studentLeaveClass(socket,io)
    }
    connections.splice(connections.indexOf(connection), 1);
    console.log(`## Connection (${connection.id}) (${socket.id}) disconnected. Remaining: ${connections.length}.`);
  }
  socket.disconnect();
}
      // =================================== Instructor ===========================

function submitClassName(socket, className){
  // this connection guy does nothing yet (just put here in case)
  var room = {
    name: className,
    // pass in secretcodefunction
    secretCode: secretCodeGenerator(availableCodeList,usedCodeList)
  }
  socket.join(room.secretCode)
  rooms.push(room);
  let connection = findConnection(socket.id);
  if (connection){
    connection.secretCode = room.secretCode;
    connection.userType = "instructor";
    socket.emit('createSecretCode', room)
  }
}

function closeClass(socket,io){
  let connection = findConnection(socket.id);
  if (connection) {
    let room = findRoom(connection.secretCode);
    if (room){
      console.log(`## Room (${room.name}) closed. Remaining: ${rooms.length}.`);
      rooms.splice(rooms.indexOf(room), 1);
      returnBackSecretCode(availableCodeList,usedCodeList,room.secretCode);
      // you want to find all connections in the room with a ready status and set them all to false
      resetAllStatusForRoomConnections(socket,room.secretCode)
      // reset room connection back to 0 for everyone when room is closed so that when you start a new room, the room starts with 0 connection
      io.to(room.secretCode).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(room.secretCode)));
      // this socketsLeaveRoom function must come after the io because if it comes first, we would not be able to emit to all sockets in that room anymore
      socketsLeaveRoom(room.secretCode)
      socket.broadcast.to(room.secretCode).emit('studentsCloseClass')
    }
  }
}

function instructorCallReady(socket){
  // use the classroomService to emit instructorReady() to the server that we are starting are u ready
  // use the server to emit startStudentReady() to all those in the room (excluding instructor) - use broadcast
  // and in the service (listen for an emit)
  // in the emit (reroute the student into student ready)
  let connection = findConnection(socket.id);
  if (connection) {
    let room = findRoom(connection.secretCode);
    if (room) {
      room.readySessionEnabled = true;
      socket.broadcast.to(room.secretCode).emit('startStudentReady')
    }
  }
}

function instructorEndsReadySession(socket){
  let connection = findConnection(socket.id);
  if (connection){
    let room = findRoom(connection.secretCode);
    if (room) {
      // you want to find all connections in the room with a ready status and set them all to false
      room.readySessionEnabled = false;
      resetReadyStatusForRoomConnections(socket,room.secretCode)
      socket.broadcast.to(room.secretCode).emit('studentsEndReadySession')
    }
  }
}
      // =================================== Student ===========================

function submitProfileName(socket, profileName){
  let connection = findConnection(socket.id);
  if (connection){
    connection.profileName = profileName;
  }
}

function submitSecretCode(socket, secretCode, io){
  // this connection guy does nothing yet (just put here in case)
  let room = findRoom(secretCode);
  if (room) {
    let connection = findConnection(socket.id);
    if (connection){
      connection.secretCode = secretCode;
      connection.userType = "student"
      socket.join(room.secretCode)
      // emit something back so that we can route him to the next page
      // =>> added this shit in when we were sleepy
      socket.emit('secretCodeExist', {secretCodeExist: true, room: room})
      // connections should be number of sockets who are joined to the room - 1 (instructor)
      io.to(room.secretCode).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(secretCode)-1));
    }
  } else {
    // emit him some message so that client knows that the secret code is wrong
    socket.emit('secretCodeExist', false)
  }
}

function studentLeaveClass(socket,io){
  let connection = findConnection(socket.id);
  if (connection){
    var secretCodeOfPreviousRoom = connection.secretCode
    connection.secretCode = null;
    if (connection.ready){
      connection.ready = null;
    }
    io.to(secretCodeOfPreviousRoom).emit("updateNumberOfRoomConnections", (findNumberOfRoomConnections(secretCodeOfPreviousRoom)-1))
    socket.leave(connection.secretCode)
  }
}

function studentReady(socket,io){
  let connection = findConnection(socket.id);
  if (connection){
    // the difference between studentReady and studentNotReady is setting connection.ready true and false
    connection.ready = true;
    // end of difference
    let room = findRoom(connection.secretCode);
    if (room) {
      // this socket emit is for the individual student's ready toggle button
      socket.emit("RecievedYourLovelyReadyResponse")
      // this socket broadcast is for everyone in the room so that everyone knows the number of students who are ready
      io.to(room.secretCode).emit("updateStudentReady", findNumberOfReadyConnections(connection.secretCode))
      // on the client side, it is waiting for updatestudentready
      // it will save a property for the number of studentready
      // display it on both the instructor and student dashboard
      // so we need to use the service reference hack so that both student and instructor ready component will be able to access the updated property
      // 1)Once i receive the emit, i need to save that argument that is passed to me under a property object
      // 2)I need to create a getProperty in the service (just above the constructor)
      // 3)In my two components, i need to make a getPropertyRequest
    }
  }
}

function studentNotReady(socket, io){
  let connection = findConnection(socket.id);
  if (connection){
    connection.ready = false;
    let room = findRoom(connection.secretCode);
    if (room) {
      // this socket emit is for the individual student's ready toggle button
      socket.emit("RecievedYourLovelyNotReadyResponse")
      console.log("server received lovely not ready response")
      // this socket broadcast is for everyone in the room so that everyone knows the number of students who are ready
      io.to(room.secretCode).emit("updateStudentReady", findNumberOfReadyConnections(connection.secretCode))
      console.log("studentNotReady completed run")
    }
  }
}

// Functions we are exporting to (server.js)
module.exports = {
  connect: connect,
  disconnect: disconnect,
  submitClassName: submitClassName,
  closeClass: closeClass,
  instructorEndsReadySession: instructorEndsReadySession,
  submitProfileName: submitProfileName,
  submitSecretCode: submitSecretCode,
  studentLeaveClass: studentLeaveClass,
  instructorCallReady: instructorCallReady,
  studentReady: studentReady,
  studentNotReady: studentNotReady
}
<|endoftext|>


<commit_before>'use strict';

var path = require('path');
var url = require('url');

var webpack = require('webpack');

var WriteManifestPlugin = require('../plugins/write-manifest');

var hopsConfig = require('..');

var getAssetPath = path.join.bind(path, hopsConfig.assetPath);

module.exports = {
  entry: [
    require.resolve('webpack-dev-server/client') + '?' + url.format({
      protocol: hopsConfig.https ? 'https' : 'http',
      hostname: hopsConfig.host === '0.0.0.0' ? 'localhost' : hopsConfig.host,
      port: hopsConfig.port
    }),
    require.resolve('webpack/hot/dev-server'),
    require.resolve('../shims/develop')
  ],
  output: {
    path: hopsConfig.buildDir,
    publicPath: '/',
    filename: getAssetPath('[name].js'),
    chunkFilename: getAssetPath('chunk-[id].js')
  },
  context: hopsConfig.appDir,
  resolve: require('../sections/resolve')('develop'),
  module: {
    rules: require('../sections/module-rules')('develop')
  },
  plugins: [
    new WriteManifestPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'development'
    })
  ],
  performance: {
    hints: false
  },
  devtool: '#source-map',
  watchOptions: {
    aggregateTimeout: 300,
    ignored: /node_modules/
  },
  devServer: {
    contentBase: hopsConfig.buildDir,
    hot: true,
    disableHostCheck: true,
    overlay: {
      warnings: true,
      errors: true
    },
    stats: 'errors-only',
    https: require('../sections/dev-server-https')()
  }
};
<commit_msg>feat(hops-config): use faster source map strategy<commit_after>'use strict';

var path = require('path');
var url = require('url');

var webpack = require('webpack');

var WriteManifestPlugin = require('../plugins/write-manifest');

var hopsConfig = require('..');

var getAssetPath = path.join.bind(path, hopsConfig.assetPath);

module.exports = {
  entry: [
    require.resolve('webpack-dev-server/client') + '?' + url.format({
      protocol: hopsConfig.https ? 'https' : 'http',
      hostname: hopsConfig.host === '0.0.0.0' ? 'localhost' : hopsConfig.host,
      port: hopsConfig.port
    }),
    require.resolve('webpack/hot/dev-server'),
    require.resolve('../shims/develop')
  ],
  output: {
    path: hopsConfig.buildDir,
    publicPath: '/',
    filename: getAssetPath('[name].js'),
    chunkFilename: getAssetPath('chunk-[id].js')
  },
  context: hopsConfig.appDir,
  resolve: require('../sections/resolve')('develop'),
  module: {
    rules: require('../sections/module-rules')('develop')
  },
  plugins: [
    new WriteManifestPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'development'
    })
  ],
  performance: {
    hints: false
  },
  devtool: 'cheap-module-eval-source-map',
  watchOptions: {
    aggregateTimeout: 300,
    ignored: /node_modules/
  },
  devServer: {
    contentBase: hopsConfig.buildDir,
    hot: true,
    disableHostCheck: true,
    overlay: {
      warnings: true,
      errors: true
    },
    stats: 'errors-only',
    https: require('../sections/dev-server-https')()
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';

import { login } from '../actions';

import TopMenu from '../components/TopMenu'
import Dashboard from '../components/Dasshboard';
import Performance from '../components/Performance';
import Preferences from '../components/Preferences';

class Authenticated extends React.Component {
  constructor () {
    super();
    this.state = { loggedIn: false };
  }

  render() {
    if (!this.props.loggedIn) {
      return <Redirect to="/sign-in" />
    } else {
      return

        <TopMenu />
        <Route exact path="/" component={Dashboard}/>
        <Route path="/performance" component={Performance}/>
        <Route path="/preferences" component={Preferences}/>

;
    }
  }
}

const mapStateToProps = (state) => ({
  loggedIn: state.authorization.loggedIn,
});

const mapDispatchToProps = (dispatch) => ({
  login: () => dispatch(login()),
});

export default connect(mapStateToProps, mapDispatchToProps)(Authenticated);
<commit_msg>fix: Authenticated js<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';

import { login } from '../actions';

import TopMenu from '../components/TopMenu'
import Dashboard from '../components/Dashboard';
import Performance from '../components/Performance';
import Preferences from '../components/Preferences';

class Authenticated extends React.Component {
  constructor () {
    super();
    this.state = { loggedIn: false };
  }

  render() {
    if (!this.props.loggedIn) {
      return <Redirect to="/sign-in" />
    } else {
      return

        <TopMenu />
        <Route exact path="/" component={Dashboard}/>
        <Route path="/performance" component={Performance}/>
        <Route path="/preferences" component={Preferences}/>

;
    }
  }
}

const mapStateToProps = (state) => ({
  loggedIn: state.authorization.loggedIn,
});

const mapDispatchToProps = (dispatch) => ({
  login: () => dispatch(login()),
});

export default connect(mapStateToProps, mapDispatchToProps)(Authenticated);
<|endoftext|>


<commit_before>import Immutable from 'immutable'
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { push, replace } from 'react-router-redux'
import { bindActionCreators } from 'redux'
import classNames from 'classnames'
import set from 'lodash/set'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectAssets } from '../selectors/assets'
import {
  selectColumnWidth,
  selectCommentOffset,
  selectContentWidth,
  selectDeviceSize,
  selectInnerHeight,
  selectIsMobile,
} from '../selectors/gui'
import {
  selectPost,
  selectPostAuthor,
  selectPostBody,
  selectPostCategoryName,
  selectPostCategorySlug,
  selectPostCommentsCount,
  selectPostContent,
  selectPostContentWarning,
  selectPostCreatedAt,
  selectPostDetailPath,
  selectPostIsCommentsRequesting,
  selectPostIsGridMode,
  selectPostIsOwn,
  selectPostIsOwnOriginal,
  selectPostIsRepost,
  selectPostIsReposting,
  selectPostIsWatching,
  selectPostLoved,
  selectPostLovesCount,
  selectPostRepostAuthorWithFallback,
  selectPostRepostContent,
  selectPostReposted,
  selectPostRepostsCount,
  selectPostShowCommentEditor,
  selectPostShowCommentsDrawer,
  selectPostShowEditor,
  selectPostShowLoversDrawer,
  selectPostShowRepostersDrawer,
  selectPostSummary,
  selectPostViewsCountRounded,
  selectPropsPostId,
} from '../selectors/post'
import { selectIsDiscoverRoot, selectIsPostDetail, selectPathname, selectPreviousPath } from '../selectors/routing'
import { trackEvent } from '../actions/analytics'
import { openModal, closeModal } from '../actions/modals'
import * as postActions from '../actions/posts'
import ConfirmDialog from '../components/dialogs/ConfirmDialog'
import FlagDialog from '../components/dialogs/FlagDialog'
import ShareDialog from '../components/dialogs/ShareDialog'
import Editor from '../components/editor/Editor'
import { HeartIcon, RepostIcon } from '../components/posts/PostIcons'
import {
  CategoryHeader,
  CommentStream,
  PostBody,
  PostHeader,
  RepostHeader,
} from '../components/posts/PostRenderables'
import { PostTools, WatchTool } from '../components/posts/PostTools'
import { UserDrawer } from '../components/users/UserRenderables'
import { postLovers, postReposters } from '../networking/api'

// TODO: Possibly create an individual mapStateToProps for each container
// instance. This will allow each component it's own private group of
// selectors. It would be good to measure this though, based on how these run
// we may not gain a whole lot from it.
export function mapStateToProps(state, props) {
  return {
    assets: selectAssets(state),
    author: selectPostAuthor(state, props),
    categoryName: selectPostCategoryName(state, props),
    categoryPath: selectPostCategorySlug(state, props),
    columnWidth: selectColumnWidth(state),
    commentOffset: selectCommentOffset(state),
    content: selectPostContent(state, props),
    contentWarning: selectPostContentWarning(state, props),
    contentWidth: selectContentWidth(state),
    detailPath: selectPostDetailPath(state, props),
    deviceSize: selectDeviceSize(state),
    innerHeight: selectInnerHeight(state),
    isCommentsRequesting: selectPostIsCommentsRequesting(state, props),
    isDiscoverRoot: selectIsDiscoverRoot(state, props),
    isGridMode: selectPostIsGridMode(state, props),
    isLoggedIn: selectIsLoggedIn(state),
    isMobile: selectIsMobile(state),
    isOwnOriginalPost: selectPostIsOwnOriginal(state, props),
    isOwnPost: selectPostIsOwn(state, props),
    isPostDetail: selectIsPostDetail(state, props),
    isRepost: selectPostIsRepost(state, props),
    isReposting: selectPostIsReposting(state, props),
    isWatchingPost: selectPostIsWatching(state, props),
    pathname: selectPathname(state),
    post: selectPost(state, props),
    postBody: selectPostBody(state, props),
    postCommentsCount: selectPostCommentsCount(state, props),
    postCreatedAt: selectPostCreatedAt(state, props),
    postId: selectPropsPostId(state, props),
    postLoved: selectPostLoved(state, props),
    postLovesCount: selectPostLovesCount(state, props),
    postReposted: selectPostReposted(state, props),
    postRepostsCount: selectPostRepostsCount(state, props),
    postViewsCountRounded: selectPostViewsCountRounded(state, props),
    previousPath: selectPreviousPath(state),
    repostAuthor: selectPostRepostAuthorWithFallback(state, props),
    repostContent: selectPostRepostContent(state, props),
    showCommentEditor: selectPostShowCommentEditor(state, props),
    showComments: selectPostShowCommentsDrawer(state, props),
    showEditor: selectPostShowEditor(state, props),
    showLovers: selectPostShowLoversDrawer(state, props),
    showReposters: selectPostShowRepostersDrawer(state, props),
    summary: selectPostSummary(state, props),
  }
}

class PostContainer extends Component {

  static propTypes = {
    assets: PropTypes.object,
    author: PropTypes.object.isRequired,
    categoryName: PropTypes.string,
    categoryPath: PropTypes.string,
    columnWidth: PropTypes.number.isRequired,
    commentOffset: PropTypes.number.isRequired,
    content: PropTypes.object.isRequired,
    contentWarning: PropTypes.string,
    contentWidth: PropTypes.number.isRequired,
    detailPath: PropTypes.string.isRequired,
    deviceSize: PropTypes.string.isRequired,
    dispatch: PropTypes.func.isRequired,
    innerHeight: PropTypes.number.isRequired,
    isCommentsRequesting: PropTypes.bool.isRequired,
    isDiscoverRoot: PropTypes.bool.isRequired,
    isGridMode: PropTypes.bool.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    isMobile: PropTypes.bool.isRequired,
    isOwnOriginalPost: PropTypes.bool.isRequired,
    isOwnPost: PropTypes.bool.isRequired,
    isPostDetail: PropTypes.bool.isRequired,
    isPostHeaderHidden: PropTypes.bool,
    isRepost: PropTypes.bool.isRequired,
    isReposting: PropTypes.bool.isRequired,
    isWatchingPost: PropTypes.bool.isRequired,
    pathname: PropTypes.string.isRequired,
    post: PropTypes.object.isRequired,
    postBody: PropTypes.object,
    postCommentsCount: PropTypes.number.isRequired,
    postCreatedAt: PropTypes.string.isRequired,
    postId: PropTypes.string.isRequired,
    postLoved: PropTypes.bool.isRequired,
    postLovesCount: PropTypes.number.isRequired,
    postReposted: PropTypes.bool.isRequired,
    postRepostsCount: PropTypes.number.isRequired,
    postViewsCountRounded: PropTypes.string.isRequired,
    previousPath: PropTypes.string,
    repostAuthor: PropTypes.object,
    repostContent: PropTypes.object,
    showCommentEditor: PropTypes.bool.isRequired,
    showComments: PropTypes.bool.isRequired,
    showEditor: PropTypes.bool.isRequired,
    showLovers: PropTypes.bool.isRequired,
    showReposters: PropTypes.bool.isRequired,
    summary: PropTypes.object.isRequired,
  }

  static defaultProps = {
    assets: null,
    categoryName: null,
    categoryPath: null,
    contentWarning: null,
    isPostHeaderHidden: false,
    postBody: null,
    previousPath: null,
    repostAuthor: null,
    repostContent: null,
  }

  static childContextTypes = {
    onClickDeletePost: PropTypes.func.isRequired,
    onClickEditPost: PropTypes.func.isRequired,
    onClickFlagPost: PropTypes.func.isRequired,
    onClickLovePost: PropTypes.func.isRequired,
    onClickRepostPost: PropTypes.func.isRequired,
    onClickSharePost: PropTypes.func.isRequired,
    onClickToggleComments: PropTypes.func.isRequired,
    onClickToggleLovers: PropTypes.func.isRequired,
    onClickToggleReposters: PropTypes.func.isRequired,
    onClickWatchPost: PropTypes.func.isRequired,
  }

  static contextTypes = {
    onClickOpenRegistrationRequestDialog: PropTypes.func,
  }

  getChildContext() {
    const { isLoggedIn } = this.props
    return {
      onClickDeletePost: this.onClickDeletePost,
      onClickEditPost: this.onClickEditPost,
      onClickFlagPost: this.onClickFlagPost,
      onClickLovePost: isLoggedIn ? this.onClickLovePost : this.onOpenSignupModal,
      onClickRepostPost: isLoggedIn ? this.onClickRepostPost : this.onOpenSignupModal,
      onClickSharePost: this.onClickSharePost,
      onClickToggleComments: this.onClickToggleComments,
      onClickToggleLovers: isLoggedIn ? this.onClickToggleLovers : this.onOpenSignupModal,
      onClickToggleReposters: isLoggedIn ? this.onClickToggleReposters : this.onOpenSignupModal,
      onClickWatchPost: isLoggedIn ? this.onClickWatchPost : this.onOpenSignupModal,
    }
  }

  componentWillMount() {
    this.state = {
      isCommentsActive: false,
      showComments: false,
      showLovers: false,
      showReposters: false,
    }
  }

  shouldComponentUpdate(nextProps) {
    return !Immutable.is(nextProps.post, this.props.post) ||
      ['columnWidth', 'contentWidth', 'innerHeight', 'isGridMode', 'isLoggedIn', 'isMobile'].some(prop =>
        nextProps[prop] !== this.props[prop],
      )
  }

  onClickDeletePost = () => {
    const { dispatch } = this.props
    dispatch(openModal(
      <ConfirmDialog
        title="Delete Post?"
        onConfirm={this.onConfirmDeletePost}
        onDismiss={this.onCloseModal}
      />))
  }

  onConfirmDeletePost = () => {
    const { dispatch, pathname, post, previousPath } = this.props
    this.onCloseModal()
    const action = postActions.deletePost(post)
    if (pathname.match(post.get('token'))) {
      set(action, 'meta.successAction', replace(previousPath || '/'))
    }
    dispatch(action)
  }

  onClickEditPost = () => {
    const { dispatch, post } = this.props
    dispatch(postActions.toggleEditing(post, true))
    dispatch(postActions.loadEditablePost(post.get('id')))
  }

  onClickFlagPost = () => {
    const { deviceSize, dispatch } = this.props
    dispatch(openModal(
      <FlagDialog
        deviceSize={deviceSize}
        onResponse={this.onPostWasFlagged}
        onConfirm={this.onCloseModal}
      />))
  }

  onPostWasFlagged = ({ flag }) => {
    const { dispatch, post } = this.props
    dispatch(postActions.flagPost(post, flag))
  }

  onClickLovePost = () => {
    const { dispatch, post, postLoved } = this.props
    if (postLoved) {
      dispatch(postActions.unlovePost(post))
    } else {
      dispatch(postActions.lovePost(post))
      dispatch(trackEvent('web_production.post_actions_love'))
    }
  }

  onClickRepostPost = () => {
    const { dispatch, post, postReposted } = this.props
    if (!postReposted) {
      dispatch(postActions.toggleReposting(post, true))
      dispatch(postActions.loadEditablePost(post.get('id')))
    }
  }

  onClickSharePost = () => {
    const { author, dispatch, post } = this.props
    const action = bindActionCreators(trackEvent, dispatch)
    dispatch(openModal(<ShareDialog author={author} post={post} trackEvent={action} />))
    dispatch(trackEvent('open-share-dialog'))
  }

  onClickToggleComments = () => {
    const { detailPath, dispatch, isLoggedIn, post, showComments } = this.props
    if (isLoggedIn) {
      const nextShowComments = !showComments
      this.setState({ isCommentsActive: nextShowComments })
      dispatch(postActions.toggleComments(post, nextShowComments))
    } else {
      dispatch(push(detailPath))
    }
  }

  onClickToggleLovers = () => {
    const { detailPath, dispatch, isGridMode, pathname, post, showLovers } = this.props
    if (isGridMode && pathname !== detailPath) {
      dispatch(push(detailPath))
    } else {
      const nextShowLovers = !showLovers
      dispatch(postActions.toggleLovers(post, nextShowLovers))
    }
  }

  onClickToggleReposters = () => {
    const { detailPath, dispatch, isGridMode, pathname, post, showReposters } = this.props
    if (isGridMode && pathname !== detailPath) {
      dispatch(push(detailPath))
    } else {
      const nextShowReposters = !showReposters
      dispatch(postActions.toggleReposters(post, nextShowReposters))
    }
  }

  onClickWatchPost = () => {
    const { dispatch, post, isWatchingPost } = this.props
    if (isWatchingPost) {
      dispatch(postActions.unwatchPost(post))
      dispatch(trackEvent('unwatched-post'))
    } else {
      dispatch(postActions.watchPost(post))
      dispatch(trackEvent('watched-post'))
    }
  }

  onCloseModal = () => {
    const { dispatch } = this.props
    dispatch(closeModal())
  }

  onOpenSignupModal = () => {
    const { onClickOpenRegistrationRequestDialog } = this.context
    onClickOpenRegistrationRequestDialog('post-tools')
  }

  render() {
    const {
      assets,
      author,
      categoryName,
      categoryPath,
      columnWidth,
      commentOffset,
      content,
      contentWarning,
      contentWidth,
      detailPath,
      innerHeight,
      isCommentsRequesting,
      isDiscoverRoot,
      isGridMode,
      isLoggedIn,
      isMobile,
      isOwnOriginalPost,
      isOwnPost,
      isPostDetail,
      isPostHeaderHidden,
      isRepost,
      isReposting,
      isWatchingPost,
      post,
      postBody,
      postCommentsCount,
      postCreatedAt,
      postId,
      postLoved,
      postLovesCount,
      postReposted,
      postRepostsCount,
      postViewsCountRounded,
      repostAuthor,
      repostContent,
      showCommentEditor,
      showComments,
      showEditor,
      showLovers,
      showReposters,
      summary,
    } = this.props
    if (!post || !post.get('id') || !author || !author.get('id')) { return null }
    let postHeader
    const headerProps = { detailPath, postCreatedAt, postId }
    if (isRepost) {
      postHeader = (
        <RepostHeader
          {...headerProps}
          inUserDetail={isPostHeaderHidden}
          repostAuthor={repostAuthor}
          repostedBy={author}
        />
      )
    } else if (isPostHeaderHidden) {
      postHeader = null
    } else if (isDiscoverRoot && categoryName && categoryPath) {
      postHeader = (
        <CategoryHeader
          {...headerProps}
          author={author}
          categoryName={categoryName}
          categoryPath={categoryPath}
        />
      )
    } else {
      postHeader = (
        <PostHeader
          {...headerProps}
          author={author}
          isPostDetail={isPostDetail}
        />
      )
    }

    const isRepostAnimating = isReposting && !postBody
    return (
      <div className={classNames('Post', { isPostHeaderHidden: isPostHeaderHidden && !isRepost })}>
        {postHeader}
        {showEditor ?
          <Editor post={post} /> :
          <PostBody
            assets={assets}
            author={author}
            columnWidth={columnWidth}
            commentOffset={commentOffset}
            content={content}
            contentWarning={contentWarning}
            contentWidth={contentWidth}
            detailPath={detailPath}
            innerHeight={innerHeight}
            isGridMode={isGridMode}
            isRepost={isRepost}
            postId={postId}
            repostContent={repostContent}
            summary={summary}
          />
        }
        <PostTools
          author={author}
          detailPath={detailPath}
          isCommentsActive={this.state.isCommentsActive}
          isCommentsRequesting={isCommentsRequesting}
          isGridMode={isGridMode}
          isLoggedIn={isLoggedIn}
          isMobile={isMobile}
          isOwnOriginalPost={isOwnOriginalPost}
          isOwnPost={isOwnPost}
          isRepostAnimating={isRepostAnimating}
          isWatchingPost={isWatchingPost}
          postCreatedAt={postCreatedAt}
          postCommentsCount={postCommentsCount}
          postId={postId}
          postLoved={postLoved}
          postLovesCount={postLovesCount}
          postReposted={postReposted}
          postRepostsCount={postRepostsCount}
          postViewsCountRounded={postViewsCountRounded}
        />
        {showLovers &&
          <UserDrawer
            endpoint={postLovers(postId)}
            icon={<HeartIcon />}
            key={`userAvatarsLovers_${postId}`}
            postId={postId}
            resultType="love"
          />
        }
        {showReposters &&
          <UserDrawer
            endpoint={postReposters(postId)}
            icon={<RepostIcon />}
            key={`userAvatarsReposters_${postId}`}
            postId={postId}
            resultType="repost"
          />
        }
        {isMobile &&
          <WatchTool
            isMobile
            isWatchingPost={isWatchingPost}
            onClickWatchPost={this.onClickWatchPost}
          />
        }
        {showCommentEditor && <Editor post={post} isComment />}
        {showComments &&
          <CommentStream
            detailPath={detailPath}
            postCommentsCount={postCommentsCount}
            postId={postId}
          />
        }
      </div>)
  }
}

export default connect(mapStateToProps)(PostContainer)

<commit_msg>Import the specific post actions<commit_after>import Immutable from 'immutable'
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { push, replace } from 'react-router-redux'
import { bindActionCreators } from 'redux'
import classNames from 'classnames'
import set from 'lodash/set'
import { selectIsLoggedIn } from '../selectors/authentication'
import { selectAssets } from '../selectors/assets'
import {
  selectColumnWidth,
  selectCommentOffset,
  selectContentWidth,
  selectDeviceSize,
  selectInnerHeight,
  selectIsMobile,
} from '../selectors/gui'
import {
  selectPost,
  selectPostAuthor,
  selectPostBody,
  selectPostCategoryName,
  selectPostCategorySlug,
  selectPostCommentsCount,
  selectPostContent,
  selectPostContentWarning,
  selectPostCreatedAt,
  selectPostDetailPath,
  selectPostIsCommentsRequesting,
  selectPostIsGridMode,
  selectPostIsOwn,
  selectPostIsOwnOriginal,
  selectPostIsRepost,
  selectPostIsReposting,
  selectPostIsWatching,
  selectPostLoved,
  selectPostLovesCount,
  selectPostRepostAuthorWithFallback,
  selectPostRepostContent,
  selectPostReposted,
  selectPostRepostsCount,
  selectPostShowCommentEditor,
  selectPostShowCommentsDrawer,
  selectPostShowEditor,
  selectPostShowLoversDrawer,
  selectPostShowRepostersDrawer,
  selectPostSummary,
  selectPostViewsCountRounded,
  selectPropsPostId,
} from '../selectors/post'
import { selectIsDiscoverRoot, selectIsPostDetail, selectPathname, selectPreviousPath } from '../selectors/routing'
import { trackEvent } from '../actions/analytics'
import { openModal, closeModal } from '../actions/modals'
import {
  deletePost,
  flagPost,
  loadEditablePost,
  lovePost,
  toggleComments,
  toggleEditing,
  toggleLovers,
  toggleReposters,
  toggleReposting,
  unlovePost,
  unwatchPost,
  watchPost,
} from '../actions/posts'
import ConfirmDialog from '../components/dialogs/ConfirmDialog'
import FlagDialog from '../components/dialogs/FlagDialog'
import ShareDialog from '../components/dialogs/ShareDialog'
import Editor from '../components/editor/Editor'
import { HeartIcon, RepostIcon } from '../components/posts/PostIcons'
import {
  CategoryHeader,
  CommentStream,
  PostBody,
  PostHeader,
  RepostHeader,
} from '../components/posts/PostRenderables'
import { PostTools, WatchTool } from '../components/posts/PostTools'
import { UserDrawer } from '../components/users/UserRenderables'
import { postLovers, postReposters } from '../networking/api'

// TODO: Possibly create an individual mapStateToProps for each container
// instance. This will allow each component it's own private group of
// selectors. It would be good to measure this though, based on how these run
// we may not gain a whole lot from it.
export function mapStateToProps(state, props) {
  return {
    assets: selectAssets(state),
    author: selectPostAuthor(state, props),
    categoryName: selectPostCategoryName(state, props),
    categoryPath: selectPostCategorySlug(state, props),
    columnWidth: selectColumnWidth(state),
    commentOffset: selectCommentOffset(state),
    content: selectPostContent(state, props),
    contentWarning: selectPostContentWarning(state, props),
    contentWidth: selectContentWidth(state),
    detailPath: selectPostDetailPath(state, props),
    deviceSize: selectDeviceSize(state),
    innerHeight: selectInnerHeight(state),
    isCommentsRequesting: selectPostIsCommentsRequesting(state, props),
    isDiscoverRoot: selectIsDiscoverRoot(state, props),
    isGridMode: selectPostIsGridMode(state, props),
    isLoggedIn: selectIsLoggedIn(state),
    isMobile: selectIsMobile(state),
    isOwnOriginalPost: selectPostIsOwnOriginal(state, props),
    isOwnPost: selectPostIsOwn(state, props),
    isPostDetail: selectIsPostDetail(state, props),
    isRepost: selectPostIsRepost(state, props),
    isReposting: selectPostIsReposting(state, props),
    isWatchingPost: selectPostIsWatching(state, props),
    pathname: selectPathname(state),
    post: selectPost(state, props),
    postBody: selectPostBody(state, props),
    postCommentsCount: selectPostCommentsCount(state, props),
    postCreatedAt: selectPostCreatedAt(state, props),
    postId: selectPropsPostId(state, props),
    postLoved: selectPostLoved(state, props),
    postLovesCount: selectPostLovesCount(state, props),
    postReposted: selectPostReposted(state, props),
    postRepostsCount: selectPostRepostsCount(state, props),
    postViewsCountRounded: selectPostViewsCountRounded(state, props),
    previousPath: selectPreviousPath(state),
    repostAuthor: selectPostRepostAuthorWithFallback(state, props),
    repostContent: selectPostRepostContent(state, props),
    showCommentEditor: selectPostShowCommentEditor(state, props),
    showComments: selectPostShowCommentsDrawer(state, props),
    showEditor: selectPostShowEditor(state, props),
    showLovers: selectPostShowLoversDrawer(state, props),
    showReposters: selectPostShowRepostersDrawer(state, props),
    summary: selectPostSummary(state, props),
  }
}

class PostContainer extends Component {

  static propTypes = {
    assets: PropTypes.object,
    author: PropTypes.object.isRequired,
    categoryName: PropTypes.string,
    categoryPath: PropTypes.string,
    columnWidth: PropTypes.number.isRequired,
    commentOffset: PropTypes.number.isRequired,
    content: PropTypes.object.isRequired,
    contentWarning: PropTypes.string,
    contentWidth: PropTypes.number.isRequired,
    detailPath: PropTypes.string.isRequired,
    deviceSize: PropTypes.string.isRequired,
    dispatch: PropTypes.func.isRequired,
    innerHeight: PropTypes.number.isRequired,
    isCommentsRequesting: PropTypes.bool.isRequired,
    isDiscoverRoot: PropTypes.bool.isRequired,
    isGridMode: PropTypes.bool.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    isMobile: PropTypes.bool.isRequired,
    isOwnOriginalPost: PropTypes.bool.isRequired,
    isOwnPost: PropTypes.bool.isRequired,
    isPostDetail: PropTypes.bool.isRequired,
    isPostHeaderHidden: PropTypes.bool,
    isRepost: PropTypes.bool.isRequired,
    isReposting: PropTypes.bool.isRequired,
    isWatchingPost: PropTypes.bool.isRequired,
    pathname: PropTypes.string.isRequired,
    post: PropTypes.object.isRequired,
    postBody: PropTypes.object,
    postCommentsCount: PropTypes.number.isRequired,
    postCreatedAt: PropTypes.string.isRequired,
    postId: PropTypes.string.isRequired,
    postLoved: PropTypes.bool.isRequired,
    postLovesCount: PropTypes.number.isRequired,
    postReposted: PropTypes.bool.isRequired,
    postRepostsCount: PropTypes.number.isRequired,
    postViewsCountRounded: PropTypes.string.isRequired,
    previousPath: PropTypes.string,
    repostAuthor: PropTypes.object,
    repostContent: PropTypes.object,
    showCommentEditor: PropTypes.bool.isRequired,
    showComments: PropTypes.bool.isRequired,
    showEditor: PropTypes.bool.isRequired,
    showLovers: PropTypes.bool.isRequired,
    showReposters: PropTypes.bool.isRequired,
    summary: PropTypes.object.isRequired,
  }

  static defaultProps = {
    assets: null,
    categoryName: null,
    categoryPath: null,
    contentWarning: null,
    isPostHeaderHidden: false,
    postBody: null,
    previousPath: null,
    repostAuthor: null,
    repostContent: null,
  }

  static childContextTypes = {
    onClickDeletePost: PropTypes.func.isRequired,
    onClickEditPost: PropTypes.func.isRequired,
    onClickFlagPost: PropTypes.func.isRequired,
    onClickLovePost: PropTypes.func.isRequired,
    onClickRepostPost: PropTypes.func.isRequired,
    onClickSharePost: PropTypes.func.isRequired,
    onClickToggleComments: PropTypes.func.isRequired,
    onClickToggleLovers: PropTypes.func.isRequired,
    onClickToggleReposters: PropTypes.func.isRequired,
    onClickWatchPost: PropTypes.func.isRequired,
  }

  static contextTypes = {
    onClickOpenRegistrationRequestDialog: PropTypes.func,
  }

  getChildContext() {
    const { isLoggedIn } = this.props
    return {
      onClickDeletePost: this.onClickDeletePost,
      onClickEditPost: this.onClickEditPost,
      onClickFlagPost: this.onClickFlagPost,
      onClickLovePost: isLoggedIn ? this.onClickLovePost : this.onOpenSignupModal,
      onClickRepostPost: isLoggedIn ? this.onClickRepostPost : this.onOpenSignupModal,
      onClickSharePost: this.onClickSharePost,
      onClickToggleComments: this.onClickToggleComments,
      onClickToggleLovers: isLoggedIn ? this.onClickToggleLovers : this.onOpenSignupModal,
      onClickToggleReposters: isLoggedIn ? this.onClickToggleReposters : this.onOpenSignupModal,
      onClickWatchPost: isLoggedIn ? this.onClickWatchPost : this.onOpenSignupModal,
    }
  }

  componentWillMount() {
    this.state = {
      isCommentsActive: false,
      showComments: false,
      showLovers: false,
      showReposters: false,
    }
  }

  shouldComponentUpdate(nextProps) {
    return !Immutable.is(nextProps.post, this.props.post) ||
      ['columnWidth', 'contentWidth', 'innerHeight', 'isGridMode', 'isLoggedIn', 'isMobile'].some(prop =>
        nextProps[prop] !== this.props[prop],
      )
  }

  onClickDeletePost = () => {
    const { dispatch } = this.props
    dispatch(openModal(
      <ConfirmDialog
        title="Delete Post?"
        onConfirm={this.onConfirmDeletePost}
        onDismiss={this.onCloseModal}
      />))
  }

  onConfirmDeletePost = () => {
    const { dispatch, pathname, post, previousPath } = this.props
    this.onCloseModal()
    const action = deletePost(post)
    if (pathname.match(post.get('token'))) {
      set(action, 'meta.successAction', replace(previousPath || '/'))
    }
    dispatch(action)
  }

  onClickEditPost = () => {
    const { dispatch, post } = this.props
    dispatch(toggleEditing(post, true))
    dispatch(loadEditablePost(post.get('id')))
  }

  onClickFlagPost = () => {
    const { deviceSize, dispatch } = this.props
    dispatch(openModal(
      <FlagDialog
        deviceSize={deviceSize}
        onResponse={this.onPostWasFlagged}
        onConfirm={this.onCloseModal}
      />))
  }

  onPostWasFlagged = ({ flag }) => {
    const { dispatch, post } = this.props
    dispatch(flagPost(post, flag))
  }

  onClickLovePost = () => {
    const { dispatch, post, postLoved } = this.props
    if (postLoved) {
      dispatch(unlovePost(post))
    } else {
      dispatch(lovePost(post))
      dispatch(trackEvent('web_production.post_actions_love'))
    }
  }

  onClickRepostPost = () => {
    const { dispatch, post, postReposted } = this.props
    if (!postReposted) {
      dispatch(toggleReposting(post, true))
      dispatch(loadEditablePost(post.get('id')))
    }
  }

  onClickSharePost = () => {
    const { author, dispatch, post } = this.props
    const action = bindActionCreators(trackEvent, dispatch)
    dispatch(openModal(<ShareDialog author={author} post={post} trackEvent={action} />))
    dispatch(trackEvent('open-share-dialog'))
  }

  onClickToggleComments = () => {
    const { detailPath, dispatch, isLoggedIn, post, showComments } = this.props
    if (isLoggedIn) {
      const nextShowComments = !showComments
      this.setState({ isCommentsActive: nextShowComments })
      dispatch(toggleComments(post, nextShowComments))
    } else {
      dispatch(push(detailPath))
    }
  }

  onClickToggleLovers = () => {
    const { detailPath, dispatch, isGridMode, pathname, post, showLovers } = this.props
    if (isGridMode && pathname !== detailPath) {
      dispatch(push(detailPath))
    } else {
      const nextShowLovers = !showLovers
      dispatch(toggleLovers(post, nextShowLovers))
    }
  }

  onClickToggleReposters = () => {
    const { detailPath, dispatch, isGridMode, pathname, post, showReposters } = this.props
    if (isGridMode && pathname !== detailPath) {
      dispatch(push(detailPath))
    } else {
      const nextShowReposters = !showReposters
      dispatch(toggleReposters(post, nextShowReposters))
    }
  }

  onClickWatchPost = () => {
    const { dispatch, post, isWatchingPost } = this.props
    if (isWatchingPost) {
      dispatch(unwatchPost(post))
      dispatch(trackEvent('unwatched-post'))
    } else {
      dispatch(watchPost(post))
      dispatch(trackEvent('watched-post'))
    }
  }

  onCloseModal = () => {
    const { dispatch } = this.props
    dispatch(closeModal())
  }

  onOpenSignupModal = () => {
    const { onClickOpenRegistrationRequestDialog } = this.context
    onClickOpenRegistrationRequestDialog('post-tools')
  }

  render() {
    const {
      assets,
      author,
      categoryName,
      categoryPath,
      columnWidth,
      commentOffset,
      content,
      contentWarning,
      contentWidth,
      detailPath,
      innerHeight,
      isCommentsRequesting,
      isDiscoverRoot,
      isGridMode,
      isLoggedIn,
      isMobile,
      isOwnOriginalPost,
      isOwnPost,
      isPostDetail,
      isPostHeaderHidden,
      isRepost,
      isReposting,
      isWatchingPost,
      post,
      postBody,
      postCommentsCount,
      postCreatedAt,
      postId,
      postLoved,
      postLovesCount,
      postReposted,
      postRepostsCount,
      postViewsCountRounded,
      repostAuthor,
      repostContent,
      showCommentEditor,
      showComments,
      showEditor,
      showLovers,
      showReposters,
      summary,
    } = this.props
    if (!post || !post.get('id') || !author || !author.get('id')) { return null }
    let postHeader
    const headerProps = { detailPath, postCreatedAt, postId }
    if (isRepost) {
      postHeader = (
        <RepostHeader
          {...headerProps}
          inUserDetail={isPostHeaderHidden}
          repostAuthor={repostAuthor}
          repostedBy={author}
        />
      )
    } else if (isPostHeaderHidden) {
      postHeader = null
    } else if (isDiscoverRoot && categoryName && categoryPath) {
      postHeader = (
        <CategoryHeader
          {...headerProps}
          author={author}
          categoryName={categoryName}
          categoryPath={categoryPath}
        />
      )
    } else {
      postHeader = (
        <PostHeader
          {...headerProps}
          author={author}
          isPostDetail={isPostDetail}
        />
      )
    }

    const isRepostAnimating = isReposting && !postBody
    return (
      <div className={classNames('Post', { isPostHeaderHidden: isPostHeaderHidden && !isRepost })}>
        {postHeader}
        {showEditor ?
          <Editor post={post} /> :
          <PostBody
            assets={assets}
            author={author}
            columnWidth={columnWidth}
            commentOffset={commentOffset}
            content={content}
            contentWarning={contentWarning}
            contentWidth={contentWidth}
            detailPath={detailPath}
            innerHeight={innerHeight}
            isGridMode={isGridMode}
            isRepost={isRepost}
            postId={postId}
            repostContent={repostContent}
            summary={summary}
          />
        }
        <PostTools
          author={author}
          detailPath={detailPath}
          isCommentsActive={this.state.isCommentsActive}
          isCommentsRequesting={isCommentsRequesting}
          isGridMode={isGridMode}
          isLoggedIn={isLoggedIn}
          isMobile={isMobile}
          isOwnOriginalPost={isOwnOriginalPost}
          isOwnPost={isOwnPost}
          isRepostAnimating={isRepostAnimating}
          isWatchingPost={isWatchingPost}
          postCreatedAt={postCreatedAt}
          postCommentsCount={postCommentsCount}
          postId={postId}
          postLoved={postLoved}
          postLovesCount={postLovesCount}
          postReposted={postReposted}
          postRepostsCount={postRepostsCount}
          postViewsCountRounded={postViewsCountRounded}
        />
        {showLovers &&
          <UserDrawer
            endpoint={postLovers(postId)}
            icon={<HeartIcon />}
            key={`userAvatarsLovers_${postId}`}
            postId={postId}
            resultType="love"
          />
        }
        {showReposters &&
          <UserDrawer
            endpoint={postReposters(postId)}
            icon={<RepostIcon />}
            key={`userAvatarsReposters_${postId}`}
            postId={postId}
            resultType="repost"
          />
        }
        {isMobile &&
          <WatchTool
            isMobile
            isWatchingPost={isWatchingPost}
            onClickWatchPost={this.onClickWatchPost}
          />
        }
        {showCommentEditor && <Editor post={post} isComment />}
        {showComments &&
          <CommentStream
            detailPath={detailPath}
            postCommentsCount={postCommentsCount}
            postId={postId}
          />
        }
      </div>)
  }
}

export default connect(mapStateToProps)(PostContainer)

<|endoftext|>


<commit_before>import './optional_newrelic'
import './bootstrap'

import path from 'path'
import fs from 'fs'
import passport from 'passport'
import http from 'http'
import spdy from 'spdy'
import express from 'express'
import cookieParser from 'cookie-parser'
import Azure from './azure'
import User from './user'
import tokenHandler from './token_handler'
import config from './config'
import bodyParser from 'body-parser'
import log from './log'
import api from './api'
//import {User as ModelUser} from './model'
import actions from './actions'
import reporter from './reporter'

import createDebug from 'debug'
let debug = createDebug('dhm:app')
debug('starting server')

var app = express()
app.use(reporter.requestHandler)

function createServer () {
  if (process.env.USE_HTTPS === '1') {
    const options = {
      cert: fs.readFileSync(process.env.SSL_CERT),
      key: fs.readFileSync(process.env.SSL_KEY)
    }
    return new spdy.Server(options, app)
  } else {
    return new http.Server(app)
  }
}
const server = createServer()

let azure = Azure.createFromEnv()

app.use(log.requestLogger())
app.enable('trust proxy')
app.disable('x-powered-by')
app.use(bodyParser.json({limit: '1mb'}))
app.use(cookieParser())

app.use(passport.initialize())
app.use('/api/actions', actions)
app.use('/api', api.router)

app.get('/js/config.js', function(req, res) {
  var cfg = {
    socketIoUrl: 'http://localhost:3000',
    storageAccount: azure.blobs.storageAccount,
  }
  res.send('angular.module("dhm").constant("config", ' + JSON.stringify(cfg) + ')')
})

app.use(express.static(__dirname + '/../../../../build/public'))
app.use(express.static(__dirname + '/../../../../public'))
app.get('*', function(req, res, next) {
  req.url = '/'
  res.sendFile(path.resolve(__dirname + '/../../../../build/public/index.html'))
})

app.use(function(err, req, res, next) {
  if (res.headersSent) {
    return next(err)
  }

  if (err.rest) {
    res.status(400).send(err.rest)
  }

  next(err)
})

app.use(reporter.errorHandler)

// log errors
app.use(log.errorLogger())

// error handler
app.use(function(err, req, res, next) {
  // don't do anything if the response was already sent
  if (res.headersSent) {
    return next(err)
  }

  res.status(500)

  if (req.accepts('html')) {
    res.send('Internal Server Error. Request identifier: ' + req.id)
    return next(err)
  }

  if (req.accepts('json')) {
    res.json({ error: 'Internal Server Error', requestId: req.id })
    return next(err)
  }

  res.type('txt').send('Internal Server Error. Request identifier: ' + req.id)

  next(err)
})

function start() {
  var port = process.env.PORT || 3000

  const listener = server.listen(port, function(err) {
    if (err) return reporter.error(err, {fatal: true})

    log.info({port: port}, 'listening on %s', port)

    const protocol = process.env.USE_HTTPS === '1' ? 'https' : 'http'
    const address = listener.address().family === 'IPv6' ? `[${listener.address().address}]` : listener.address().address
    console.info('----\n==> ✅  %s is running', 'Daheim App API')
    console.info('==> 💻  Open %s://%s:%s in a browser to view the app.', protocol, address, listener.address().port)
  })
  server.on('error', function(err) {
    reporter.error(err)
  })
  return server
}

module.exports = {
  app: app,
  start: start,
}

start()
<commit_msg>Fixed fake positive API server error reports<commit_after>import './optional_newrelic'
import './bootstrap'

import path from 'path'
import fs from 'fs'
import passport from 'passport'
import http from 'http'
import spdy from 'spdy'
import express from 'express'
import cookieParser from 'cookie-parser'
import Azure from './azure'
import User from './user'
import tokenHandler from './token_handler'
import config from './config'
import bodyParser from 'body-parser'
import log from './log'
import api from './api'
//import {User as ModelUser} from './model'
import actions from './actions'
import reporter from './reporter'

import createDebug from 'debug'
let debug = createDebug('dhm:app')
debug('starting server')

var app = express()
app.use(reporter.requestHandler)

function createServer () {
  if (process.env.USE_HTTPS === '1') {
    const options = {
      cert: fs.readFileSync(process.env.SSL_CERT),
      key: fs.readFileSync(process.env.SSL_KEY)
    }
    return new spdy.Server(options, app)
  } else {
    return new http.Server(app)
  }
}
const server = createServer()

let azure = Azure.createFromEnv()

app.use(log.requestLogger())
app.enable('trust proxy')
app.disable('x-powered-by')
app.use(bodyParser.json({limit: '1mb'}))
app.use(cookieParser())

app.use(passport.initialize())
app.use('/api/actions', actions)
app.use('/api', api.router)

app.get('/js/config.js', function(req, res) {
  var cfg = {
    socketIoUrl: 'http://localhost:3000',
    storageAccount: azure.blobs.storageAccount,
  }
  res.send('angular.module("dhm").constant("config", ' + JSON.stringify(cfg) + ')')
})

app.use(express.static(__dirname + '/../../../../build/public'))
app.use(express.static(__dirname + '/../../../../public'))
app.get('*', function(req, res, next) {
  req.url = '/'
  res.sendFile(path.resolve(__dirname + '/../../../../build/public/index.html'))
})

app.use(function(err, req, res, next) {
  if (!res.headersSent && err.rest) return res.status(400).send(err.rest)
  next(err)
})

app.use(reporter.errorHandler)

// log errors
app.use(log.errorLogger())

// error handler
app.use(function(err, req, res, next) {
  // don't do anything if the response was already sent
  if (res.headersSent) {
    return next(err)
  }

  res.status(500)

  if (req.accepts('html')) {
    res.send('Internal Server Error. Request identifier: ' + req.id)
    return next(err)
  }

  if (req.accepts('json')) {
    res.json({ error: 'Internal Server Error', requestId: req.id })
    return next(err)
  }

  res.type('txt').send('Internal Server Error. Request identifier: ' + req.id)

  next(err)
})

function start() {
  var port = process.env.PORT || 3000

  const listener = server.listen(port, function(err) {
    if (err) return reporter.error(err, {fatal: true})

    log.info({port: port}, 'listening on %s', port)

    const protocol = process.env.USE_HTTPS === '1' ? 'https' : 'http'
    const address = listener.address().family === 'IPv6' ? `[${listener.address().address}]` : listener.address().address
    console.info('----\n==> ✅  %s is running', 'Daheim App API')
    console.info('==> 💻  Open %s://%s:%s in a browser to view the app.', protocol, address, listener.address().port)
  })
  server.on('error', function(err) {
    reporter.error(err)
  })
  return server
}

module.exports = {
  app: app,
  start: start,
}

start()
<|endoftext|>


<commit_before>import { MiddlewareCache } from '../util/caches';
import process from '../util/process';

const { SyncTreeHookCache } = MiddlewareCache;
const { assign, keys } = Object;
const empty = {};
const keyNames = ['old', 'new'];

// Compares how the new state should look to the old state and mutates it,
// while recording the changes along the way.
export default function syncTree(oldTree, newTree, patches) {
  if (!oldTree) oldTree = empty;
  if (!newTree) newTree = empty;

  const oldNodeName = oldTree.nodeName;
  const newNodeName = newTree.nodeName;
  const isFragment = newTree.nodeType === 11;
  const isEmpty = oldTree === empty;

  // Reuse these maps, it's more efficient to clear them than to re-create.
  const keysLookup = { old: new Map(), new: new Map() };

  if (process.env.NODE_ENV !== 'production') {
    if (newTree === empty) {
      throw new Error('Missing new Virtual Tree to sync changes from');
    }

    if (!isEmpty && oldNodeName !== newNodeName && !isFragment) {
      throw new Error(
        `Sync failure, cannot compare ${newNodeName} with ${oldNodeName}`
      );
    }
  }

  // Reduce duplicate logic by condensing old and new operations in a loop.
  for (let i = 0; i < keyNames.length; i++) {
    const keyName = keyNames[i];
    const map = keysLookup[keyName];
    const vTree = arguments[i];
    const nodes = vTree && vTree.childNodes;

    if (nodes && nodes.length) {
      for (let i = 0; i < nodes.length; i++) {
        const vTree = nodes[i];

        if (vTree.key) {
          map.set(vTree.key, vTree);
        }
        else if (map.size && vTree.nodeType === 1) {
          if (process.env.NODE_ENV !== 'production') {
            throw new Error(
              `Missing \`key\` all siblings must supply this attribute.

Virtual Element: ${JSON.stringify(vTree, null, 2)}`
            );
          }
        }
      }
    }
  }

  // Invoke any middleware hooks, allow the middleware to replace the
  // `newTree`. Pass along the `keysLookup` object so that middleware can make
  // smart decisions when dealing with keys.
  SyncTreeHookCache.forEach((fn, retVal) => {
    if (retVal = fn(oldTree, newTree, null)) {
      newTree = retVal;

      // Find attributes.
      syncTree(null, retVal, patches);
    }

    for (let i = 0; i < newTree.childNodes.length; i++) {
      const oldChildNode = isEmpty ? empty : oldTree.childNodes[i];
      const newChildNode = newTree.childNodes[i];

      if (retVal = fn(oldChildNode, newChildNode, keysLookup)) {
        newTree.childNodes[i] = retVal;
      }
    }
  });

  // Create new arrays for patches or use existing from a recursive call.
  patches = patches || {
    SET_ATTRIBUTE: [],
    REMOVE_ATTRIBUTE: [],
    TREE_OPS: [],
    NODE_VALUE: [],
  };

  const { SET_ATTRIBUTE, REMOVE_ATTRIBUTE, TREE_OPS, NODE_VALUE } = patches;

  // Build up a patchset object to use for tree operations.
  const patchset = {
    INSERT_BEFORE: [],
    REMOVE_CHILD: [],
    REPLACE_CHILD: [],
  };

  // USED: INSERT_BEFORE: 3x, REMOVE_CHILD: 2x, REPLACE_CHILD: 3x.
  const { INSERT_BEFORE, REMOVE_CHILD, REPLACE_CHILD } = patchset;
  const isElement = newTree.nodeType === 1;

  // Text nodes are low level and frequently change, so this path is accounted
  // for first.
  if (newTree.nodeName === '#text') {
    // If there was no previous element to compare to, simply set the value
    // on the new node.
    if (oldTree.nodeName !== '#text') {
      NODE_VALUE.push(newTree, newTree.nodeValue, null);
    }
    // If both VTrees are text nodes and the values are different, change the
    // `Element#nodeValue`.
    else if (!isEmpty && oldTree.nodeValue !== newTree.nodeValue) {
      NODE_VALUE.push(oldTree, newTree.nodeValue, oldTree.nodeValue);
      oldTree.nodeValue = newTree.nodeValue;
    }

    return patches;
  }

  // Seek out attribute changes first, but only from element Nodes.
  if (isElement) {
    const oldAttributes = isEmpty ? empty : oldTree.attributes;
    const newAttributes = newTree.attributes;

    // Search for sets and changes.
    for (let key in newAttributes) {
      const value = newAttributes[key];

      if (key in oldAttributes && oldAttributes[key] === newAttributes[key]) {
        continue;
      }

      if (!isEmpty) {
        oldAttributes[key] = value;
      }

      SET_ATTRIBUTE.push(isEmpty ? newTree : oldTree, key, value);
    }

    // Search for removals.
    if (!isEmpty) {
      for (let key in oldAttributes) {
        if (key in newAttributes) { continue; }
        REMOVE_ATTRIBUTE.push(oldTree, key);
        delete oldAttributes[key];
      }
    }
  }

  // If we somehow end up comparing two totally different kinds of elements,
  // we'll want to raise an error to let the user know something is wrong.
  if (process.env.NODE_ENV !== 'production') {
    if (!isEmpty && oldNodeName !== newNodeName && !isFragment) {
      throw new Error(
        `Sync failure, cannot compare ${newNodeName} with ${oldNodeName}`
      );
    }
  }

  if (isEmpty) {
    return patches;
  }

  const oldChildNodes = oldTree.childNodes;
  const newChildNodes = newTree.childNodes;

  // If we are working with keys, we can follow an optimized path.
  if (keysLookup.old.size || keysLookup.new.size) {
    const values = keysLookup.old.values();

    // Do a single pass over the new child nodes.
    for (let i = 0; i < newChildNodes.length; i++) {
      const oldChildNode = oldChildNodes[i];
      const newChildNode = newChildNodes[i];
      const newKey = newChildNode.key;

      // If there is no old element to compare to, this is a simple addition.
      if (!oldChildNode) {
        INSERT_BEFORE.push(oldTree, newChildNode, null);
        oldChildNodes.push(newChildNode);
        syncTree(null, newChildNode, patches);
        continue;
      }

      const oldKey = oldChildNode.key;
      const oldInNew = keysLookup.new.has(oldKey);
      const newInOld = keysLookup.old.has(newKey);

      // Remove the old Node and insert the new node (aka replace).
      if (!oldInNew && !newInOld) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldChildNodes.splice(oldChildNodes.indexOf(oldChildNode), 1, newChildNode);
        syncTree(null, newChildNode, patches);
        continue;
      }
      // Remove the old node instead of replacing.
      else if (!oldInNew) {
        REMOVE_CHILD.push(oldChildNode);
        oldChildNodes.splice(oldChildNodes.indexOf(oldChildNode), 1);
        i = i - 1;
        continue;
      }

      // If there is a key set for this new element, use that to figure out
      // which element to use.
      if (newKey !== oldKey) {
        let optimalNewNode = newChildNode;

        // Prefer existing to new and remove from old position.
        if (newKey && newInOld) {
          optimalNewNode = keysLookup.old.get(newKey);
          oldChildNodes.splice(oldChildNodes.indexOf(optimalNewNode), 1);
        }
        else if (newKey) {
          optimalNewNode = newChildNode;

          // Find attribute changes for this Node.
          syncTree(null, newChildNode, patches);
        }

        INSERT_BEFORE.push(oldTree, optimalNewNode, oldChildNode);
        oldChildNodes.splice(i, 0, optimalNewNode);
        continue;
      }

      // If the element we're replacing is totally different from the previous
      // replace the entire element, don't bother investigating children.
      if (oldChildNode.nodeName !== newChildNode.nodeName) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldTree.childNodes[i] = newChildNode;
        syncTree(null, newChildNode, patches);
        continue;
      }

      syncTree(oldChildNode, newChildNode, patches);
    }
  }

  // No keys used on this level, so we will do easier transformations.
  else {
    // Do a single pass over the new child nodes.
    for (let i = 0; i < newChildNodes.length; i++) {
      const oldChildNode = oldChildNodes && oldChildNodes[i];
      const newChildNode = newChildNodes[i];

      // If there is no old element to compare to, this is a simple addition.
      if (!oldChildNode) {
        INSERT_BEFORE.push(oldTree, newChildNode, null);

        if (oldChildNodes) {
          oldChildNodes.push(newChildNode);
        }

        syncTree(null, newChildNode, patches);
        continue;
      }

      // If the element we're replacing is totally different from the previous
      // replace the entire element, don't bother investigating children.
      if (oldChildNode.nodeName !== newChildNode.nodeName) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldTree.childNodes[i] = newChildNode;
        syncTree(null, newChildNode, patches);
        continue;
      }

      syncTree(oldChildNode, newChildNode, patches);
    }
  }

  // If there was no `oldTree` provided, we have sync'd all the attributes and
  // the node value of the `newTree` so we can early abort and not worry about
  // tree operations.
  if (isEmpty) {
    return patches;
  }

  // We've reconciled new changes, so we can remove any old nodes and adjust
  // lengths to be equal.
  if (oldChildNodes.length !== newChildNodes.length) {
    for (let i = newChildNodes.length; i < oldChildNodes.length; i++) {
      REMOVE_CHILD.push(oldChildNodes[i]);
    }

    oldChildNodes.length = newChildNodes.length;
  }

  // We want to look if anything has changed, if nothing has we won't add it to
  // the patchset.
  if (INSERT_BEFORE.length || REMOVE_CHILD.length || REPLACE_CHILD.length) {
    // Null out the empty arrays.
    if (!INSERT_BEFORE.length) { patchset.INSERT_BEFORE = null; }
    if (!REMOVE_CHILD.length) { patchset.REMOVE_CHILD = null; }
    if (!REPLACE_CHILD.length) { patchset.REPLACE_CHILD = null; }

    TREE_OPS.push(patchset);
  }

  return patches;
}
<commit_msg>Check if retVal has changed before processsing<commit_after>import { MiddlewareCache } from '../util/caches';
import process from '../util/process';

const { SyncTreeHookCache } = MiddlewareCache;
const { assign, keys } = Object;
const empty = {};
const keyNames = ['old', 'new'];

// Compares how the new state should look to the old state and mutates it,
// while recording the changes along the way.
export default function syncTree(oldTree, newTree, patches) {
  if (!oldTree) oldTree = empty;
  if (!newTree) newTree = empty;

  const oldNodeName = oldTree.nodeName;
  const newNodeName = newTree.nodeName;
  const isFragment = newTree.nodeType === 11;
  const isEmpty = oldTree === empty;

  // Reuse these maps, it's more efficient to clear them than to re-create.
  const keysLookup = { old: new Map(), new: new Map() };

  if (process.env.NODE_ENV !== 'production') {
    if (newTree === empty) {
      throw new Error('Missing new Virtual Tree to sync changes from');
    }

    if (!isEmpty && oldNodeName !== newNodeName && !isFragment) {
      throw new Error(
        `Sync failure, cannot compare ${newNodeName} with ${oldNodeName}`
      );
    }
  }

  // Reduce duplicate logic by condensing old and new operations in a loop.
  for (let i = 0; i < keyNames.length; i++) {
    const keyName = keyNames[i];
    const map = keysLookup[keyName];
    const vTree = arguments[i];
    const nodes = vTree && vTree.childNodes;

    if (nodes && nodes.length) {
      for (let i = 0; i < nodes.length; i++) {
        const vTree = nodes[i];

        if (vTree.key) {
          map.set(vTree.key, vTree);
        }
        else if (map.size && vTree.nodeType === 1) {
          if (process.env.NODE_ENV !== 'production') {
            throw new Error(
              `Missing \`key\` all siblings must supply this attribute.

Virtual Element: ${JSON.stringify(vTree, null, 2)}`
            );
          }
        }
      }
    }
  }

  // Invoke any middleware hooks, allow the middleware to replace the
  // `newTree`. Pass along the `keysLookup` object so that middleware can make
  // smart decisions when dealing with keys.
  SyncTreeHookCache.forEach((fn, retVal) => {
    if ((retVal = fn(oldTree, newTree, null)) && retVal !== newTree) {
      newTree = retVal;

      // Find attributes.
      syncTree(null, retVal, patches);
    }

    for (let i = 0; i < newTree.childNodes.length; i++) {
      const oldChildNode = isEmpty ? empty : oldTree.childNodes[i];
      const newChildNode = newTree.childNodes[i];

      if (retVal = fn(oldChildNode, newChildNode, keysLookup)) {
        newTree.childNodes[i] = retVal;
      }
    }
  });

  // Create new arrays for patches or use existing from a recursive call.
  patches = patches || {
    SET_ATTRIBUTE: [],
    REMOVE_ATTRIBUTE: [],
    TREE_OPS: [],
    NODE_VALUE: [],
  };

  const { SET_ATTRIBUTE, REMOVE_ATTRIBUTE, TREE_OPS, NODE_VALUE } = patches;

  // Build up a patchset object to use for tree operations.
  const patchset = {
    INSERT_BEFORE: [],
    REMOVE_CHILD: [],
    REPLACE_CHILD: [],
  };

  // USED: INSERT_BEFORE: 3x, REMOVE_CHILD: 2x, REPLACE_CHILD: 3x.
  const { INSERT_BEFORE, REMOVE_CHILD, REPLACE_CHILD } = patchset;
  const isElement = newTree.nodeType === 1;

  // Text nodes are low level and frequently change, so this path is accounted
  // for first.
  if (newTree.nodeName === '#text') {
    // If there was no previous element to compare to, simply set the value
    // on the new node.
    if (oldTree.nodeName !== '#text') {
      NODE_VALUE.push(newTree, newTree.nodeValue, null);
    }
    // If both VTrees are text nodes and the values are different, change the
    // `Element#nodeValue`.
    else if (!isEmpty && oldTree.nodeValue !== newTree.nodeValue) {
      NODE_VALUE.push(oldTree, newTree.nodeValue, oldTree.nodeValue);
      oldTree.nodeValue = newTree.nodeValue;
    }

    return patches;
  }

  // Seek out attribute changes first, but only from element Nodes.
  if (isElement) {
    const oldAttributes = isEmpty ? empty : oldTree.attributes;
    const newAttributes = newTree.attributes;

    // Search for sets and changes.
    for (let key in newAttributes) {
      const value = newAttributes[key];

      if (key in oldAttributes && oldAttributes[key] === newAttributes[key]) {
        continue;
      }

      if (!isEmpty) {
        oldAttributes[key] = value;
      }

      SET_ATTRIBUTE.push(isEmpty ? newTree : oldTree, key, value);
    }

    // Search for removals.
    if (!isEmpty) {
      for (let key in oldAttributes) {
        if (key in newAttributes) { continue; }
        REMOVE_ATTRIBUTE.push(oldTree, key);
        delete oldAttributes[key];
      }
    }
  }

  // If we somehow end up comparing two totally different kinds of elements,
  // we'll want to raise an error to let the user know something is wrong.
  if (process.env.NODE_ENV !== 'production') {
    if (!isEmpty && oldNodeName !== newNodeName && !isFragment) {
      throw new Error(
        `Sync failure, cannot compare ${newNodeName} with ${oldNodeName}`
      );
    }
  }

  if (isEmpty) {
    return patches;
  }

  const oldChildNodes = oldTree.childNodes;
  const newChildNodes = newTree.childNodes;

  // If we are working with keys, we can follow an optimized path.
  if (keysLookup.old.size || keysLookup.new.size) {
    const values = keysLookup.old.values();

    // Do a single pass over the new child nodes.
    for (let i = 0; i < newChildNodes.length; i++) {
      const oldChildNode = oldChildNodes[i];
      const newChildNode = newChildNodes[i];
      const newKey = newChildNode.key;

      // If there is no old element to compare to, this is a simple addition.
      if (!oldChildNode) {
        INSERT_BEFORE.push(oldTree, newChildNode, null);
        oldChildNodes.push(newChildNode);
        syncTree(null, newChildNode, patches);
        continue;
      }

      const oldKey = oldChildNode.key;
      const oldInNew = keysLookup.new.has(oldKey);
      const newInOld = keysLookup.old.has(newKey);

      // Remove the old Node and insert the new node (aka replace).
      if (!oldInNew && !newInOld) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldChildNodes.splice(oldChildNodes.indexOf(oldChildNode), 1, newChildNode);
        syncTree(null, newChildNode, patches);
        continue;
      }
      // Remove the old node instead of replacing.
      else if (!oldInNew) {
        REMOVE_CHILD.push(oldChildNode);
        oldChildNodes.splice(oldChildNodes.indexOf(oldChildNode), 1);
        i = i - 1;
        continue;
      }

      // If there is a key set for this new element, use that to figure out
      // which element to use.
      if (newKey !== oldKey) {
        let optimalNewNode = newChildNode;

        // Prefer existing to new and remove from old position.
        if (newKey && newInOld) {
          optimalNewNode = keysLookup.old.get(newKey);
          oldChildNodes.splice(oldChildNodes.indexOf(optimalNewNode), 1);
        }
        else if (newKey) {
          optimalNewNode = newChildNode;

          // Find attribute changes for this Node.
          syncTree(null, newChildNode, patches);
        }

        INSERT_BEFORE.push(oldTree, optimalNewNode, oldChildNode);
        oldChildNodes.splice(i, 0, optimalNewNode);
        continue;
      }

      // If the element we're replacing is totally different from the previous
      // replace the entire element, don't bother investigating children.
      if (oldChildNode.nodeName !== newChildNode.nodeName) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldTree.childNodes[i] = newChildNode;
        syncTree(null, newChildNode, patches);
        continue;
      }

      syncTree(oldChildNode, newChildNode, patches);
    }
  }

  // No keys used on this level, so we will do easier transformations.
  else {
    // Do a single pass over the new child nodes.
    for (let i = 0; i < newChildNodes.length; i++) {
      const oldChildNode = oldChildNodes && oldChildNodes[i];
      const newChildNode = newChildNodes[i];

      // If there is no old element to compare to, this is a simple addition.
      if (!oldChildNode) {
        INSERT_BEFORE.push(oldTree, newChildNode, null);

        if (oldChildNodes) {
          oldChildNodes.push(newChildNode);
        }

        syncTree(null, newChildNode, patches);
        continue;
      }

      // If the element we're replacing is totally different from the previous
      // replace the entire element, don't bother investigating children.
      if (oldChildNode.nodeName !== newChildNode.nodeName) {
        REPLACE_CHILD.push(newChildNode, oldChildNode);
        oldTree.childNodes[i] = newChildNode;
        syncTree(null, newChildNode, patches);
        continue;
      }

      syncTree(oldChildNode, newChildNode, patches);
    }
  }

  // If there was no `oldTree` provided, we have sync'd all the attributes and
  // the node value of the `newTree` so we can early abort and not worry about
  // tree operations.
  if (isEmpty) {
    return patches;
  }

  // We've reconciled new changes, so we can remove any old nodes and adjust
  // lengths to be equal.
  if (oldChildNodes.length !== newChildNodes.length) {
    for (let i = newChildNodes.length; i < oldChildNodes.length; i++) {
      REMOVE_CHILD.push(oldChildNodes[i]);
    }

    oldChildNodes.length = newChildNodes.length;
  }

  // We want to look if anything has changed, if nothing has we won't add it to
  // the patchset.
  if (INSERT_BEFORE.length || REMOVE_CHILD.length || REPLACE_CHILD.length) {
    // Null out the empty arrays.
    if (!INSERT_BEFORE.length) { patchset.INSERT_BEFORE = null; }
    if (!REMOVE_CHILD.length) { patchset.REMOVE_CHILD = null; }
    if (!REPLACE_CHILD.length) { patchset.REPLACE_CHILD = null; }

    TREE_OPS.push(patchset);
  }

  return patches;
}
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import colors from 'fyndiq-styles-colors'

const Truck = ({ className, color }) => (
  <svg className={className} viewBox="0 0 19 14">
    <path
      stroke={color}
      fill="none"
      d="M.5 11.5h10V.5H.5z"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path
      stroke={color}
      fill="none"
      d="M11 2.5h3.8c.2 0 .4.12.5.3l2.05 3.66c.1.18.15.4.15.6v3.85c0 .34-.26.6-.6.6H5.5"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path fill={color} d="M12.5 4.03V7h3.25l-1.47-2.97z" />
    <path
      fill="#FFF"
      stroke={color}
      d="M16 11.5a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm-10 0a2 2 0 1 1-4 0 2 2 0 0 1 4 0z"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
)

Truck.propTypes = {
  className: PropTypes.string,
  color: PropTypes.string,
}

Truck.defaultProps = {
  className: '',
  color: colors.black,
}

export default Truck
<commit_msg>:eyes: Make Truck CSS friendly<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import colors from 'fyndiq-styles-colors'

const Truck = ({ className, color }) => (
  <svg className={className} viewBox="0 0 19 14">
    <path
      stroke={color}
      fill="none"
      d="m 6,11.5 h 4.5 v -11 h -10 v 11 H 2"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path
      stroke={color}
      fill="none"
      d="m 11,2.5 h 3.8 c 0.2,0 0.4,0.12 0.5,0.3 l 2.05,3.66 c 0.1,0.18 0.15,0.4 0.15,0.6 v 3.85 c 0,0.34 -0.26,0.6 -0.6,0.6 h -0.900025 m -3.99995,0 L 10.5,11.5"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
    <path fill={color} stroke="none" d="M12.5 4.03V7h3.25l-1.47-2.97z" />
    <path
      fill="none"
      stroke={color}
      d="M16 11.5a2 2 0 1 1-4 0 2 2 0 0 1 4 0zm-10 0a2 2 0 1 1-4 0 2 2 0 0 1 4 0z"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
)

Truck.propTypes = {
  className: PropTypes.string,
  color: PropTypes.string,
}

Truck.defaultProps = {
  className: '',
  color: colors.black,
}

export default Truck
<|endoftext|>