<commit_before>define(module, function(exports, require) {

  var http = require('http');
  var fs = require('fs');
  var domain = require('domain');
  var useragent = require('useragent');
  var mustache = require('mustache');
  var mime = require('mime');
  var qp = require('qp-utility');
  var fss = require('qp-library/fss');
  var url = require('qp-library/url');
  var log = require('qp-library/log');
  var connections = require('qp-library/http_server/connections');

  qp.make(exports, {

    ns: 'qp-library/http_server',

    title: '',
    name: '',
    port: 80,
    www: '',
    favicon: 'none',
    headers: {},
    cors: {
      preflight: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': 'true',
        'Access-Control-Allow-Methods': 'GET,POST',
        'Access-Control-Allow-Headers': 'SessionId, Content-Type, Accept, X-Requested-With'
      },
      request: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': 'true'
      }
    },
    templates: {},

    http_server: null,
    is_closing: false,
    enable_domain: true,
    enable_session_cookie: false,
    session_cookie_secure: false,
    session_cookie_domain: false,
    session_cookie_path: false,
    session_cookie_expires: false,

    mime_types: {
      text: mime.getType('txt'),
      html: mime.getType('html'),
      css: mime.getType('css'),
      js: mime.getType('js'),
      json: mime.getType('json'),
      ico: mime.getType('ico')
    },

    handlers: {

      template: function(send, id, data, headers) {
        var template = this.templates[id];
        if (template) {
          send.data(mustache.render(fss.read(template.path), data), this.mime(template.type), headers);
        }
      },

      text: function(send, msg, headers) {
        send.data(msg, this.mime('text'), headers);
      },

      html: function(send, html, headers) {
        send.data(html, this.mime('html'), headers);
      },

      data: function(send, data, mime, headers) {
        send(200, { mime: mime, size: Buffer.byteLength(data) }, data, headers);
      },

      file: function(send, file, headers) {
        if (file.is_file && file.exists) {
          send(200, file, fs.createReadStream(file.fullname), headers);
        } else {
          send(404);
        }
      },

      json: function(send, o, headers) {
        var data = JSON.stringify(o, null, 2);
        send(200, { mime: this.mime('json'), size: Buffer.byteLength(data) }, data, headers);
      },

      redirect: function(send, location) {
        send(302, null, null, { 'Location': location });
      }

    },

    start: function() {
      if (!this.http_server) this.create_server();

      process.on('SIGTERM', function() {
        log(log.red(' * SIGTERM * '));
        this.stop(() => {
          log(log.blue(' * SIGTERM * '));
          process.exit(0);
        });
      }.bind(this));

      connections.monitor(this.http_server);
      this.http_server.listen(this.port);
      this.on_start();
    },

    stop: function(done) {
      connections.close_all(true);
      this.http_server.close(() => {
        this.on_stop(done);
      });
    },

    add_handler: function(key, handler) {
      this.handlers[key] = handler.bind(this);
    },

    create_server: function() {
      if (this.enable_domain) {
        this.http_server = http.createServer(function(req, res) {
          var d = domain.create();
          d.on('error', this.on_error.bind(this, req, res));
          d.add(req);
          d.add(res);
          d.run(this.run_request.bind(this, req, res));
        }.bind(this));
      } else {
        process.on('uncaughtException', this.on_error.bind(this, undefined, undefined));
        this.http_server = http.createServer(function(req, res) {
          this.run_request.call(this, req, res);
        }.bind(this));
      }
    },

    mime: function(type) {
      return this.mime_types[type] || (this.mime_types[type] = mime.getType(type));
    },

    read_data: function(req, done) {
      var post_data = '';
      req.on('data', function(data) { post_data += data; });
      req.on('end', function() { done.call(this, null, post_data); }.bind(this));
    },

    read_json: function(req, done) {
      var json = '';
      req.on('data', function(data) { json += data; });
      req.on('end', function() { done.call(this, null, JSON.parse(json)); }.bind(this));
    },

    read_agent: function(req) {
      req.ua = useragent.parse(req.headers['user-agent']);
    },

    set_session_cookie: function(res, sid) {
      if (this.enable_session_cookie) {
        var cookie = ['Session-Id=' + sid];
        if (this.session_cookie_expires) {
          var expires_dt = new Date();
          expires_dt.setTime(expires_dt.getTime() + this.session_cookie_expires);
          cookie.push('Expires=' + expires_dt.toUTCString());
        }
        if (this.session_cookie_path) cookie.push('Path=' + this.session_cookie_path);
        if (this.session_cookie_domain) cookie.push('Domain=' + this.session_cookie_domain);
        cookie.push('HttpOnly');
        cookie.push('SameSite=Strict');
        res.setHeader('Set-Cookie', cookie.join('; '));
      }
    },

    ip_address: function(req) {
      var ip_address;
      var forwarded = req.headers['x-forwarded-for'];
      if (forwarded) {
        ip_address = forwarded.split(',')[0];
      }
      return ip_address || req.connection.remoteAddress;
    },

    user_agent: function(req) { return req.headers['user-agent']; },

    session_id: function(o) {
      if (qp.is(o, 'url')) {
        return o.get_params().sid || '';
      } else if (o.headers['session-id']) {
        return o.headers['session-id'] || '';
      } else if (this.enable_session_cookie) {
        var cookie = o.headers['cookie'] || '';
        var results = cookie.match('Session-Id' + '=(.*?)(;|$)');
        return results ? results[1] : '';
      } else {
        return '';
      }
    },

    status: function(code, include_code) {
      var description = http.STATUS_CODES[code] || '';
      return (include_code ? code : '') + (description ? ' - ' + description : '');
    },

    run_request: function(req, res) {
      var req_url = url.create({ url: req.url });
      var send = this.send.bind(this, req_url, req, res);
      qp.each(this.handlers, function(handler, key) {
        send[key] = handler.bind(this, send);
      }, this);
      if (req.method === 'GET' && req_url.equals('/favicon.ico') && this.favicon === 'none') {
        send(200, { mime: this.mime('ico'), size: 0 }, '');
      } else {
        this.on_request(req.method, req_url, send, req, res);
      }
    },

    send: function(req_url, req, res, status, stat, data, headers) {
      if (!res.done) {
        res.done = true;
        this.log_request(status, req.method, req_url.fullname);
        if (arguments.length === 3) {
          res.writeHead(204, this.headers);
          res.end();
        } else if (arguments.length === 4) {
          res.writeHead(status, this.create_headers({ mime: this.mime('text'), size: 0 }));
          res.end();
        } else {
          res.writeHead(status, this.create_headers(stat, headers));
          if (qp.is(data, 'string')) {
            res.write(data);
            res.end();
          } else if (qp.is(data, 'readstream')) {
            data.pipe(res);
          } else {
            res.end();
          }
        }
      }
    },

    log_request: function(status, method, url) {
      var status_color = status < 200 ? 'magenta' : status < 300 ? 'green' : status < 400 ? 'yellow' : 'white_red';
      var method_color = status >= 400 ? 'white_red' : 'blue';
      var url_color = status >= 400 ? 'white_red' : 'white';
      log(log[status_color](status), log[method_color](qp.rpad(method, 4)), log[url_color](url));
    },

    create_headers: function(stat, headers) {
      if (!stat) { return qp.assign({}, this.headers, headers); }
      stat.mtime = stat.mtime || qp.now();
      return qp.assign({
        'ETag': JSON.stringify([stat.ino || 'x', stat.size, stat.mtime.getTime()].join('-')),
        'Last-Modified': stat.mtime.toUTCString(),
        'Content-Type': stat.mime,
        'Content-Length': stat.size
      }, this.headers, headers);
    },

    on_request: function(method, url, send) { send(204); },

    on_start: function() { },

    on_stop: function(done) { done(); },

    on_error: function(http_request, http_response, error) {
      try {
        this.http_server.close();
        log('Exception:', http_request ? http_request.url : ' ...');
        log(error.stack);
        if (http_response) {
          http_response.statusCode = 500;
          http_response.setHeader('content-type', 'text/plain');
          http_response.end(error.stack);
        }
      } catch (error1) {
        log(error1.stack);
      } finally {
        log('Terminated');
        process.exit(1);
      }
    }

  });

});
<commit_msg>http_server; shutdown<commit_after>define(module, function(exports, require) {

  var http = require('http');
  var fs = require('fs');
  var domain = require('domain');
  var useragent = require('useragent');
  var mustache = require('mustache');
  var mime = require('mime');
  var qp = require('qp-utility');
  var fss = require('qp-library/fss');
  var url = require('qp-library/url');
  var log = require('qp-library/log');

  qp.make(exports, {

    ns: 'qp-library/http_server',

    title: '',
    name: '',
    port: 80,
    www: '',
    favicon: 'none',
    headers: {},
    cors: {
      preflight: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': 'true',
        'Access-Control-Allow-Methods': 'GET,POST',
        'Access-Control-Allow-Headers': 'SessionId, Content-Type, Accept, X-Requested-With'
      },
      request: {
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Credentials': 'true'
      }
    },
    templates: {},

    http_server: null,
    is_closing: false,
    enable_domain: true,
    enable_session_cookie: false,
    session_cookie_secure: false,
    session_cookie_domain: false,
    session_cookie_path: false,
    session_cookie_expires: false,

    mime_types: {
      text: mime.getType('txt'),
      html: mime.getType('html'),
      css: mime.getType('css'),
      js: mime.getType('js'),
      json: mime.getType('json'),
      ico: mime.getType('ico')
    },

    handlers: {

      template: function(send, id, data, headers) {
        var template = this.templates[id];
        if (template) {
          send.data(mustache.render(fss.read(template.path), data), this.mime(template.type), headers);
        }
      },

      text: function(send, msg, headers) {
        send.data(msg, this.mime('text'), headers);
      },

      html: function(send, html, headers) {
        send.data(html, this.mime('html'), headers);
      },

      data: function(send, data, mime, headers) {
        send(200, { mime: mime, size: Buffer.byteLength(data) }, data, headers);
      },

      file: function(send, file, headers) {
        if (file.is_file && file.exists) {
          send(200, file, fs.createReadStream(file.fullname), headers);
        } else {
          send(404);
        }
      },

      json: function(send, o, headers) {
        var data = JSON.stringify(o, null, 2);
        send(200, { mime: this.mime('json'), size: Buffer.byteLength(data) }, data, headers);
      },

      redirect: function(send, location) {
        send(302, null, null, { 'Location': location });
      }

    },

    start: function() {
      if (!this.http_server) this.create_server();

      process.on('SIGTERM', function() {
        this.stop(() => {
          log(log.red(' * Process Terminated * '));
          process.exit(0);
        });
      }.bind(this));

      this.http_server.listen(this.port);
      this.on_start();
    },

    stop: function(done) {
      qp.parallel([
        (data, done) => this.http_server.close(done),
        (data, done) => this.on_stop(done)
      ], done);
    },

    add_handler: function(key, handler) {
      this.handlers[key] = handler.bind(this);
    },

    create_server: function() {
      if (this.enable_domain) {
        this.http_server = http.createServer(function(req, res) {
          var d = domain.create();
          d.on('error', this.on_error.bind(this, req, res));
          d.add(req);
          d.add(res);
          d.run(this.run_request.bind(this, req, res));
        }.bind(this));
      } else {
        process.on('uncaughtException', this.on_error.bind(this, undefined, undefined));
        this.http_server = http.createServer(function(req, res) {
          this.run_request.call(this, req, res);
        }.bind(this));
      }
    },

    mime: function(type) {
      return this.mime_types[type] || (this.mime_types[type] = mime.getType(type));
    },

    read_data: function(req, done) {
      var post_data = '';
      req.on('data', function(data) { post_data += data; });
      req.on('end', function() { done.call(this, null, post_data); }.bind(this));
    },

    read_json: function(req, done) {
      var json = '';
      req.on('data', function(data) { json += data; });
      req.on('end', function() { done.call(this, null, JSON.parse(json)); }.bind(this));
    },

    read_agent: function(req) {
      req.ua = useragent.parse(req.headers['user-agent']);
    },

    set_session_cookie: function(res, sid) {
      if (this.enable_session_cookie) {
        var cookie = ['Session-Id=' + sid];
        if (this.session_cookie_expires) {
          var expires_dt = new Date();
          expires_dt.setTime(expires_dt.getTime() + this.session_cookie_expires);
          cookie.push('Expires=' + expires_dt.toUTCString());
        }
        if (this.session_cookie_path) cookie.push('Path=' + this.session_cookie_path);
        if (this.session_cookie_domain) cookie.push('Domain=' + this.session_cookie_domain);
        cookie.push('HttpOnly');
        cookie.push('SameSite=Strict');
        res.setHeader('Set-Cookie', cookie.join('; '));
      }
    },

    ip_address: function(req) {
      var ip_address;
      var forwarded = req.headers['x-forwarded-for'];
      if (forwarded) {
        ip_address = forwarded.split(',')[0];
      }
      return ip_address || req.connection.remoteAddress;
    },

    user_agent: function(req) { return req.headers['user-agent']; },

    session_id: function(o) {
      if (qp.is(o, 'url')) {
        return o.get_params().sid || '';
      } else if (o.headers['session-id']) {
        return o.headers['session-id'] || '';
      } else if (this.enable_session_cookie) {
        var cookie = o.headers['cookie'] || '';
        var results = cookie.match('Session-Id' + '=(.*?)(;|$)');
        return results ? results[1] : '';
      } else {
        return '';
      }
    },

    status: function(code, include_code) {
      var description = http.STATUS_CODES[code] || '';
      return (include_code ? code : '') + (description ? ' - ' + description : '');
    },

    run_request: function(req, res) {
      var req_url = url.create({ url: req.url });
      var send = this.send.bind(this, req_url, req, res);
      qp.each(this.handlers, function(handler, key) {
        send[key] = handler.bind(this, send);
      }, this);
      if (req.method === 'GET' && req_url.equals('/favicon.ico') && this.favicon === 'none') {
        send(200, { mime: this.mime('ico'), size: 0 }, '');
      } else {
        this.on_request(req.method, req_url, send, req, res);
      }
    },

    send: function(req_url, req, res, status, stat, data, headers) {
      if (!res.done) {
        res.done = true;
        this.log_request(status, req.method, req_url.fullname);
        if (arguments.length === 3) {
          res.writeHead(204, this.headers);
          res.end();
        } else if (arguments.length === 4) {
          res.writeHead(status, this.create_headers({ mime: this.mime('text'), size: 0 }));
          res.end();
        } else {
          res.writeHead(status, this.create_headers(stat, headers));
          if (qp.is(data, 'string')) {
            res.write(data);
            res.end();
          } else if (qp.is(data, 'readstream')) {
            data.pipe(res);
          } else {
            res.end();
          }
        }
      }
    },

    log_request: function(status, method, url) {
      var status_color = status < 200 ? 'magenta' : status < 300 ? 'green' : status < 400 ? 'yellow' : 'white_red';
      var method_color = status >= 400 ? 'white_red' : 'blue';
      var url_color = status >= 400 ? 'white_red' : 'white';
      log(log[status_color](status), log[method_color](qp.rpad(method, 4)), log[url_color](url));
    },

    create_headers: function(stat, headers) {
      if (!stat) { return qp.assign({}, this.headers, headers); }
      stat.mtime = stat.mtime || qp.now();
      return qp.assign({
        'ETag': JSON.stringify([stat.ino || 'x', stat.size, stat.mtime.getTime()].join('-')),
        'Last-Modified': stat.mtime.toUTCString(),
        'Content-Type': stat.mime,
        'Content-Length': stat.size
      }, this.headers, headers);
    },

    on_request: function(method, url, send) { send(204); },

    on_start: function() { },

    on_stop: function(done) { done(); },

    on_error: function(http_request, http_response, error) {
      try {
        this.http_server.close();
        log('Exception:', http_request ? http_request.url : ' ...');
        log(error.stack);
        if (http_response) {
          http_response.statusCode = 500;
          http_response.setHeader('content-type', 'text/plain');
          http_response.end(error.stack);
        }
      } catch (error1) {
        log(error1.stack);
      } finally {
        log('Terminated');
        process.exit(1);
      }
    }

  });

});
<|endoftext|>


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

function getDisplayName (component) {
  return component.displayName || component.name || 'Component'
}

export default function registerReducers (reducers) {
  return DecoratedComponent => (
    class RegisterReducersDecorator extends Component {
      static displayName = `Reducers(${getDisplayName(DecoratedComponent)})`
      static DecoratedComponent = DecoratedComponent;

      componentWillMount () {
        const { storesRegistry } = this.props.route.userContext
        storesRegistry.addReducers(reducers)
      }

      render () {
        return <DecoratedComponent {...this.props} />
      }
    }
  )
}
<commit_msg>add getDisplayName source comment<commit_after>import React, { Component } from 'react'

// duplicated from
// github.com/gaearon/react-redux/blob/master/src/utils/getDisplayName.js
function getDisplayName (component) {
  return component.displayName || component.name || 'Component'
}

export default function registerReducers (reducers) {
  return DecoratedComponent => (
    class RegisterReducersDecorator extends Component {
      static displayName = `Reducers(${getDisplayName(DecoratedComponent)})`
      static DecoratedComponent = DecoratedComponent;

      componentWillMount () {
        const { storesRegistry } = this.props.route.userContext
        storesRegistry.addReducers(reducers)
      }

      render () {
        return <DecoratedComponent {...this.props} />
      }
    }
  )
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Link } from 'react-router';
import './BookDetails.scss';

export default class BookDetails extends Component {
  render() {
    const book = this.props.book;
    const bookSummary = {
      __html: book.summary || 'No Description Available.'
    };

    return (

          <Link to="/">

          </Link>

{book.title}

by {book.author.name || book.author}

          {
            book.category.length > 0 &&

              {book.category.join(', ')}

          }

            <Link className="button" to={`/read/${book.id}`}>Start Reading</Link>
            Add to My Books

    );
  }
}
<commit_msg>app: category -> subjects<commit_after>import React, { Component } from 'react';
import { Link } from 'react-router';
import './BookDetails.scss';

export default class BookDetails extends Component {
  render() {
    const book = this.props.book;
    const bookSummary = {
      __html: book.summary || 'No Description Available.'
    };

    return (

          <Link to="/">

          </Link>

{book.title}

by {book.author.name || book.author}

          {
            book.subjects && book.subjects.length &&

              {book.subjects.join(', ')}

          }

            <Link className="button" to={`/read/${book.id}`}>Start Reading</Link>
            Add to My Books

    );
  }
}
<|endoftext|>


<commit_before>import React from 'react';
import {
  View,
  ScrollView,
  Image,
  TouchableHighlight,
  Text
} from 'react-native';
import styles from './styles';

const nextImage = require('assets/next.png');

function List(props) {
  return (
    <ScrollView>
      {props.content.map((data, key) =>
      (
        <TouchableHighlight
          key={`link-${key}`}
          onPress={data.functionOnPress}
          activeOpacity={1}
          underlayColor="transparent"
        >
          <View
            key={key}
            style={props.bigSeparation ? [styles.container, styles.containerBigSeparation] : [styles.container]}
          >
            <View style={data.text ? styles.containerImageText : styles.containerOnlyImage}>
              {data.image &&
                <Image
                  style={styles.imageList}
                  source={data.image}
                />
              }
              {data.text &&
                <Text style={styles.text}>{data.text}</Text>
              }
            </View>
            <Image
              style={styles.nextIcon}
              source={nextImage}
            />
          </View>
        </TouchableHighlight>
      )
    )}
    </ScrollView>
  );
}

List.propTypes = {
  content: React.PropTypes.array,
  bigSeparation: React.PropTypes.bool
};

export default List;
<commit_msg>Fix link<commit_after>import React from 'react';
import {
  View,
  ScrollView,
  Image,
  TouchableHighlight,
  Text
} from 'react-native';
import styles from './styles';

const nextImage = require('assets/next.png');

function List(props) {
  return (
    <ScrollView>
      {props.content.map((data, key) =>
      (
        <TouchableHighlight
          key={`link-${key}`}
          onPress={() => data.functionOnPress()}
          activeOpacity={1}
          underlayColor="transparent"
        >
          <View
            key={key}
            style={props.bigSeparation ? [styles.container, styles.containerBigSeparation] : [styles.container]}
          >
            <View style={data.text ? styles.containerImageText : styles.containerOnlyImage}>
              {data.image &&
                <Image
                  style={styles.imageList}
                  source={data.image}
                />
              }
              {data.text &&
                <Text style={styles.text}>{data.text}</Text>
              }
            </View>
            <Image
              style={styles.nextIcon}
              source={nextImage}
            />
          </View>
        </TouchableHighlight>
      )
    )}
    </ScrollView>
  );
}

List.propTypes = {
  content: React.PropTypes.array,
  bigSeparation: React.PropTypes.bool
};

export default List;
<|endoftext|>


<commit_before>import $ from 'jquery'
import THREE from 'three'
import TWEEN from 'tween'
import {ll2cartesian, wrapDegDelta, debounce, deg2rad} from 'utils'
import {bodies} from 'resources/bodies'

export default {
	inherit: true,
	template: require('./template.jade')({styles: require('./stylesheet.sass')}),
	props: ['config'],
	data() {
		return {
			displayRadius: 50,
		}
	},
	ready() {
		var origo = new THREE.Vector3(0, 0, 0)

		// Init three.js renderer
		var renderer = new THREE.WebGLRenderer({
			alpha: true,
			antialias: true,
		})
		renderer.setSize(1, 1)
		$('.orbital-display').append(renderer.domElement)

		// Resize renderer when window is resized
		function resize() {
			var $dim = $('.orbital-display').width()
			renderer.setSize($dim, $dim)
		}
		$(window).on('resize', debounce(resize))
		resize()

		// Create scene and setup camera and lights
		var scene = new THREE.Scene()
		var camera = new THREE.PerspectiveCamera(30, 1, 0.01, 1000)

		scene.add(new THREE.AmbientLight(0x666666))

		var light = new THREE.DirectionalLight(0xffffff, 2)
		light.position.set(5000, 0, 0)
		scene.add(light)

		// Init body geometry and materials
		var bodyGeometry = new THREE.SphereGeometry(this.displayRadius, 32, 32)
		var bodyMaterial = new THREE.MeshPhongMaterial({
			shininess: 30,
		})
		var bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial)

		// Init vessel geometry
		var vesselGeometry = new THREE.SphereGeometry(2, 8, 8)
		var vesselMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 })
		var vesselMesh = new THREE.Mesh(vesselGeometry, vesselMaterial)

		// Init vessel line (to body center, indicating altitude)
		var lineGeometry = new THREE.Geometry()
		var lineMaterial = new THREE.LineBasicMaterial({ color: 0x770000 })
		var line = new THREE.Line(lineGeometry, lineMaterial)

		lineGeometry.vertices.push(new THREE.Vector3(0, 0, 0))
		lineGeometry.vertices.push(new THREE.Vector3(0, 0, 0))

		// Init orbit ellipse
		var orbitMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00 })
		var orbitPath = new THREE.CurvePath()
		orbitPath.add(new THREE.EllipseCurve(0, 0, 1, 1, 0, 2 * Math.PI, false))
		var orbitGeometry = orbitPath.createPointsGeometry(64)
		orbitGeometry.computeTangents()
		var orbitLine = new THREE.Line(orbitGeometry, orbitMaterial)

		scene.add(bodyMesh)
		scene.add(vesselMesh)
		scene.add(line)
		scene.add(orbitLine)

		// Animate callback
		var animate = () => {
			requestAnimationFrame(animate)

			TWEEN.update()

			renderer.render(scene, camera)
		}
		requestAnimationFrame(animate)

		// Tweening
		var trueAnomaly = 0
		var inclination = 0
		var argumentOfPeriapsis = 0

		var vesselTweenProperties
		var vesselTween

		this.$watch(() => this.data['v.long'] + this.data['v.lat'] + this.data['v.altitude'] + this.data['v.body'], () => {
			var body = bodies[this.data['v.body']]

			if (!bodyMaterial.map || bodyMaterial.map.sourceFile !== body.textures.diffuse) {
				// Update textures based on the current body
				// Only updates if the current texture source files differs from the current body
				bodyMaterial.map = THREE.ImageUtils.loadTexture(body.textures.diffuse)
				bodyMaterial.specularMap = THREE.ImageUtils.loadTexture(body.textures.specular)
				bodyMaterial.normalMap = THREE.ImageUtils.loadTexture(body.textures.normal)

				bodyMaterial.map.anisotropy = renderer.getMaxAnisotropy()
				bodyMaterial.normalMap.anisotropy = renderer.getMaxAnisotropy() / 2
				bodyMaterial.specularMap.anisotropy = renderer.getMaxAnisotropy() / 2

				bodyMaterial.needsUpdate = true
			}

			// Rotate body correctly in relation to Kerbol
			// I have no idea why this is offset by -45deg, but it works
			var epoch = this.data['o.epoch']
			bodyMesh.rotation.y = deg2rad(((epoch / body.rotPeriod) * 360) - 45 - 180)

			// Animate vessel and camera positions
			vesselTweenProperties = {
				trueAnomaly: trueAnomaly,
				inclination: inclination,
				argumentOfPeriapsis: argumentOfPeriapsis,
			}
			vesselTween = new TWEEN.Tween(vesselTweenProperties).to({
				// Add normalized delta values to current values
				trueAnomaly: trueAnomaly + wrapDegDelta(this.data['o.trueAnomaly'] - trueAnomaly),
				inclination: inclination + wrapDegDelta(this.data['o.inclination'] - inclination),
				argumentOfPeriapsis: argumentOfPeriapsis + wrapDegDelta(this.data['o.argumentOfPeriapsis'] - argumentOfPeriapsis),
			}, this.refreshInterval)

			trueAnomaly = this.data['o.trueAnomaly']
			inclination = this.data['o.inclination']
			argumentOfPeriapsis = this.data['o.argumentOfPeriapsis']

			// Draw orbit ellipse
			// http://stackoverflow.com/questions/19432633/how-do-i-draw-an-ellipse-with-svg-based-around-a-focal-point-instead-of-the-cen
			var ratio = (this.displayRadius / body.radius)

			var aop = this.data['o.argumentOfPeriapsis']
			var incl = 90 - this.data['o.inclination']
			var sma = this.data['o.sma']
			var ecc = this.data['o.eccentricity']

			var rx = ratio * sma
			var ry = ratio * (sma * (Math.sqrt(1 - Math.pow(ecc, 2))))
			var cx = -Math.sqrt(Math.pow(rx, 2) - Math.pow(ry, 2))
			var cy = 0

			orbitPath = new THREE.CurvePath()
			orbitPath.add(new THREE.EllipseCurve(cx, cy, rx, ry, 0, 2 * Math.PI, false))
			orbitGeometry = orbitPath.createPointsGeometry(64)
			orbitGeometry.computeTangents()

			orbitLine.geometry.vertices = orbitGeometry.vertices
			orbitLine.geometry.verticesNeedUpdate = true

			orbitLine.rotation.x = deg2rad(-incl)
			orbitLine.rotation.z = deg2rad(aop)

			vesselTween.onUpdate(() => {
				// Calculate orbital position
				var sin = Math.sin
				var cos = Math.cos

				var ta = deg2rad(vesselTweenProperties.trueAnomaly)
				var i = deg2rad(vesselTweenProperties.inclination)
				var w = deg2rad(vesselTweenProperties.argumentOfPeriapsis)
				var omega = deg2rad(0) // I have no idea why this works, and deg2rad(o.lan) does not

				var r = ratio * sma * (1 - Math.pow(ecc, 2)) / (1 + ecc * cos(ta))
				var ta_w = ta + w
				var x = r * (cos(omega) * cos(ta_w) - sin(omega) * sin(ta_w) * cos(i))
				var y = r * (sin(omega) * cos(ta_w) + cos(omega) * sin(ta_w) * cos(i))
				var z = r * (sin(ta_w) * sin(i))

				vesselMesh.position.x = x
				vesselMesh.position.y = z
				vesselMesh.position.z = -y
				lineGeometry.vertices[1].x = x
				lineGeometry.vertices[1].y = z
				lineGeometry.vertices[1].z = -y
				lineGeometry.verticesNeedUpdate = true

				camera.lookAt(origo)
			})
			vesselTween.start()
		})

	},
}
<commit_msg>Fix orbital equations<commit_after>import $ from 'jquery'
import THREE from 'three'
import TWEEN from 'tween'
import {ll2cartesian, wrapDegDelta, debounce, deg2rad} from 'utils'
import {bodies} from 'resources/bodies'

export default {
	inherit: true,
	template: require('./template.jade')({styles: require('./stylesheet.sass')}),
	props: ['config'],
	data() {
		return {
			displayRadius: 50,
		}
	},
	ready() {
		var origo = new THREE.Vector3(0, 0, 0)

		// Init three.js renderer
		var renderer = new THREE.WebGLRenderer({
			alpha: true,
			antialias: true,
		})
		renderer.setSize(1, 1)
		$('.orbital-display').append(renderer.domElement)

		// Resize renderer when window is resized
		function resize() {
			var $dim = $('.orbital-display').width()
			renderer.setSize($dim, $dim)
		}
		$(window).on('resize', debounce(resize))
		resize()

		// Create scene and setup camera and lights
		var scene = new THREE.Scene()
		var camera = new THREE.PerspectiveCamera(30, 1, 0.01, 1000)

		scene.add(new THREE.AmbientLight(0x666666))

		var light = new THREE.DirectionalLight(0xffffff, 2)
		light.position.set(5000, 0, 0)
		scene.add(light)

		// Init body geometry and materials
		var bodyGeometry = new THREE.SphereGeometry(this.displayRadius, 32, 32)
		var bodyMaterial = new THREE.MeshPhongMaterial({
			shininess: 30,
		})
		var bodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial)

		// Init vessel geometry
		var vesselGeometry = new THREE.SphereGeometry(2, 8, 8)
		var vesselMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 })
		var vesselMesh = new THREE.Mesh(vesselGeometry, vesselMaterial)

		// Init vessel line (to body center, indicating altitude)
		var lineGeometry = new THREE.Geometry()
		var lineMaterial = new THREE.LineBasicMaterial({ color: 0x770000 })
		var line = new THREE.Line(lineGeometry, lineMaterial)

		lineGeometry.vertices.push(new THREE.Vector3(0, 0, 0))
		lineGeometry.vertices.push(new THREE.Vector3(0, 0, 0))

		// Init orbit ellipse
		var orbitMaterial = new THREE.LineBasicMaterial({ color: 0x00ff00 })
		var orbitPath = new THREE.CurvePath()
		orbitPath.add(new THREE.EllipseCurve(0, 0, 1, 1, 0, 2 * Math.PI, false))
		var orbitGeometry = orbitPath.createPointsGeometry(64)
		orbitGeometry.computeTangents()
		var orbitLine = new THREE.Line(orbitGeometry, orbitMaterial)

		scene.add(bodyMesh)
		scene.add(vesselMesh)
		scene.add(line)
		scene.add(orbitLine)

		// Animate callback
		var animate = () => {
			requestAnimationFrame(animate)

			TWEEN.update()

			renderer.render(scene, camera)
		}
		requestAnimationFrame(animate)

		// Tweening
		var trueAnomaly = 0
		var inclination = 0
		var argumentOfPeriapsis = 0

		var vesselTweenProperties
		var vesselTween

		this.$watch(() => this.data['v.long'] + this.data['v.lat'] + this.data['v.altitude'] + this.data['v.body'], () => {
			var body = bodies[this.data['v.body']]

			if (!bodyMaterial.map || bodyMaterial.map.sourceFile !== body.textures.diffuse) {
				// Update textures based on the current body
				// Only updates if the current texture source files differs from the current body
				bodyMaterial.map = THREE.ImageUtils.loadTexture(body.textures.diffuse)
				bodyMaterial.specularMap = THREE.ImageUtils.loadTexture(body.textures.specular)
				bodyMaterial.normalMap = THREE.ImageUtils.loadTexture(body.textures.normal)

				bodyMaterial.map.anisotropy = renderer.getMaxAnisotropy()
				bodyMaterial.normalMap.anisotropy = renderer.getMaxAnisotropy() / 2
				bodyMaterial.specularMap.anisotropy = renderer.getMaxAnisotropy() / 2

				bodyMaterial.needsUpdate = true
			}

			// FIXME Rotate body correctly in relation to Kerbol
			var epoch = this.data['o.epoch']
			bodyMesh.rotation.y = deg2rad(((epoch / body.rotPeriod) * 360))

			// Animate vessel and camera positions
			vesselTweenProperties = {
				trueAnomaly: trueAnomaly,
				inclination: inclination,
				argumentOfPeriapsis: argumentOfPeriapsis,
			}
			vesselTween = new TWEEN.Tween(vesselTweenProperties).to({
				// Add normalized delta values to current values
				trueAnomaly: trueAnomaly + wrapDegDelta(this.data['o.trueAnomaly'] - trueAnomaly),
				inclination: inclination + wrapDegDelta(this.data['o.inclination'] - inclination),
				argumentOfPeriapsis: argumentOfPeriapsis + wrapDegDelta(this.data['o.argumentOfPeriapsis'] - argumentOfPeriapsis),
			}, this.refreshInterval)

			trueAnomaly = this.data['o.trueAnomaly']
			inclination = this.data['o.inclination']
			argumentOfPeriapsis = this.data['o.argumentOfPeriapsis']

			// Draw orbit ellipse
			// http://stackoverflow.com/questions/19432633/how-do-i-draw-an-ellipse-with-svg-based-around-a-focal-point-instead-of-the-cen
			var ratio = (this.displayRadius / body.radius)

			var aop = this.data['o.argumentOfPeriapsis']
			var incl = this.data['o.inclination']
			var sma = this.data['o.sma']
			var ecc = this.data['o.eccentricity']
			var lan = this.data['o.lan']

			var rx = ratio * sma
			var ry = ratio * (sma * (Math.sqrt(1 - Math.pow(ecc, 2))))
			var cx = Math.sqrt(Math.pow(rx, 2) - Math.pow(ry, 2))
			var cy = 0

			orbitPath = new THREE.CurvePath()
			orbitPath.add(new THREE.EllipseCurve(cx, cy, rx, ry, 0, 2 * Math.PI, false))
			orbitGeometry = orbitPath.createPointsGeometry(64)
			orbitGeometry.computeTangents()

			orbitLine.geometry.vertices = orbitGeometry.vertices
			orbitLine.geometry.verticesNeedUpdate = true

			vesselTween.onUpdate(() => {
				// Calculate orbital position
				var sin = Math.sin
				var cos = Math.cos

				var ta = deg2rad(vesselTweenProperties.trueAnomaly)
				var i = deg2rad(vesselTweenProperties.inclination)
				var w = deg2rad(vesselTweenProperties.argumentOfPeriapsis)
				var omega = deg2rad(lan)

				var r = ratio * sma * (1 - Math.pow(ecc, 2)) / (1 + ecc * cos(ta))
				var ta_w = ta + w
				var x = r * (cos(omega) * cos(ta_w) - sin(omega) * sin(ta_w) * cos(i))
				var y = r * (sin(omega) * cos(ta_w) + cos(omega) * sin(ta_w) * cos(i))
				var z = r * (sin(ta_w) * sin(i))

				vesselMesh.position.x = x
				vesselMesh.position.y = z
				vesselMesh.position.z = -y
				lineGeometry.vertices[1].x = x
				lineGeometry.vertices[1].y = z
				lineGeometry.vertices[1].z = -y
				lineGeometry.verticesNeedUpdate = true

				camera.lookAt(origo)
			})
			vesselTween.start()
		})

	},
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import classNames from 'classnames';
import styles from './../../assets/css/pages/profile.scss';
import { Row, Col } from 'react-bootstrap';
import { Link } from 'react-router';

class ProjectFeed extends React.Component {
    constructor(props) {
        super(props);
        this.props = props;
        this.active = 'About';
    }

    componentDidMount() {
        this.props.onFeedLoad();
    }

    componentWillReceiveProps(props) {
        this.props = props;
    }

    displaySkills(skills) {
        return skills.map((value, key) => {
            return
{value}
;
        });
    }

    match(projectId, e) {
        e.preventDefault();
        const js = {
            id: projectId
        };
        this.props.makeMatch(js);
    }

    render() {
        let projects;
        // const typeWidth = {
        //     'website': '40px',
        //     'issues': '10px',
        //     'setup': '40px',
        //     'mobile': '25px',
        //     'backend': '40px'
        // };

        if(this.props.projects.length > 0) {
            projects = this.props.projects.map((value, key) => {
                const nonprofiturl = '/' + value.nonprofitId.url;
                // <img width={typeWidth[value.item.toLowerCase()]} src={require(`./../../assets/images/icons/black/${value.item.toLowerCase()}black.png`)} />
                return (
                    <Row className={styles.newProjectRow} key={key}>
                        <Col xs={12} sm={12} md={12} lg={12}>
                            <Row>
                                <Col xs={12} sm={12} md={2} lg={2}>

                                </Col>
                                <Col xs={12} sm={12} md={10} lg={10}>
                                    <Row>
                                        <Col xs={12} sm={12} md={12} lg={12}>

{value.title}

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12}>

Posted By: <Link to={nonprofiturl}>{value.nonprofitId.organizationname}</Link>

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12} className={styles.skillsWrapper}>

{this.displaySkills(value.skills)}

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12}>

{value.description}

                                        </Col>
                                        <Col xs={12} sm={4} md={4} lg={4}>
                                            {(value.matched === false && value.confirmed === false) && Match Me }
                                            {(value.matched === true && value.potential._id !== this.props.userid) && Another match in progress. Sorry!}
                                            {(value.matched === true && value.potential._id === this.props.userid) && Request Pending...}
                                            {(value.confirmed === true && value.potential && value.potential._id !== this.props.userid) && Project has been taken!}
                                            {(value.confirmed === true && value.potential && value.potential._id === this.props.userid) && Accepted }
                                        </Col>
                                        <Col xs={12} sm={4} md={4} lg={4} />
                                    </Row>
                                </Col>
                            </Row>
                        </Col>
                    </Row>
                );
            });
        }
        return (

                {projects}

        );
    }
}

ProjectFeed.propTypes = {
    error: PropTypes.string,
    onFeedLoad: PropTypes.func,
    user: PropTypes.object,
    projects: PropTypes.array,
    feed: PropTypes.object,
    matches: PropTypes.object,
    makeMatch: PropTypes.func,
    userid: PropTypes.string,
};

export default ProjectFeed;
<commit_msg>Added back projectp ics<commit_after>import React, { PropTypes } from 'react';
import classNames from 'classnames';
import styles from './../../assets/css/pages/profile.scss';
import { Row, Col } from 'react-bootstrap';
import { Link } from 'react-router';

class ProjectFeed extends React.Component {
    constructor(props) {
        super(props);
        this.props = props;
        this.active = 'About';
    }

    componentDidMount() {
        this.props.onFeedLoad();
    }

    componentWillReceiveProps(props) {
        this.props = props;
    }

    displaySkills(skills) {
        return skills.map((value, key) => {
            return
{value}
;
        });
    }

    match(projectId, e) {
        e.preventDefault();
        const js = {
            id: projectId
        };
        this.props.makeMatch(js);
    }

    render() {
        let projects;
        const typeWidth = {
            'website': '40px',
            'issues': '10px',
            'setup': '40px',
            'mobile': '25px',
            'backend': '40px'
        };

        if(this.props.projects.length > 0) {
            projects = this.props.projects.map((value, key) => {
                const nonprofiturl = '/' + value.nonprofitId.url;
                let image = <img width={typeWidth[value.item.toLowerCase()]} src={require(`./../../assets/images/icons/black/${value.item.toLowerCase()}black.png`)} />;
                return (
                    <Row className={styles.newProjectRow} key={key}>
                        <Col xs={12} sm={12} md={12} lg={12}>
                            <Row>
                                <Col xs={12} sm={12} md={2} lg={2}>

                                        {image}

                                </Col>
                                <Col xs={12} sm={12} md={10} lg={10}>
                                    <Row>
                                        <Col xs={12} sm={12} md={12} lg={12}>

{value.title}

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12}>

Posted By: <Link to={nonprofiturl}>{value.nonprofitId.organizationname}</Link>

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12} className={styles.skillsWrapper}>

{this.displaySkills(value.skills)}

                                        </Col>
                                        <Col xs={12} sm={12} md={12} lg={12}>

{value.description}

                                        </Col>
                                        <Col xs={12} sm={4} md={4} lg={4}>
                                            {(value.matched === false && value.confirmed === false) && Match Me }
                                            {(value.matched === true && value.potential._id !== this.props.userid) && Another match in progress. Sorry!}
                                            {(value.matched === true && value.potential._id === this.props.userid) && Request Pending...}
                                            {(value.confirmed === true && value.potential && value.potential._id !== this.props.userid) && Project has been taken!}
                                            {(value.confirmed === true && value.potential && value.potential._id === this.props.userid) && Accepted }
                                        </Col>
                                        <Col xs={12} sm={4} md={4} lg={4} />
                                    </Row>
                                </Col>
                            </Row>
                        </Col>
                    </Row>
                );
            });
        }
        return (

                {projects}

        );
    }
}

ProjectFeed.propTypes = {
    error: PropTypes.string,
    onFeedLoad: PropTypes.func,
    user: PropTypes.object,
    projects: PropTypes.array,
    feed: PropTypes.object,
    matches: PropTypes.object,
    makeMatch: PropTypes.func,
    userid: PropTypes.string,
};

export default ProjectFeed;
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
  View,
  Image,
  TouchableOpacity,
  Text
} from 'react-native';

import Theme from 'config/theme';
import StepsSlider from 'components/common/steps-slider';

import styles from './styles';

const backIcon = require('assets/previous.png');
const nextIcon = require('assets/next.png');
const phone1 = require('assets/walkthrough-phone1.png');
const phone2 = require('assets/walkthrough-phone2.png');
const phone3 = require('assets/walkthrough-phone3.png');
const phone4 = require('assets/walkthrough-phone4.png');
const phone5 = require('assets/walkthrough-phone5.png');

const SLIDES = [
  {
    title: 'Welcome to Forest Watcher',
    subtitle: 'Create areas of interest to monitor alerts of forest change',
    image: phone1,
    color: Theme.colors.color1
  },
  {
    subtitle: 'Enter the settings to configure the data you want to see',
    image: phone2,
    color: Theme.colors.color2
  },
  {
    subtitle: 'Navigate to the alerts and create reports to collect data about that change',
    image: phone3,
    color: Theme.colors.color3
  },
  {
    subtitle: 'You can select multiple alerts to report them in bulk.',
    image: phone4,
    color: Theme.colors.color5
  },
  {
    subtitle: 'If you discover a new area of forest change, tap directly on the map to report it',
    image: phone5,
    color: Theme.colors.color6
  }
];

class Walkthrough extends PureComponent {
  static navigatorStyle = {
    navBarHidden: true
  };

  static propTypes = {
    navigator: PropTypes.object.isRequired
  };

  state = {
    page: 0
  };

  onPressBack = () => {
    this.setState(state => ({ page: state.page - 1 }));
  };

  onPressNext = () => {
    const { page } = this.state;
    const { navigator } = this.props;

    if (page + 1 < SLIDES.length) {
      this.setState({ page: page + 1 });
    } else {
      navigator.resetTo({
        screen: 'ForestWatcher.Login',
        title: 'Set up',
        passProps: {
          goBackDisabled: true
        }
      });
    }
  };

  render() {
    const { page } = this.state;
    return (
      <View style={styles.container}>
        <StepsSlider page={page} barStyle={{ height: 64 }}>
          {SLIDES.map((slide, index) =>
            (
              <View style={styles.slideContainer} key={`slide-${index}`}>
                <View style={styles.textsContainer}>
                  {slide.title &&
                    <Text style={styles.title}>{slide.title}</Text>
                  }
                  {slide.subtitle &&
                    <Text style={styles.subtitle}>{slide.subtitle}</Text>
                  }
                </View>
                <View style={styles.phoneContainer}>
                  {slide.image ?
                    <Image style={styles.phoneImage} source={slide.image} />
                  : <View style={[styles.phoneImage, { backgroundColor: slide.color }]} />
                  }
                </View>
                <View style={styles.footerHack} />
              </View>
            ))
          }
        </StepsSlider>
        <View style={[styles.footer, page > 0 ? { justifyContent: 'space-between' } : { justifyContent: 'flex-end' }]}>
          {page > 0 && // Buttons are placed here because inside the StepsSlider the events wont trigger
          <TouchableOpacity
            onPress={this.onPressBack}
          >
            <Image style={Theme.icon} source={backIcon} />
          </TouchableOpacity>
          }
          <TouchableOpacity
            onPress={this.onPressNext}
          >
            <Image style={Theme.icon} source={nextIcon} />
          </TouchableOpacity>
        </View>
      </View>
    );
  }
}

export default Walkthrough;
<commit_msg>fix: adds event handler to support sliding on walkthrough<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import {
  View,
  Image,
  TouchableOpacity,
  Text
} from 'react-native';

import Theme from 'config/theme';
import StepsSlider from 'components/common/steps-slider';

import styles from './styles';

const backIcon = require('assets/previous.png');
const nextIcon = require('assets/next.png');
const phone1 = require('assets/walkthrough-phone1.png');
const phone2 = require('assets/walkthrough-phone2.png');
const phone3 = require('assets/walkthrough-phone3.png');
const phone4 = require('assets/walkthrough-phone4.png');
const phone5 = require('assets/walkthrough-phone5.png');

const SLIDES = [
  {
    title: 'Welcome to Forest Watcher',
    subtitle: 'Create areas of interest to monitor alerts of forest change',
    image: phone1,
    color: Theme.colors.color1
  },
  {
    subtitle: 'Enter the settings to configure the data you want to see',
    image: phone2,
    color: Theme.colors.color2
  },
  {
    subtitle: 'Navigate to the alerts and create reports to collect data about that change',
    image: phone3,
    color: Theme.colors.color3
  },
  {
    subtitle: 'You can select multiple alerts to report them in bulk.',
    image: phone4,
    color: Theme.colors.color5
  },
  {
    subtitle: 'If you discover a new area of forest change, tap directly on the map to report it',
    image: phone5,
    color: Theme.colors.color6
  }
];

class Walkthrough extends PureComponent {
  static navigatorStyle = {
    navBarHidden: true
  };

  static propTypes = {
    navigator: PropTypes.object.isRequired
  };

  state = {
    page: 0
  };

  onPressBack = () => {
    this.setSliderPage(this.state.page - 1);
  };

  onPressNext = () => {
    const { page } = this.state;
    const { navigator } = this.props;

    if (page + 1 < SLIDES.length) {
      this.setState({ page: page + 1 });
    } else {
      navigator.resetTo({
        screen: 'ForestWatcher.Login',
        title: 'Set up',
        passProps: {
          goBackDisabled: true
        }
      });
    }
  };

  setSliderPage = (page) => {
    this.setState({ page });
  };

  render() {
    const { page } = this.state;
    return (
      <View style={styles.container}>
        <StepsSlider
          page={page}
          barStyle={{ height: 64 }}
          locked={false}
          prerenderingSiblingsNumber={1}
          onChangeTab={({ i }) => this.setSliderPage(i)}
        >
          {SLIDES.map((slide, index) =>
            (
              <View style={styles.slideContainer} key={`slide-${index}`}>
                <View style={styles.textsContainer}>
                  {slide.title &&
                    <Text style={styles.title}>{slide.title}</Text>
                  }
                  {slide.subtitle &&
                    <Text style={styles.subtitle}>{slide.subtitle}</Text>
                  }
                </View>
                <View style={styles.phoneContainer}>
                  {slide.image ?
                    <Image style={styles.phoneImage} source={slide.image} />
                  : <View style={[styles.phoneImage, { backgroundColor: slide.color }]} />
                  }
                </View>
                <View style={styles.footerHack} />
              </View>
            ))
          }
        </StepsSlider>
        <View style={[styles.footer, page > 0 ? { justifyContent: 'space-between' } : { justifyContent: 'flex-end' }]}>
          {page > 0 && // Buttons are placed here because inside the StepsSlider the events wont trigger
          <TouchableOpacity
            onPress={this.onPressBack}
          >
            <Image style={Theme.icon} source={backIcon} />
          </TouchableOpacity>
          }
          <TouchableOpacity
            onPress={this.onPressNext}
          >
            <Image style={Theme.icon} source={nextIcon} />
          </TouchableOpacity>
        </View>
      </View>
    );
  }
}

export default Walkthrough;
<|endoftext|>


<commit_before>import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import Add from './Add.react';
import Message from '../components/Message.react';
import { fetchPostEdge } from '../actions/edge';
import { fetchHeart } from '../actions/heart';
import analytics from '../analytics';

import config from '../config';
const { rootURL } = config;

const mapStateToProps = (state) => {
  const {
    user: {
      isLoggedIn,
    },
    user: {
      profile,
    },
    edge,
    connectEntity,
    currentPage: {
      id,
      entityCount,
      isFetching,
      title,
      superEdges,
      queryLink,
      canonicalLink,
      heartCount,
      heartValue,
    },
  } = state;
  const connectEntityId = connectEntity.id;
  const isFetchingEdge = edge.isFetching;
  const messagesEdge = edge.messages;
  const messagesConnect = connectEntity.messages;

  return {
    isFetching,
    isLoggedIn,
    edge,
    id,
    connectEntityId,
    entityCount,
    title,
    isFetchingEdge,
    superEdges,
    queryLink,
    canonicalLink,
    messagesConnect,
    heartCount,
    heartValue,
  };
};

class Connections extends Component {

  static propTypes = {
    dispatch: PropTypes.func.isRequired,
    fullPageToggle: PropTypes.func.isRequired,
    superEdges: PropTypes.array.isRequired,
    entityCount: PropTypes.number.isRequired,
    id: PropTypes.string,
    isFetching: PropTypes.bool.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    isFetchingEdge: PropTypes.bool.isRequired,
    heartValue: PropTypes.bool.isRequired,
    messagesConnect: PropTypes.array.isRequired,
    heartCount: PropTypes.number.isRequired,
    connectEntityId: PropTypes.string,
    expanded: PropTypes.bool.isRequired,
  }

  state = {
    connectionDisplayIndex: 0,
    isAddConnectionToggledOn: false,
    isLoginRedirectToggledOn: false,
    heartClickAttempted: false,
    rotateConnectionBox: false,
  }

  componentDidMount() {
    window.onkeyup = (e) => {
      if (e.keyCode === 27) {
        this.setState({
          isAddConnectionToggledOn: false,
        });
      }
    };
  }

  incrementConnectionsIndex = () => {
    analytics('incrementConnectionsIndexAttempted');
    if (this.state.connectionDisplayIndex < this.props.entityCount - 1) {
      this.setState({
        connectionDisplayIndex: this.state.connectionDisplayIndex + 1,
      });
      analytics('incrementConnectionsIndex');
    }
  }

  decrementConnectionsIndex = () => {
      analytics('decrementConnectionsIndexAttempted');
    if (this.state.connectionDisplayIndex > 0) {
      this.setState({
        connectionDisplayIndex: this.state.connectionDisplayIndex - 1,
      });
      analytics('decrementConnectionsIndex');
    }
  }

  render() {
    const {
      isFetching,
      isLoggedIn,
      superEdges,
      entityCount,
      isFetchingEdge,
      messagesConnect,
      heartValue,
      heartCount,
      expanded,
    } = this.props;

    const {
      connectionDisplayIndex,
      isAddConnectionToggledOn,
      heartClickAttempted,
      rotateConnectionBox,
      isLoginRedirectToggledOn,
    } = this.state;

    /* increment/decrement styling */
    let incrementButtonStyle;
    let decrementButtonStyle;
    if (entityCount > 0) {
      incrementButtonStyle = { color: 'rgba(0,0,0,.6)' };
      decrementButtonStyle = { color: 'rgba(0,0,0,.6)' };
      if (connectionDisplayIndex === entityCount - 1) {
        decrementButtonStyle = { color: 'rgba(0,0,0,.33)' };
      } else if (connectionDisplayIndex === 0) {
        incrementButtonStyle = { color: 'rgba(0,0,0,.33)' };
      }
    } else {
      incrementButtonStyle = { display: 'none' };
      decrementButtonStyle = { display: 'none' };
    }

    const showLoginInfo = (isAddConnectionToggledOn && !isLoggedIn) || (heartClickAttempted && !isLoggedIn) ? 'flex' : 'none';
    const loginButton = (

         {
            this.onLoginRedirect()
            analytics('loginClicked');
          }}
          href={`${rootURL}/login`}
        >
          Log in

)

    const loginText = heartClickAttempted ?
      (

        You must be logged in to recommend a web page

) :
      (

        You must be logged in to make a connection

)

    const calculatedTopOffset = connectionDisplayIndex * -45;

    const showRecommenderInfo = !isAddConnectionToggledOn ? 'flex' : 'none';
    const recommenderInfo =  entityCount > 0 ?
      (

          {superEdges.map((edge, i) =>

                  Contributor

                   { analytics('reccommenderClicked'); }}
                    href={`${rootURL}/@${edge.edges[0].user.username}`}
                  >
                    @{edge.edges[0].user.username}

          )}

) : null

    const inputBox = isLoggedIn && isAddConnectionToggledOn ? (

        <Add onSave={this.onSave} />

) : null;

    const showRecommendationBox = heartClickAttempted || isAddConnectionToggledOn ? 'none' : 'flex';
    const changeRecommendationBox = superEdges.length > 1 ?
      (

      ) :
      null;
    const recommendationBox =
      entityCount > 0 &&
      !isFetching &&
      !isFetchingEdge ?
      (

        {superEdges.map((edge, i) =>

                   { analytics('outboundLinkToTheArticle'); }}
                    target="_blank"
                    rel="noreferrer noopener"
                  >
                    Read next

                   { analytics('outboundLinkToTheArticle'); }}
                    href={edge.entity.canonicalLink}>
                    {edge.entity.domain}
                     -
                    {edge.entity.title}

        )}

        {changeRecommendationBox}

) : null;

    const noRecommendationBox =
      entityCount === 0 &&
      !heartClickAttempted &&
      !isFetching &&
      !isFetchingEdge ?
      (

              There are no recommendations for this page

      ) : null;
    const inputSuccessErrorMessages = isAddConnectionToggledOn ?
      (

        {isFetchingEdge ? 'isFetchingEdge' : ''}
        <Message messages={messagesConnect} />

) : null;

    const heartIconType = heartValue ? 'fa-heart' : 'fa-heart-o';
    const showHeartCount = heartCount > 0 ? 'flex' : 'none';
    const connectionBoxRotationClass = rotateConnectionBox ? 'rotateIn' : 'rotateOut';

    const verticalDivider =

    console.log(this.props, 'props')

    const expandIconClass = superEdges && superEdges.length > 1 ?
      'fa fa-forward expandButtonMultipleUserConnections' :
      'fa fa-forward expandButtonNoUserConnections';
    const expandBox = (

)

    return (

        {expandBox}

      {isLoginRedirectToggledOn?

            Please refresh the page after you log in.

        :null}

                {heartCount}

            {verticalDivider}

            {recommendationBox}
            {noRecommendationBox}
            {loginText}
            {inputBox}

            {verticalDivider}
            {recommenderInfo}
            {inputSuccessErrorMessages}
            {loginButton}

    );
  }

  onSave = (e) => {
    const { dispatch, id, connectEntityId } = this.props;

    //const { description, tags } = this.state;
    dispatch(fetchPostEdge(
      id,
      connectEntityId,
      '',
      []
    ));
    this.setState({
      isAddConnectionToggledOn: !this.state.isAddConnectionToggledOn,
      rotateConnectionBox: false,
    });
    analytics('connectionMade');
    e.preventDefault();
  }

  onCloseFooter = () => {
    analytics('toolbarClosed');
    chrome.storage.local.set({ wikiwebFooterActive: false });
  }

  onExpandFooter = () => {
    analytics('toolbarExpanded');
    this.props.fullPageToggle();
  }

  onLoginRedirect = () => {
    const { isLoginRedirectToggledOn } = this.state;
    const { fullPageToggle } = this.props;
    fullPageToggle();
    this.setState({
      isLoginRedirectToggledOn: !isLoginRedirectToggledOn,
    });
  }

  onHeart = (e) => {
    if (this.props.isLoggedIn) {
      const { dispatch, id, heartValue } = this.props;
      analytics(heartValue ? 'pageHeartCreated' : 'pageHeartUndone');
      dispatch(fetchHeart(
        id,
        !heartValue,
      ));
    } else {
      this.setState({
        heartClickAttempted: !this.state.heartClickAttempted,
      });
    }

    e.preventDefault();
  }
}

export default connect(mapStateToProps)(Connections);

function enterConnectionBox(e) {
  this.setState({
    rotateConnectionBox: true,
  });
  e.preventDefault();
}

function leaveConnectionBox(e) {
  if (!this.state.isAddConnectionToggledOn) {
    this.setState({
      rotateConnectionBox: false,
    });
  }
  e.preventDefault();
}

function toggleMiddleSection(e) {
  const { isAddConnectionToggledOn } = this.state;
  if (isAddConnectionToggledOn) { analytics('addConnectionToggled'); }

  this.setState({
    heartClickAttempted: false,
    isAddConnectionToggledOn: !isAddConnectionToggledOn
  });
  e.preventDefault();
}
<commit_msg>minor copy<commit_after>import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import Add from './Add.react';
import Message from '../components/Message.react';
import { fetchPostEdge } from '../actions/edge';
import { fetchHeart } from '../actions/heart';
import analytics from '../analytics';

import config from '../config';
const { rootURL } = config;

const mapStateToProps = (state) => {
  const {
    user: {
      isLoggedIn,
    },
    user: {
      profile,
    },
    edge,
    connectEntity,
    currentPage: {
      id,
      entityCount,
      isFetching,
      title,
      superEdges,
      queryLink,
      canonicalLink,
      heartCount,
      heartValue,
    },
  } = state;
  const connectEntityId = connectEntity.id;
  const isFetchingEdge = edge.isFetching;
  const messagesEdge = edge.messages;
  const messagesConnect = connectEntity.messages;

  return {
    isFetching,
    isLoggedIn,
    edge,
    id,
    connectEntityId,
    entityCount,
    title,
    isFetchingEdge,
    superEdges,
    queryLink,
    canonicalLink,
    messagesConnect,
    heartCount,
    heartValue,
  };
};

class Connections extends Component {

  static propTypes = {
    dispatch: PropTypes.func.isRequired,
    fullPageToggle: PropTypes.func.isRequired,
    superEdges: PropTypes.array.isRequired,
    entityCount: PropTypes.number.isRequired,
    id: PropTypes.string,
    isFetching: PropTypes.bool.isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
    isFetchingEdge: PropTypes.bool.isRequired,
    heartValue: PropTypes.bool.isRequired,
    messagesConnect: PropTypes.array.isRequired,
    heartCount: PropTypes.number.isRequired,
    connectEntityId: PropTypes.string,
    expanded: PropTypes.bool.isRequired,
  }

  state = {
    connectionDisplayIndex: 0,
    isAddConnectionToggledOn: false,
    isLoginRedirectToggledOn: false,
    heartClickAttempted: false,
    rotateConnectionBox: false,
  }

  componentDidMount() {
    window.onkeyup = (e) => {
      if (e.keyCode === 27) {
        this.setState({
          isAddConnectionToggledOn: false,
        });
      }
    };
  }

  incrementConnectionsIndex = () => {
    analytics('incrementConnectionsIndexAttempted');
    if (this.state.connectionDisplayIndex < this.props.entityCount - 1) {
      this.setState({
        connectionDisplayIndex: this.state.connectionDisplayIndex + 1,
      });
      analytics('incrementConnectionsIndex');
    }
  }

  decrementConnectionsIndex = () => {
      analytics('decrementConnectionsIndexAttempted');
    if (this.state.connectionDisplayIndex > 0) {
      this.setState({
        connectionDisplayIndex: this.state.connectionDisplayIndex - 1,
      });
      analytics('decrementConnectionsIndex');
    }
  }

  render() {
    const {
      isFetching,
      isLoggedIn,
      superEdges,
      entityCount,
      isFetchingEdge,
      messagesConnect,
      heartValue,
      heartCount,
      expanded,
    } = this.props;

    const {
      connectionDisplayIndex,
      isAddConnectionToggledOn,
      heartClickAttempted,
      rotateConnectionBox,
      isLoginRedirectToggledOn,
    } = this.state;

    /* increment/decrement styling */
    let incrementButtonStyle;
    let decrementButtonStyle;
    if (entityCount > 0) {
      incrementButtonStyle = { color: 'rgba(0,0,0,.6)' };
      decrementButtonStyle = { color: 'rgba(0,0,0,.6)' };
      if (connectionDisplayIndex === entityCount - 1) {
        decrementButtonStyle = { color: 'rgba(0,0,0,.33)' };
      } else if (connectionDisplayIndex === 0) {
        incrementButtonStyle = { color: 'rgba(0,0,0,.33)' };
      }
    } else {
      incrementButtonStyle = { display: 'none' };
      decrementButtonStyle = { display: 'none' };
    }

    const showLoginInfo = (isAddConnectionToggledOn && !isLoggedIn) || (heartClickAttempted && !isLoggedIn) ? 'flex' : 'none';
    const loginButton = (

         {
            this.onLoginRedirect()
            analytics('loginClicked');
          }}
          href={`${rootURL}/login`}
        >
          Log in

)

    const loginText = heartClickAttempted ?
      (

        You must be logged in to recommend a web page

) :
      (

        You must be logged in to make a connection

)

    const calculatedTopOffset = connectionDisplayIndex * -45;

    const showRecommenderInfo = !isAddConnectionToggledOn ? 'flex' : 'none';
    const recommenderInfo =  entityCount > 0 ?
      (

          {superEdges.map((edge, i) =>

                  Contributor

                   { analytics('reccommenderClicked'); }}
                    href={`${rootURL}/@${edge.edges[0].user.username}`}
                  >
                    @{edge.edges[0].user.username}

          )}

) : null

    const inputBox = isLoggedIn && isAddConnectionToggledOn ? (

        <Add onSave={this.onSave} />

) : null;

    const showRecommendationBox = heartClickAttempted || isAddConnectionToggledOn ? 'none' : 'flex';
    const changeRecommendationBox = superEdges.length > 1 ?
      (

      ) :
      null;
    const recommendationBox =
      entityCount > 0 &&
      !isFetching &&
      !isFetchingEdge ?
      (

        {superEdges.map((edge, i) =>

                   { analytics('outboundLinkToTheArticle'); }}
                    target="_blank"
                    rel="noreferrer noopener"
                  >
                    Read next

                   { analytics('outboundLinkToTheArticle'); }}
                    href={edge.entity.canonicalLink}>
                    {edge.entity.domain}
                     -
                    {edge.entity.title}

        )}

        {changeRecommendationBox}

) : null;

    const noRecommendationBox =
      entityCount === 0 &&
      !heartClickAttempted &&
      !isFetching &&
      !isFetchingEdge ?
      (

              There are no user recommendations for this page

      ) : null;
    const inputSuccessErrorMessages = isAddConnectionToggledOn ?
      (

        {isFetchingEdge ? 'isFetchingEdge' : ''}
        <Message messages={messagesConnect} />

) : null;

    const heartIconType = heartValue ? 'fa-heart' : 'fa-heart-o';
    const showHeartCount = heartCount > 0 ? 'flex' : 'none';
    const connectionBoxRotationClass = rotateConnectionBox ? 'rotateIn' : 'rotateOut';

    const verticalDivider =

    console.log(this.props, 'props')

    const expandIconClass = superEdges && superEdges.length > 1 ?
      'fa fa-forward expandButtonMultipleUserConnections' :
      'fa fa-forward expandButtonNoUserConnections';
    const expandBox = (

)

    return (

        {expandBox}

      {isLoginRedirectToggledOn?

            Please refresh the page after you log in.

        :null}

                {heartCount}

            {verticalDivider}

            {recommendationBox}
            {noRecommendationBox}
            {loginText}
            {inputBox}

            {verticalDivider}
            {recommenderInfo}
            {inputSuccessErrorMessages}
            {loginButton}

    );
  }

  onSave = (e) => {
    const { dispatch, id, connectEntityId } = this.props;

    //const { description, tags } = this.state;
    dispatch(fetchPostEdge(
      id,
      connectEntityId,
      '',
      []
    ));
    this.setState({
      isAddConnectionToggledOn: !this.state.isAddConnectionToggledOn,
      rotateConnectionBox: false,
    });
    analytics('connectionMade');
    e.preventDefault();
  }

  onCloseFooter = () => {
    analytics('toolbarClosed');
    chrome.storage.local.set({ wikiwebFooterActive: false });
  }

  onExpandFooter = () => {
    analytics('toolbarExpanded');
    this.props.fullPageToggle();
  }

  onLoginRedirect = () => {
    const { isLoginRedirectToggledOn } = this.state;
    const { fullPageToggle } = this.props;
    fullPageToggle();
    this.setState({
      isLoginRedirectToggledOn: !isLoginRedirectToggledOn,
    });
  }

  onHeart = (e) => {
    if (this.props.isLoggedIn) {
      const { dispatch, id, heartValue } = this.props;
      analytics(heartValue ? 'pageHeartCreated' : 'pageHeartUndone');
      dispatch(fetchHeart(
        id,
        !heartValue,
      ));
    } else {
      this.setState({
        heartClickAttempted: !this.state.heartClickAttempted,
      });
    }

    e.preventDefault();
  }
}

export default connect(mapStateToProps)(Connections);

function enterConnectionBox(e) {
  this.setState({
    rotateConnectionBox: true,
  });
  e.preventDefault();
}

function leaveConnectionBox(e) {
  if (!this.state.isAddConnectionToggledOn) {
    this.setState({
      rotateConnectionBox: false,
    });
  }
  e.preventDefault();
}

function toggleMiddleSection(e) {
  const { isAddConnectionToggledOn } = this.state;
  if (isAddConnectionToggledOn) { analytics('addConnectionToggled'); }

  this.setState({
    heartClickAttempted: false,
    isAddConnectionToggledOn: !isAddConnectionToggledOn
  });
  e.preventDefault();
}
<|endoftext|>